Freigeben über


When’s a principle not a principle? When it’s an Anti-Principle!

“When’s a principle not a principle?” was what I muttered to the person next to me at the UK IASA meeting earlier this week. But I think I do “an anti-principle!”

About 30 people turned up at the Onalytica offices to enjoy pizza supplied by Microsoft and to take part in a great workshop on applying design principles led by Eoin Woods, Nick Rozanski and Chris Cooper-Bland. As part of the introduction Eoin went through a baker’s dozen well known and not-so well known system design principles that were used in subsequent the exercise:

  • Minimise coupling
  • Maximise Cohesion
  • Minimise complexity
  • Maximise genericity
  • Hide Information
  • Modularise implementations
  • Structure using services
  • Design for concurrency
  • Identify what varies and encapsulate it
  • Keep dependencies acyclic
  • Dependencies should reflect stability
  • Make Stable elements abstract
  • Define things once

Although I think that there is much merit in these principles, many are used implicitly in the design of systems, I worry that by stating explicitly and used as a rule there could be are serious side effects.

First, there seems to me much duplicity here, for example 1,2,5, 6, 7 and 9 I think could all reasonably refer to the same principle of “Encapsulate where applicable” [Matt Deacon 2010]. Out of all of these the Gang of Four version “Identify what varies and encapsulate it” is the best as at least it responds to my next and perhaps, bigger concern.

Second, by using principles, it may be possible to defer responsibility to a default state which can lead to a poor solution for a given context. It becomes too easy to defer to the principle over making the right choice for a given situation which can lead to issues such as over-engineering, increased complexity, increased maintenance or poor performance. It is my contention that the context in which a principle might ubiquitously apply is so small as to make the overhead of their use far too expensive.

Third, the definitions and explanations for these prinicples may be in themselves, confusing or misleading, or open to interpretation. As Nick said late on it is “essential to be clear and unambiguous in the definition of principles” if they are to be used. As examples, I found “Maximise genericity” confusing (not just in trying to say the word after a beer) – does it mean to take a standard design approach or to create one? “Hide information” was another, besides the horrible use of the word “Hide” the description suggested to “hide as many design decisions as possible” and although it probably referred to implementation details it could easily lead to misinterpretation. It concerns me that in order to make these things brief and consumable we lose some of the clarity and accuracy of what we mean to convey/

So having sat back and thought on all this for a while I have tried to articulate a “set of principles on using principles wisely”, or what I think I’ll call a set of Anti-Principles!

Don’t hide behind principles (aka the blanket principle) . When introducing a principle it can be all too easy to assume that this applies in all cases. However, it is often the case that a principle only applies in certain contexts even within a single design. Assuming a blanket approach to context can significantly impact other key aspects of a system requirements and quality attributes. For example using the principle “Structure using services” has a innate impact on performance. This may prove significant or not dependent on the context, but by using a blanket principle who is to know?

Not all principles are good bedfellows. In choosing to take on a principle, it is important to consider the impact that this will have on other principles and design considerations or quality attributes. Designing for concurrency might achieve performance but impacts on complexity, structuring as services might modularise a design but impacts also on complexity and performance and may impact on being able to define things once. Principles are not independent and can create a design conflict in which often all principles suffer.

Principles doesn’t trump pragmatism (aka over-engineering through principles) . A closely related outcome of both anti-principles above, is the introduction of unnecessary complexity through over-engineering. A blanket application of principles may lead to an overly complex solution in certain parts of a system where there is no current requirement for this to be the case. This is further exacerbated by the fact that the complexity at first glance appears to be practice but is in fact an over-engineering of the problem due to adhering to a principle.

To demonstrate these anti-principles let’s take the example from the workshop.

image

The functional model describes several modules and a large monolithic database (plus config database) that we assumed was shared across the modules. As best as one could tell the design appeared reasonably well “modularised” but it was thought that the data store might compromise “modularity” or “coupling”. to solve this it was suggested that the data might be broken up and the parts maintained within the module to which it applies, in so doing we’d conform to the “hide information” principle.  However, concern was expressed that data may be required by multiple modules which might lead to compromising the “define things once” principle as private data may become duplicated. A natural conclusion would be to extract this data out to a separate ‘shared’ module. On one level the new design would appear an correct and appropriate but this now creates an additional layer of complexity not contained within the original design, nor dictated by any functional requirement of the solution as a whole.

It is not possible to say with certainty how to best resolve in this particular instance with the information available, but it does illustrate the need for pragmatism and flexibility when considering principles for a project and much more so when one considers laying down principles at an enterprise wide level.

I think there is much that can be learnt from the agile development in this respect and that rather than setting down principles and rules up front, an architecture needs to be more adaptive and refactoring more acceptable. Building software we all know is not like building buildings, it’s set in a context of uncertain requirements and in a medium of the virtual and abstract unconstrained by physics. Guidance through principles I would agree is valid, but these should not be viewed as laws, for if that is the case, they will be broken but this will be hidden. Far better that we challenge the default and if we carry ‘debt’ as a consequence, that ‘debt’ is known and can be managed.

The value of managing “Technical Debt” is another agile concept from which much benefit can be taken but that I’ll leave for another day.