With apologies to McIlroy, Pinson, and Tague.
A number of maxims have gained currency among the builders and users of microservices to explain and promote their characteristic style:
(i) Make each microservice do one thing well. To do a new job, build afresh rather than complicate old microservices by adding new features.
(ii) Expect the output of every microservice to become the input to another, as yet unknown, microservice. Don't clutter output with extraneous information. Avoid strongly-typed or binary input formats. Don't insist on object trees as input.
(iii) Design and build microservices to be created and deployed early, ideally within weeks. Don't hesitate to throw away the clumsy parts and rebuild them.
(iv) Use testing and deployment tooling (in preference to manual efforts) 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.
this is my ring of keys -- just three of them: work, home, car. i've been focusing over the last couple years on reducing. cutting back. lightening my load, etc. and the keys are one of my more obvious examples of success.
i've also been trying to lighten my load cognitively -- to reduce the amount of things i carry in my head and pare things down to essentials. i think it helps me focus on the things that matter when i carry less things around in my head. that's me.
staring at my keys today lead me to something that's been on my mind lately. something i am seeing quite often when i visit customers. the approach these companies use for governing their IT development lack the clarity and focus of my "three keys." in fact, most of the time as i am reading these companies' governance documents, they make me wince. why? because they're bloated, over-bearing, and -- almost all of them -- making things worse, not better.
over-constraining makes everyone non-compliant
i am frequently asked to provide advice on design and implementation of API-related development programs -- most often APIs that run over HTTP. and, in that process, i am usually handed some from of "Design-Time Governance" (DTG) document that has been written in-house. sometimes it is just a rough draft. sometims it is a detailed document running over 100 pages. but, while the details vary, there are general themes i see all too often.
- Constraining HTTP
- almost every DTG approach i see lists things like HTTP methods (and how to use them), HTTP response codes (and what they mean), and HTTP Headers (including which new REQUIRED headers were invented for this organization). all carefully written. and all terribly wrong. putting limits on the use of standard protocols within your organization means every existing framework, library, and tool is essentially non-compliant for your shop. that's crazy. stop that! if your shop uses HTTP to get things done, just say so. don't try to re-invent, "improve", or otherwise muddle with the standard -- just use it.
- Designing URLs
another thing i see in DTG documents is a section outlining the much-belabored and elaborate URLs design rules for the organization. Yikes! this is almost always an unnecessary level of "bike-shedding" that can only hold you back. designing URLs for your org (esp. large orgs) is a fool's errand -- you'll never get it right and you'll never be done with it. just stop. there are more than enough agreed standards on what makes up a valid URL and that's all you need to worry about. you should resist the urge to tell people how many slashes or dashes or dots MUST appear in a URL. it doesn't improve anything.
look, i know that some orgs want to use URL design as a way to manage routing rules -- that's understandable. but, again, resist the urge to tell everyone in your org which URLs they can use for now and all eternity. some teams may not rely on the same route tooling and will use different methods. some may not use routing tools at all. and, if you change tooling after five years, your whole URL design scheme may become worthless. stop using URLs as your primary routing source.
- Canonical Models
- i really get depressed when i see all the work people put into negotiating and defining "canonical models" for the organization. like URL designs, this always goes badly sooner or later. stop trying to get everyone/every-team to use the same models! instead, use the same message formats. i know this is hard for people to grasp (i've seen your faces, srsly) but i can't emphasize this enough. there are several message formats specifically designed for data transfer between parties. use them! the only shared agreement that you need is the message format (along with the data elements carried in the message).
- Versioning Schemes
- here's one that just never seems to go away -- rules and processes for creating "new versions" of APIs. these things are a waste of time. the phrase "new version" is a euphemism for "breaking changes" and this should never happen. when you build sub-systems that are used by other teams/customers you are making a promise to them that you won't break things or invalidate their work (at least you SHOULD be making that promise!). it is not rocket-science to make backward-compatible changes -- just do it. once you finally accept your responsibility for not breaking anyone using your API, you can stop trying to come up w/ schemes to tell people you broke your promise to them and just get on with the work of building great software that works for a long time.
so, stop constraining HTTP, stop designing URLs, stop trying to dictate shared models, and forget about creating an endless series of breaking changes. "What then," you might ask, "IS the proper focus of design-time governance?" "How can I actually govern IT systems unless I control all these things?"
three keys form the base of design-time governance
ok, let me introduce you to my "three keys of DTG". these are not the ONLY things that need the focus on IT governance, but they are the bare minimum -- the essential building blocks. the starting point from which all other DTG springs.
- Protocol Governance
first, all IT shops MUST provide protocol-level governance. you need to provide clear guidance and control over which application-level protocols are to be used when interacting with other parts of the org, other sub-systems, etc. and it is as simple as saying which protocols are REQUIRED, RECOMMENDED, and OPTIONAL. for example...
"Here are BigCo, Inc. all installed components that provide an API MUST support HTTP. These components SHOULD also support XMPP and MAY also support CoAP. Any components that fail to pass this audit will be deemed non-compliant and will not be promoted to production."
you'll notice the CAPITALIZED words here. these are all special words taken from the IETF's RFC2119. they carry particular meaning here and your DTGs SHOULD use them.
- Format Governance
another essential governance element is the message formats used when passing data between sub-systems. again, nothing short of clear guidance will do here. and there is no reason to invent your own message-passing formats when there are so many good ones available. for example...
"All API data responses passed between sub-systems MUST support HTML. They SHOULD also support one of the following: Collection+JSON, HAL, Siren, or UBER. sub-systems MAY also support responses in Atom, CSV, or YAML where appropriate. When accepting data bodies on requests, all components MUST support FORM-URLENCODED and SHOULD support request bodies appropriate for related response formats (e.g. Collection+JSON, Siren, etc.). Any components that fail to pass this audit will be deemed non-compliant and will not be promoted to production."
you'll notice that my sample statement does not include TXT, JSON or XML as compliant API formats. why? because all of them suffer the same problem -- they are insufficiently structured formats.
- Vocabulary Governance
the first two keys are easy. have a meeting, argue with each other about which existing standards are acceptable and report the reusults. done. but, this last key (Vocabulary Governance) is the hard one -- the kind of work for which enterprise-level governance exists. the one that will likely result in lots of angry meetings and may hurt some feelings.
there MUST be an org-level committee that governs all the data names and action names for IT data transfers. this means there needs to be a shared dictionary (or set of them) that are the final arbiter of what a data field is named when it passes from one sub-system to the other. managing the company domain vocabulary is the most important job of enterprise-level governance.
the careful reader will see that i am not talking about governing storage models or object models here -- just the names of data fields passed within messages between sub-systems. understanding this is most critical to the success of your IT operations. models are the responsibility of local sub-systems. passing data between those sub-systems is the responsibility IT governance.
what about all those "ilities"?
as i mentioned at the opening, these three keys form the base of a solid DTG. there are still many other desirable properties of a safe and healthy IT program including availability, reliability, security, and many more. this is not about an "either/or" decision ("Well, I guess we have to choose between Mike's three keys and everything else, right?" -- ROFL!). we can discuss the many possible/desirable properties of your IT systems at some point in the near future -- after you implement your baseline.
so, there you have it. protocol, format, vocabulary. get those three right and you will be laying the important foundation for an IT shop that can retain stability without rigidity; that can adapt over time by adding new protocols, formats, and vocabularies without breaking existing sub-systems or ending up in a deep hole of technical-debt.
those are the keys to a successful design-time governance plan.
it doesn't matter if your service is "micro" or "oriented", if it's tightly coupled -- especially if your service is on the Web -- you're going to be stuck nursing your service (and all it's consumers) through lots of pain every time each little change happens (addresses, operations, arguments, process-flow). and that's just needless pain. needless for you and for anyone attempting to consume it.
tight coupling is trouble
tight coupling to any external component or service -- what i call a fatal dependency -- is big trouble. you don't want it. run away. how do you know if you have a fatal dependency? if some service or component you use changes and your code breaks -- that's fatal. it doesn't matter what code framework, software pattern, or architectural style you are using -- breakage is fatal -- stop it.
you can stave off fatalities by wrapping calls to dependents in what Nygaard calls in his book Release It! a Circuit Breaker but that requires you also have either 1) an alternate service provider (or set of them) or, 2) you write your code such that the unavailable dependency doesn't mean your code is essentially unusable ("Sorry, our bank is unable to perform deposits today."). and the Circuit Breaker pattern is not meant for use when services introduce breaking changes anyway -- it's for cases when the dependent service is temporarily unavailable.
you're much better off using services that make a promise to their consumers that any changes to that service will be non-breaking. IOW, changes to the interface will be only additive. no existing operations, arguments or process-flows will be taken away. this is not really hard to do -- except that existing tooling (code editors, build-tools, and testing platforms) make it really easy break that promise!
there are lots of refactoring tools that make it hard to break existing code, but not many focus on making it hard to break existing public interfaces. and it's rare to see testing tools that go 'red' when a public interface changes even though they are great at catching changes in private function signatures. bummer.
so you want to use services that keep the "no breaking changes" pledge, right? that means you also want to deploy services that make that pledge, too.
honoring the pledge
but how do you honor this "no breaking changes" pledge and still update your service with new features and bug fixes? it turns out that isn't very difficult -- it just takes some discipline.
here's a quick checklist for implementing the pledge:
- promise operations, not addresses
service providers SHOULD promise to support a named operation (
findCustomer) instead of promising exact addresses for those operations (
http://myservice.example.org/findCustomer). on the Web you can do that using properties like
idthat have predetermined values that are well-documented. when this happens, clients can "memorize" the name instead of the address.
- promise message formats, not object serializations
- object models are bound to change -- and change often for new services. trying to get all your service consumers to learn and track all your object model changes is just plain wrong. and, even if you wanted all consumers to keep up with your team's model changes, that means your feature velocity is tied to the slowest consumer in your ecosystem - blech! instead, promise generic message formats that don't require an understanding of object models. formats like VoiceXML and Collection+JSON are specifically designed to support this kind of promise. HTML, Atom, and other formats can be used in a way that maintains this promise, too. clients can now "bind" for the messgae format, not the object model -- changes to the model on the service don't leak out to the consumer. when this happens, adding new data elements in the response will not break clients.
- promise transitions, not functions
service providers SHOULD treat all public interface operations as message-based transitions, not fixed functions with arguments. that means you need to give up on the classic RPC-style implementation patterns so many tools lead you into. instead, publish operations that pass messages (using registered formats like
application/x-form-urlencoded) that contain the arguments currently needed for that operation. when this happens, clients only need to "memorize" the argument names (all pre-defined in well-written documentation) and then pay attention to the transition details that are supplied in service responses. some "old skool" peeps call these transition details FORMs, but it doesn't matter what you call them as long as you promise to use them.
- promise dynamic process-flows, not static execution chains
serivces SHOULD NOT promised fixed-path workflows ("I promise you will always execute steps X then A, then Q, then F, then be done."). this just leads consumers to hard code that nonsense into their app and break when you want to modify the workflow due to new business processes within the service. instead, services SHOULD promise a operation identifiers (see above) along with a limited set of process-flow identifiers (
done) that work with any process-flow that you need to support. when this happens clients only need to "memorize" the generic process-flow keywords and can be coded to act accordingly.
not complicated, just hard work
you'll note that all four of the above promises are not complicated -- and certainly not complex. but they do represent some hard work. it's a bummer that tooling doesn't make these kinds of promises easy. in fact, most tools do the opposite. they make address-based, object-serialization with fixed argument functions and static execution chain easy -- in some tools these are the defaults and you just need to press "build and deploy" to get it all working. BAM!
so, yeah. this job is not so easy. that's why you need to be diligent and disciplined for this kind of work.
and -- back to the original point here -- decoupling addresses, operations, arguments, and process-flow means you eliminate lots of fatal dependencies in your system. it is now safer to make changes in components without so much worry about unexpected side-effects. and this will be a big deal for all you microservice fans out there because deploying dozens of independent services explodes your interface-to-operation ratio and it's just brutal to do that with tightly-coupled interfaces that fail to support theses promises inherent in a loosely-coupled implementation.
for the win
so, do not fear. whether you are a "microservice" lover or a "service-oriented" fan, you'll do fine as long as your make and keep these four promises. and, if you're a consumer of services, you now have some clear measures on whether the serivce you are about to "bind" to will result in fatalities in your system.
Web For All
one of the key principles for W3C is the "Web for All"
The social value of the Web is that it enables human communication, commerce, and opportunities to share knowledge. One of W3C's primary goals is to make these benefits available to all people, whatever their hardware, software, network infrastructure, native language, culture, geographical location, or physical or mental ability.
when a single vendor has the power to block others' access to competitive products, the Web is a place that doesn't live up to this principle. I know that Tim Berners-Lee is not responsible for the way Amazon operates. Neither is W3C CEO Jeffery Jaffe. however, this unfolding battle to pre-empt Web user's ability to access any content anywhere is just another iteration of the same battle that timbl (Berners-Lee's handle) has called out numerous times at the network level. what he calls the Battle For The Net.
users over all others.
i know the W3C has attempted to deal with this in the past -- to mixed reviews. the very fact that Tim penned that piece on DRM and the Web shows that the W3C is aware of the issue. and a key part of that (now two-year-old) position paper was the notion of "users over all others":
In case of conflict, consider users over authors over implementors over specifiers over theoretical purity.
but events in this space seem to continue to run ahead of the W3C's ability to deal with them. and that's a big problem.
i know its hard, but it is important
i understand that the job of reigning in corporate greed on the open web is a tough job. and someone who has the best interests of users above all others needs to be leading the discussion. not following it. and certainly not silent while others establish the "operating rules" for yet another walled garden of profit built on the backbone of the free and Open Web.
enabling commerce is a good thing.
permitting exploitation and profiteering is not.
Tussle in Cyberspace
there is a great paper that deals with some of these issues: Tussle in Cyberspace: Defining Tomorrow's Internet. essentially:
This paper explores one important reality that surrounds the Internet today: different stakeholders that are part of the Internet milieu have interests that may be adverse to each other, and these parties each vie to favor their particular interests. We call this process “the tussle”.
the "tussle" is important. not because it happens, but because one of the key values of an open internet (not just Web) is that the Internet can be crafted (through standards) to "level the playing field" for all. this is why "Web For All" is important. this is why the Battle for the Net is important.
and it is the same for video content, too.
why standards exist
we don't need to "regulate" vendors, we need to continue to make sure the tussle is fair to all. that's why standards exist -- to level the playing field.
and, IMO, that's why the W3C exists.
and that's why the current news is disturbing to me.
Layer7's brain child
the idea for the API Academy came out of the core leadership of what was then known as Layer7. basically, it was the chance to pull together some of the great people involved in APIs for the Web and focus on promoting and supporting API-related technologies and practices. from the very beginning it was decided that the API Academy would focus on "big picture stuff" -- not a particular product or technology segment. and we dove in with both feet.
my first talk as part of the Academy was June 2012 on hypermedia and node.js at QCon NYC. Ronnie and i finally met face-to-face later that summer at the Layer7 office in Vancouver. we both talked at RESTFest 2012 where Layer7 became a key sponsor of that event. in December of 2012, Ronnie and I were proud to join Mehdi Medjaoui at the very first API Days in Paris. and we've been going strong ever since.
the API Academy is an amazing group of people. over the last three years, along w/ Matt and Ronnie we've had the chance to host Alex Gaber, Holger Reinhardt -- both of whom have moved on to other things -- and Irakli Nadareishvili who came to us from his work at National Public Radio here in the US. the oppty to work side-by-side with people of this caliber is a gift and i am happy to be a part of it.
since i joined API Academy, Layer7 has merged w/ CA Technologies and this has given us the chance to expand our reach and increase our contact w/ experienced people from all over the world. since joining w/ CA we've had the chance to travel to Australia, Hong Kong, Tokyo, Seoul, Beijing, and several cities Eastern Europe. later this year there will be visits to Shanghai and Rio de Janeiro along w/ dozens of cities in the US and Europe. along the way the API Academy continues to meet w/ CA product teams and leadership offering to assist in any way we can to continue the same mission we had at our founding.
Help People Build Great APIs for the Web
i've worked lots of places, with diverse teams, in all sorts of cultures. i have to say that my experience w/ the API Academy and w/ CA continues to be one of the most rewarding and supportive i've ever enjoyed. i am very lucky that i get to do the kind of work i love w/ people that challenge my thinking, support my experimenting, and offer excellent opportunities to learn and grow along the way.
the last three years have been full of surprises and i can't wait to see what the next three years brings. i am truly a #luckyMan