When it comes to software design, university programs put a lot of emphasis on UML. UML itself was a great effort to standardise the notation and representation of software concepts at a time that much needed it. If you pick up software design books dating 1995 and older, you will notice instantly how needed unification was. Today, UML is omnipresent and this is a good thing. It’s a great way to document and explain software. Including all diagram types and special syntaxes, it’s a great tool for any software developer to master.
My largest problem with UML is not UML itself, it’s in the people that swear by it and confuse diagrams with design. They build pretty class diagrams and believe they now have an architecture for their system. Belief is that all that needs to be done is generate the stubs, throw it at any code monkey to fill the loosely defined methods, compile the app, and you’re done. This is certainly better than the MDD belief saying that you can compile your diagram and the app will work. However, it’s still wrong.
From everything I have seen, this sort of Diagram Driven Design simply fails. The fact that the diagram is pretty, shows little coupling and high cohesion does not mean that the software does what it has to in the first place. A static view will never be enough to represent a program, because programs are not about the static aspects, their meaning comes from execution. The difference between a good design and a bad one is how it executes. How it initializes, binds with the problem to solve and interacts to the other components. Class diagrams can’t represent this. It has nothing to do with how it looks when printed on paper and how the boxes are arranged in a way that prevents lines from crossing.
Static views focus on conceptual purity. Methods get added because they make sense, not because they are needed. Or maybe they were in the head of the designer, but not in the head of the one implementing. Different people have different preferences in how they implement and get their code to work and if the designer did not communicate his ideas fully through dynamic views, the static view is just a piece of junk. On the other hand, if he was to build sequence diagrams for everything, he might as well write the code himself. I have yet to see a diagram tool that is faster to use than vim.
There are better ways to use a system architect than to ask him to draw diagrams. Get him to write the concepts and general directions in the most concise manner possible and let the implementer handle the low level design the way he prefers it. Results will come in faster, less waste will be generated and your architect will be able to do more, maybe even write code himself to make sure he stays grounded.
From the moment the important concepts and responsibilities involved are identified, a test-first approach will produce much better code. In fact, tests are not that important. Any implementation approach that places the focus on the facade of the components will produce better results. It’s just that doing this, tests are almost free, so why not do it. A well encapsulated component will be easy to integrate in a larger application, so developing it in isolation with tests is not much more trouble and there are additional benefits. Focus on how to use and encapsulate the code, not on how pretty it looks in a diagram. It will very likely be shorter, more efficient and contain less dead code.
At the other hand of the spectrum, some people focus too much on the low level details. A little while back, I saw a presentation on meta-programming. I must say that from a geek point of view, writing programs to rewite your programs is just cool. However, I can’t find a valuable use for it. I have serious doubts about the type of changes you can do from a low level static representation of your application. Examples included removing dead code. Sure, it sounds like a good idea, but dead code has nothing to do with static aspects, especially in dynamic languages. Another use was rewritting code in a different language. Sure, it can work if what you’re working on is a sort algorithm, but if you’re using a sort algorithm, it woul be pure luck if the algorithm you’re using will be called the same way in two different languages. This simply does not scale beyond the academic level. Code is rarely independent from the platform.
Sure, the static views remain important. I for one spend a lot of time formatting my code and reorganizing it to be more readable. This goes well beyond just following coding standards and it’s part of making the code self-documenting by making sure details don’t get tangled with business logic. I occasionally use diagrams to document my work (however I rarely — if ever — use class diagrams). In the end, it’s all about knowing who the artifact you’re building is aimed for. Code always is targetted towards humans. If it was not, we’d still be writing assembly and be happy with it. Then there is a distinction between writing the front-facing interfaces of a component and the internals of it. A poor design can be recognized by the amount of internal details bleeding through the facade the same way poor user documentation spends too much time explaining technical details.