Hitchhiker's Guide to Software Architecture and Everything Else - by Michael Stal

Friday, December 29, 2006

Architect's Toolset - CRC Cards


Whenever I am involved in a software architecture design, CRC cards are one of my favourite tools for team discussions. CRC is not the abbreviation of Cyclic Redundancy Check in this context as you might assume. It rather stands for "Class, Responsibility, Collaboration".
I was always wondering why I still can find developers not familiar with this tool.
So, instead of telling you all the theory, let us start with an example. In the simplistic example above, I like to design a Web Shop. After the engineers defined the most important use cases and scenarios they are now in the middle of determining all core entities. For example, they are playing around with the "customer buys items from catalog" use case. Of course, using a UML tool could be a solution but did you ever see more than two people sitting in front of a screen working efficiently on a problem? This simply does not work. Here, CRC cards come into play. A CRC card is a simple sheet of paper containing three separate sections (see figure above):
  • The class name is the name of the component being described. In the example, we are introducing a Shopping Cart.
  • The responsibility section contains all responsibilitiesfor which this component is in charge such as adding or removing items in our example.
  • In the collaboration section we define on which other components our component depends, the so-called collaborators. In the example, the shopping cart must be able to co-operate with the product catalog.

All of this is simply drawn on a sheet of paper and then visibly put on a white board, poster, whatever is available. After a while the board will be filled up with CRC cards. In order to make the collaborations visible I often use a string for connecting the CRC card to its collaborator(s) using pins.

Because this is a flexible, paper-based solution it is easy to change CRC cards, remove them again, add new ones, add or remove responsibilities or collaborators. Everyone in the team is able to participate in the whole brain storming process.

Obviously, in an agile setting the CRC cards will be incomplete in the beginning and then keep growing over time.

Later on in the design process we might add additional information to the cards such as superclasses.

