Musings on SOA Design
There’s a good reason that many software developers and system administrators prefer Unix (and Unix-like operating systems like Linux) over the alternatives. I recently came across a copy of Eric Steven Raymond’s book, The Art of Unix Programming, now available online at no cost. I used this book years ago when I was programming equity trading systems on Solaris workstations and found it very useful. While browsing the online version of the book, I happened upon the chapter Basics of the Unix Philosophy and was reminded of how well the Unix design philosophy, 20 years later, maps to good SOA design.
It’s worth repeating Eric’s opening explanation of what the Unix philosophy is and where it came from:
“The ‘Unix philosophy’ originated with Ken Thompson’s early meditations on how to design a small but capable operating system with a clean service interface. … The Unix philosophy is not a formal design method. It wasn’t handed down from the high fastnesses of theoretical computer science as a way to produce theoretically perfect software. Nor is it that perennial executive’s mirage, some way to magically extract innovative but reliable software on too short a deadline from unmotivated, badly managed, and underpaid programmers.”
How many large enterprise SOA (or software development) projects have come unglued after wasting untold millions? Quite a few in my personal experience, as well as others (see Tim Bray’s Doing it Wrong). In most of these cases, a huge up-front investment was made in an attempt to codify, document, over-design and cater to competing interests, while basic design principals (a ‘design philosophy’) overlooked. I’d like to propose the following high level design principals as the basis for good SOA design, borrowed and modified from Doug McIlroy:
- Make each service do one thing well. To do a new job, build afresh rather than complicate old services by adding new features.
- Expect the output of every service to become the input to another, as yet unknown, service. Don’t clutter output with extraneous information. Avoid stringently columnar or binary input formats.
- Design and build services to be tried early, ideally within weeks. Don’t hesitate to throw away the clumsy parts and rebuild them.
- Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you’ve finished using them.
Basics of the Unix Philosophy is a great read for anyone designing services in a SOA. Nearly every rule is directly applicable to the process; in fact many require no ‘translation’ from the world of software design, where they were created, to the distributed world of SOA. Let’s look at each of the 17 rules and how they apply to good SOA design.
Rule of Modularity
Write simple parts connected by clean interfaces. This is probably the most important of the rules. It can be difficult, or required extra work, to create clean interfaces, especially when dealing with legacy systems, but it’s essential for ongoing maintenance. Eric writes:
“The only way to write complex software that won’t fall on its face is to hold its global complexity down — to build it out of simple parts connected by well-defined interfaces, so that most problems are local and you can have some hope of upgrading a part without breaking the whole.”
and what is a SOA except a very large, complex, distributed piece of software? In this light consider RESTful interfaces over SOAP/WSDL, unless WS-* is a requirement and the functionality can’t easily be built. There are many cases where the choice of one vs. the other are a requirement, in which case the choice is made for you, but when designing, favor the simpler.
It’s easy enough to design simple, clean components when in a greenfield project, but as soon as legacy systems enter the picture (and they almost certainly will), it gets a bit tougher. The orchestration layer is where this will happen, and it’s important to focus properly on this layer when designing: simple clean interfaces exposed to the enterprise, and the proprietary, ugly interfaces localised in legacy applications. This is where problems are most often seen, especially since SOA projects are chronically under- or incrementally funded. This is also where trial-and-error and throw-away prototypes are critical. Equally important is to have an end in mind: how/when/where will those legacy systems be replaced? If no one has an answer, make an assumption and plan accordingly.
Rule of Clarity
Clarity is better than cleverness. Code is written once and read many times. While not specifically related to SOA, as a general principal, making interfaces clear and simple reduces problems later. Does a service in the registry with the name eligibleCounterparty() determine if the counterparty is eligible, or make it eligible? Does REQUIRE-SSL=1 in a config file mean that it does or does not require SSL? Coding standards and guidelines don’t have to be draconian; get developer buy-in early.
Rule of Service (de)-Composition
Design services to be connected to other services. This is probably the most radical shift in thinking. Many people think of services as producers/consumers for applications only. This form of design limits the possibilities for reuse, and reduces the agility with which services can be recombined into new services or applications. If services are easy to connect to one another, new custom applications can be quickly created out of existing services. Imagine being able to string enterprise services together the same way you do Unix commands connected by pipes. Make I/O formats simple, and create services that provide simple data augmentation, transformation or filtering, as well as serving as ultimate sources/sinks of data.
Rule of Separation
Separate policy from mechanism; separate interfaces from engines. Service policies such as authentication, access control, etc. need to be implemented as a separate framework and not integrated into services. Policies change far more frequently than mechanisms, therefore service mechanisms should be implemented as first class objects in the enterprise. This can often be combined in a registry.
Rule of Simplicity & Rule of Parsimony
Design for simplicity; add complexity only where you must.
“Even more often (at least in the commercial software world) excessive complexity comes from project requirements that are based on the marketing fad of the month rather than the reality of what customers want or software can actually deliver. Many a good design has been smothered under marketing’s pile of “checklist features” — features that, often, no customer will ever use. And a vicious circle operates; the competition thinks it has to compete with chrome by adding more chrome. Pretty soon, massive bloat is the industry standard and everyone is using huge, buggy programs not even their developers can love.” — Eric Steven Raymond
It’s difficult to find many architects what would disagree with goal of simple service design, until they’re all in a room arguing for their pet interests. This is an aspect of SOA design that isn’t (usually) technical, but more often than not organizational and political. At an enterprise level having a strong, motivated team of leading (enterprise) architects, who have internalised good design principals is essential.
This rule is often violated by ‘creeping featureitis’, where the temptation is strong to add just a little bit more here or there to satisfy some requirement. One good way to counter these tendencies is by the rule of parsimony: Write a big program only when it is clear by demonstration that nothing else will do. If a solution architect is proposing a large, complicated service, the burden of proof is on them to demonstrate that this is the only way to meet the requirement. Minimize this tendency by making it easy to create new services; lower the overheads in administration, approval, and deployment of services for example. Clear examples and templets that can be used off-the-shelf help as well.
Rule of Transparency
Design for visibility to make inspection and debugging easier. It’s hard to underestimate the importance of this rule in minimizing costs, frustration and project delays. Best practice these days says that a Common Alerting, Logging & Exception (CALE) framework should be used for this purpose. Several vendors and consulting companies offer these in various forms. Some you get ‘free’ with consulting, some are offered as products in their own right, though usually unsupported except by more consulting. A CALE framework, whether purchased or bespoke, will repay the price many times over. Consider writing application specific tests that utilize this framework too. A CALE will find many uses in a SOA.
Rule of Robustness & Rule of Repair
Postel’s Prescription says: “Be liberal in what you accept, and conservative in what you send”. He wrote this in the context of traditional Unix network service programs (e.g. sendmail), but it’s a good strategy for SOA services too. In an environment with many services connected together and in use by unknown clients, be tolerant in handling inputs. Ensure that input processing is simple and that you conform strictly to the output specified for the service. If sending/receiving XML, it’s worth considering Doug McIlroy’s warning:
“The original HTML documents recommended “be generous in what you accept”, and it has bedeviled us ever since because each browser accepts a different superset of the specifications. It is the specifications that should be generous, not their interpretation.”
Repair what you can, but when you must fail, fail noisily and as soon as possible,which is simple enough not to warrant further comment.
Rule of Representation
Fold knowledge into data so program logic can be stupid and robust. Data representation and transformation are major challenges facing any SOA designer today, with plenty of literature on the topic. From the viewpoint of Unix Philosophy & SOA, consider simple data representations like JSON over XML when possible. They’re easier to change and are mostly understandable by humans (see the Rule of Economy).
Rule of Least Surprise
In interface design, always do the least surprising thing. Does your organisation have conventions about the location, format or type of configuration file? If so, use them. It’s very unlikely that you’re going to come up with a better solution because your config file ends in ‘;’ instead of ‘\n’. In the same vein, if BO refers to ‘back office’, stick with the convention! The goal here is to ease the learning curve for others and minimise surprises.
Rule of Silence
When a program has nothing surprising to say, it should say nothing. If services are designed to work together, to create/consume data, silence is golden. If there’s nothing to report, don’t report anything. If there’s no filter/augment/transform to perform, do nothing; just pass the data along unchanged with nothing extra.
Rule of Economy
Programmer time is expensive; conserve it in preference to machine time. Although dated, it’s worth remembering that programmer time is still expensive, probably even more so today. Anything that increases programmer productivity, as many of these rules do is probably worth implementing.
Rule of Generation
Avoid hand-hacking; write programs to write programs when you can. CORBA has the IDL (Interface Definition Language) generator. While CORBA has generally fallen out of favour today, there are still many organisations using it, and IDL is one example of where complexity can be removed by code generations. In the Java world, JAXB is an example of where code generation can save many hours of programmer time. Standardizing these technologies across the enterprise (as opposed to ad-hoc usage) can yield many benefits.
Rule of Optimization
Prototype before polishing. Get it working before you optimize it. This is one of my favourites. I can’t tell you how many times I’ve seen companies spend countless hours discussing perceived performance issues before a single line of code was written — all attempting to address problems that are unlikely to ever be seen. Often the design work for the case encountered 0.0001% of the time wastes so much effort to sign off that the rest of the process is short-changed on resources. Eric writes:
‘Donald Knuth (author of The Art Of Computer Programming, one of the field’s few true classics) popularized the observation that “Premature optimization is the root of all evil”.’
This is one of the most overlooked, yet most important of the SOA design rules. If you really think there’s a performance problem, build a tool to test your hypothesis.
Rule of Diversity
Distrust all claims for “one true way”. (Unless you’re talking about emacs vs. vi). Make it easy to access services from multiple operating systems, languages, locations. Consider adding scripting languages to all services, via standardised interfaces (Guile is one of my favourites for this).
Rule of Extensibility
Design for the future, because it will be here sooner than you think. Plan on services being used in ways you haven’t imagined. Make data formats easy to change. Make configuration files extensible. The only constant today is change; services had better be ready for them.















Recent Comments