I strongly believe in emerging design & evolutionary architecture. I've seen too much in my life ;> to believe in up-front design & beautiful pictures turning miraculously into flawless, working systems. I'll save you detailed reasoning as I've written about that on several occasions already in the past. Let's consider the emerging design instead, because I've seen many people struggling with the idea which seems so easy at the first glance:
- how to make it work?
- what are the pre-requisites?
- what should be avoided?
Contrary to the common belief, emerging design is not about taking it easy or going with the flow. If you get too spontaneous you may easily end up with an unmanageable mess & overwhelming sense of guilt ... Obviously emerging design isn't also about doing last minute design - trying to figure out (& document) all the details 5 minutes before starting to compose code.
What are emerging design's top priorities then?
What truly matters is velocity of change - design doesn't have to be rock-solid, perfect, doesn't have to survive until the rise of the robots - but it has to be flexible in a way that allows rapid changes that can be introduced within minutes at most. Yes, emerging design is mainly about REFACTORING - not because we'll necessarily fix something, but because we're working on something that is continuously evolving.
build quality in since the very beginning - the way quality works in software is quite simple: once you have it in, it's relatively easy to keep it on high level (if you know the drill), but if you lose it, it's incomparably expensive to get it back to the same level. Even in skunkworks - code against interfaces, keep coupling low, document assumptions with assertions (& tests in general), etc.
good versioning & dependency mgmt is priceless - some of your decisions will not be optimal, maybe even majority: you'll have to live with their consequences. In some cases, to cut off the rotting tail, you'll have to introduce the breaking change - but to do it in a proper way, w/o service interruption, suitable versioning policy has to be already in place. It's hard, it's intellectually challenging, but it's also the only way to avoid getting stuck in dependency bog.
make architectural decisions in code, not on paper / slides - that is the only way to make sure they are realistic, to authenticate & validate them and in the end - also to make sure they are fully understood and have gained full developers' support
- postpone decisions until you really need them - pre-mature design is an equivalent of excessive inventory in lean manufacturing / development
- when you have to make them (decisions), just do it! - don't over-analyze, don't aim for perfect decision - there's always more than 1 way to solve the problem & the key point is to be good enough, not flawless
- making mistakes is ok (as long as you've secured a short feedback loop & ability to insta-fix them) - it's not possible to know everything - and I don't mean technical expertise, but business reality, IT ecosystem, evolving market conditions; there will also be some unforeseen circumstances - with such a high degree of uncertainty, it's far important to just proceed & continuously adjust your course than to try to predict perfect direction since the very beginning
- dependency inversion principle FTW! - yes, I mean DIP which stands for "D" in SOLID; proper composition, well-defined junction points & reasonably applied blackboxing will save you many grey hair
- embrace static code analysis & convention testing - they are one of the best means you have to keep the control over something you want to change (e.g. get rid of) in your codebase; sadly very few people realize their benefits
- divide & conquer - I do not want this to sound like a cliché, but there's something in a nature of human beings that we frequently exaggerate the obstacles, overestimate their influence, get scared by the scale itself ... and in all of that we sometimes do not notice that what we're really facing is an unfortunate amalgam of more atomic, simpler problems that are just a bit tangled; what we have to do is just to break them, isolate & decimate one by one
Avoid at all cost
- fear of the changes - if no-one wants to take the responsibility for the change, if people don't understand the consequences of the change, if the change is performed blindly -> there's something evidently very & fundamentally wrong ;(
- breaking other people development or impeding them in a way they haven't been warned about; avoidig that is the main purpose of having sensible versioning policy & hiding implementation details behind interfaces - to make sure that whole solution is stable (it's not "flickering") & dependencies do not drag it down
- cherishing your ego - we all have opinions, preferences, personal ambitions - in many cases design is an opportunity to fulfill them, sometimes even to prove something (with heavy involvement of our ego ...); what we're losing in the mean-time is the proper focus on value, essence of collaboration, ability to state an objective opinion or just to yield, for the sake of teamwork and respect
- exposing internal models out of context boundaries - amen, regardless of how often it's mentioned by community authorities, people keep doing that due to their own laziness or carelessness
- putting re-usability or generality over other features (especially velocity of the change) - wise man said once: don't design for re-use, as re-use is the consequence of the good design
Embracing emerging design means that sometime we have to forget what we've been taught. It requires us to work in a more dynamic, "agile" way & clearly some are not comfortable with that style - especially people who need some very stable foundation to work upon. For them, the stability of this foundation means:
- well documented
- approved by several authorities
- based on battle-proven, commonly known patterns
Emerging design can provide similarly solid foundation, but this one are based on something completely different:
- automation (continuous inspection, build, integration, ...) & repeatability
- fine-grained composition & well defined interfaces
- quality built-in (with extensive test coverage)
You won't be able to truly embrace emerging design if you favor the first list instead of the latter.
Pic: Pieter Bruegel the Elder, "Tower of Babel"