There is a lot more to say about CRC cards. Ward Cunningham , the "father" of CRC cards, and Kent Beck provided an excellent paper for OOPSLA 1989 that you should definitely read (http://c2.com/doc/oopsla89/paper.html).

Wednesday, December 27, 2006

Product Lines

Software Product Line Engineering is one of the most interesting areas in software architecture today. And it is increasingly important in software development, in particular for the development of standard software products and embedded systems - those that we ususally consider to be software-intensive. Now, you might ask, what the hell is a software product line. One of the commonly accepted comes from the Software Engineering Institute (CMU) which defines a software product line (SPL) as “a set of software-intensive systems that share a common, managed set of features satisfying the specific needs of a particular market segment or mission and that are developed from a common set of core assets in a prescribed way”. Got it? Let me introduce an example. Suppose, you are going to develop new IDEs (Integrated Development Environment). These new IDEs should come in different flavors, one edition for Ruby, one for Fortress, one for C#. How could we manage to develop such a series of editions? First approach: We develop all editions separately. This turns out to be a nightmare as we will need to set up a project for each language edition. But even worse, after a time, we will recognize that all of these projects will develop very similar modules, a GUI, a debugger, a source code browser, a project and configuration management subsystem, a refactoring toolset, an internationalization component, a plug-in manager, and so forth. Many of these core components are programming language independent. So why should we constantly violate the DRY (Don't Repeat Yourself) principle?
Ok, what is the second approach? In our second attempt, we start developing the Ruby IDE taking special consideration to implement all subsystems such as the GUI, the debugger, you name it, in a re-usable way. After the Ruby IDE is completed, we can re-use existing components for further IDEs. Basically, we got a set of independent lego units which we are just might compose in different ways. Obviously, this is a much better approach in terms of productivity through re-use, but it turns out to add other challenges. For example, we have to come up with different application architectures that use the existing components in a bottom-up way. All of these architecture require a lot of effort themselves. In addition, it turns out that some of the components developed for the Ruby IDE are not appropriate for the Fortress IDE. Thus, we need to refactor them to be more generally applicable. But after that work we need also to refactor the Ruby IDE to integrate these refactored components. Of course, we might choose to end up with different versions of components. This is exactly one of the reasons why some projects experience death by unsystematic re-use.
Ok, what is the third approach? In the third approach we set up a development team that first analyzes which concrete IDEs we are going to develop. The team will take all requirements and define an general architectural framework for all of these IDEs. It will come up with commonalities which are all assets that should be part of the general framework. E.g., components such as the project and configuration management subsystem that are basically identical no matter which programming language you need to support. The team will also define the variabilities , i.e., things that vary among different IDE editions. For example, the abstract syntax editor framework might be a commonality, but the different concrete syntax editor implementations will vary. As we expect users to be interested in adding their own components to the IDE (for example tools that support programming conventions), we integrate a plug-in manager. This is an example for a component that supports variation over time. So the general team will set up an architectural framework with explicit variation points as well as other commonly used assets. As we expect these assets and even the architecture framework to evolve, we need to set up an environment where common assets and their evolvement can be supported. By the way, assets in this context can be different kinds of things: implementation artifacts, documents, models, test plans, and so forth. The setup of such a project will be very expensive but the Return On Investment will rock. As soon as everything is in place, the Ruby IDE team will be able to systematically instantiate the architectural framework with all commonalities, and also bind the variabilities according to their own needs. They will save a lot of time because they don't have to come up with their own, new software architecture from scratch and they can even use existing assets. What we have defined here, is Software Product Line Engineering. All products instantiated from the product line are often called Software Program Families. I hope, you got the basic idea. It is like in other industries such as car manufacturing where the car design team comes up with a new series of cars, defines what parts all of the models could share, and also defines the variabilities. Obviously, a development team must carefully identify whether is worthwhile to set up product line engineering. It is probably a bad idea when you only have two different products.
So far, the teams that develop concrete products use the architectural framework and the common assets but the rest will be plain-vanilla software engineering. In most cases, there is a lot of space for automating many activities. Take a production line in a car manufacturing plant as an example. In Software Factories the idea is to define a systematic plan of how a product is configured or implemented using the common architectural framework and common assets. The Software Factory will then allow automating the process of developing a concrete product by leveraging model-driven software development. In order to make this experience less challenging, the idea is to come up with a domain-specific language (instead of forcing everyone to use UML) and provide a generator that includes all knowledge about the architectural frameworks, as well as about commonalities and variabilities. The generator will take a model as an input and generate (most parts of) the concrete product.
An issue we must consider in this context is how to deal with evolution and change of core assets It is unlikely the architectural framework or other assets will remain unchanged forever. Thus, a systematic approach is required to give feedback from product instantiations to the product line itself. This also implies, you should always have separate teams for the product line itself and for the products. Otherwise, organizational issues might me very challenging. In other words: even, if you provide a product line engineering approach, you might be doomed to fail due to organizational problems. Needless to say, that the development process is also significantly different which you should take into consideration.
An interesting issue is the differentiation between a platform and a product line. In many cases, the most important core asset of a product line will be a complete platform. Eclipse is a good example for this. In this case, the platform will be the critical part of your whole product line. If it suffers from design erosion (see my last blog posting), this will have an impact on ALL products. That's why systematic evolution of common assets is so essential. Note, that a software product line does not necessarily have to introduce a platform. This is only one extreme, where we have prefabricated implementation of the common architecture and other common subsystems and components. Another extreme might be an application framework. Or we might only have a set of loosely-coupled artifacts and a software architecture. Thus, there are lot of options to implement software product lines.
In future postings I will address architectural issues related to product lines in much more detail.

Friday, December 22, 2006

Design Erosion

Most software systems start with a clean and comprehensible software architecture. But then, developers are often forced to add or change the system under increasing time pressure. After a while the system is polluted with workarounds. The strategic core architecture becomes vague or even completely lost. Design erosion has caused a breakdown of the original software architecture. Is this the normal way of an architect's life or did we simply fail? In the waterfall model design erosion will be inevitably caused by architects trying to cover all requirements at once, which we call big bang approach. As you know, in a sufficiently large system you can never anticipate all requirements. Thus, you can never come up with a sound architecture in the first place. From my viewpoint, this problem illustrates why agile processes are not an alternative but a must. In order to cope with these challenges, we have to embrace change. Change will definitely happen. Hence, we as architects must open our software systems to allow tactical extensions. Using additional use cases or when priorities are changing, then even the strategic design might be subject to change. Refactoring will hence be an important tool for architects. As implementation and architectural soundness must go hand in hand, applications such as Sotograph will enable architects to make sure that the implementation does not violate architectural guidelines and conventions as well as quality aspects. But this is only the tip of the ice berg. Testing, organisation issues, and many other aspects play an important role. It is possible to prevent design erosion, if your process model, organization, methods, and tools are appropriate. In product lines this factors are even more important because of the significantly larger impact of any change. In some circumstances, however, requirement changes caused by new business models, technologies or desired features might be too far-reaching. In these cases, it is sometimes much more effective to throw away the old system and build a new one from scratch. "Throwing away" does not mean that you should throw away your well-proven best practices or experiences. Just ged rid of the old software system, not of your expertise. As a consequence, a good project will enforce the documentation of best practices (e.g., domain models or DSLs, patterns, guidelines). Design erosion is also a good example that all those comparisons of software engineering with other disciplines are often like comparing apples and oranges. For instance, when building a house no one would ever come up with proposals such as adding additional rooms or floors after construction is completed. But people tend to think software engineering should support exactly that kind of flexibility. That is also the reason why software engineering, especially designing a software architecture is a really tough task.

Sunday, December 10, 2006

Teaching the Architects

I published the last posting several weeks ago. But, of course, I have a good excuse: In the meantime, I gave a seminar on Software Architecture and participated in several Siemens-internal events. But now the time has come to continue with my architecture blog.
This time I'd like to address one specific issue. How can we effectively teach other persons everything they need to know about designing a high quality software architecture? For the sake of brevity, I won't cover what a software architect should know in this posting. In the seminars Frank (Buschmann) and I give, we mostly offer a mixture of Powerpoint presentations, discussions, and group exercises. In the presentation sections we also address things we've learned in projects. In the group exercise 3-5 attendees are then asked to design a small example application such as a Web Store or Chat Server. This setting works very nicely, but is far from being sufficient. Thus, another and additional approach is to teach and consult small project teams in real-world projects. In this scenario we start with a series of seminars and then participate in real-world projects as architecture consultants. However, this isn't sufficient too as we also need a kind of certification for software architects. Of course, small companies might not afford to spend all that time and budget for educating their staff in architecture concerns. But that is another topic.
I'd like to know what you think. I'd also like to know about your experiences. What did work for you and what didn't? How did you become a software architect? I am looking forward to all comments.