Categories
Software Architect

“Perfect” is the Enemy of “Good Enough”

Software designers, and architects in particular, tend to evaluate solutions by how elegant and optimum they are for a given problem. Like judges at a beauty contest, we look at a design or implementation and immediately see minor flaws or warts that could be eliminated with just a few more changes or re-factoring iterations. Domain models simply beg for one more pass to see if there are any common attributes or functions that can be moved into base classes. Services duplicated in multiple implementations cry out their need to become web services. Queries complain about “buffer gets” and non-unique indexes and demand attention.

My advice: Don’t give in to the temptation to make your design, or your implementation, perfect! Aim for “good enough” and stop when you’ve achieved it.

What exactly is “good enough,” you might ask? Good enough means that the remaining imperfections do not impact system functionality, maintainability, or performance in any meaningful way. The architecture and design hangs together. The implementation works and meets the performance requirements. Code is clear, concise, and well-documented. Could it be better? Sure, but it is good enough, so stop. Declare victory and move on to the next task.

The search for perfection in design and implementation leads, in my opinion, to over-designed and obfuscated solutions that are, in the end, harder to maintain.

A number of the axioms in this book caution designers to avoid unnecessary abstraction or complexity. Why do we have problems keeping things simple? Because we are seeking the perfect solution! Why else would an architect introduce complexity in a workable solution except to address a perceived imperfection in the simpler design.

Remember that application development is not a beauty contest, so stop looking for flaws and wasting time chasing perfection.

'Coz sharing is caring
Categories
Software Architect

Shortcuts now are paid back with interest later

It‘s important to remember when architecting a system that maintenance will, in the long run, consume more resources than initial development of the project. Short cuts taken during the initial development phase of a project can result in significant maintenance costs later.

For example, you may have been informed that unit tests don’t deliver direct value and so you tell your developers to skip the rigorous application of them. This makes the delivered system much more difficult to change in the future, and decreases confidence when making those changes. The system will require far more manual testing for a smaller set of changes, leading to brittleness and increased maintenance expenses as well as a design that’s not as appropriate as a fully-tested design (let alone a test-first design).

A serious architectural mistake that is sometimes made is to adapt an existing system for a purpose that it is not fit for, on the basis that using an existing system somehow reduces costs. For example, you might find yourself utilizing BPEL architectural components coupled with database triggers to deliver an asynchronous messaging system. This might be done or insisted upon for reasons of convenience or because that is the architecture is known to you or the client. But a messaging architecture should have been selected in the first instance after requirements made it clear it was a necessary component. Poor decisions made at the inception of a project make it much more expensive to re-architect the system to meet new requirements.

In addition to avoiding short cuts during the initial development phase, it‘s also important to correct poor design decisions as quickly as they are discovered. Poorly designed features can become the foundation for future features making corrective action later even more costly.

For example, if you discover that inappropriate libraries were selected for some underlying functionality they should be replaced as soon as possible. Otherwise the effort to make them fit evolving requirements will result in additional layers of abstractions, each designed to hide the poor fit of the previous layer. You are building yourself a ball of tangled twine, tack, and sticky tape and with every layer you add, it is harder to unravel. This easily results in a system that is resistant to change.

As an architect, when you encounter an architectural problem or design flaw insist that it be rectified now, when it cheapest to fix it. The longer you leave it to drag out, the higher the interest payment is.

'Coz sharing is caring