Translate

July 14, 2016

In principle, it's all architecture, unless it's not... or something like that.

Welcome to the wonderful world of architecture principles. A world where everything is a has to unless you've got a good justification not to.
This is an introductory for a multi-piece on a variety of Architecture Principles that I've come across in the last 5 years while working on Cloud, SOA and POA architectures.
Architecture principles are ground rules by which we develop our software. This ranges from ways of working to styles of coding, from software decomposition to business compliance, from infrastructure choices to security implementations. As you can see, it covers pretty much everything related to the development of business services, online, offline and internal.
Architecture principles are setup such that you just comply with them, unless there's a very good reason not to, and then you don't. A good example might be that everything is hosted in the public cloud, unless for compliance reasons we need to host on-premise.
All principles should lead back to our strategic goals, business goals preferably.
As a refresher, the way architecture within many companies works is as follows: As a company we have a mission, and a vision on how to accomplish the mission we've set out. There's a strategy on how to implement that vision, which consists of strategic goals that when met, we know we've implemented our vision. Turning the whole thing into a road-map from where we are to where we want to be with milestones to be reached, and steps to be taken in order to get to the next milestone. Our strategic architecture shows us the shape we're in at the various milestones, the tactical architecture shows us where we are after each step we have to take. Architecture is therefore a journey. It's not a noun but a verb instead.
Architecture is just like a satnav, you get your bearings and determine where you are, you set the location of where you want to go and the satnav calculates the best route depending on your settings regarding toll-roads, ferries and time our distance settings. And with every turn to be taken, the satnav recalculates the best route based on the most current information regarding traffic, road works, etc.
Architecture principles tell us the rules by which we live while on our journey, there's a justification for these rules explaining why obeying that rule takes us closer to our goal(s). Traffic law if you will. There's a speed limit on the road we're traveling. Obeying the law and sticking with the speed limit will ensure a save trip to our destination, but sometimes we have a passenger that's bleeding out, if we don't hurry and get to an ER, forgetting about the speed limit, caring for the passenger only. When we attest the traffic fine associated with the ticket for speeding the judge will waive the fine as a person's life is deemed invaluable. But if we just go speeding because it's so much more fun to go 200 km/h instead of the allowed 130 km/h there's no lenience from the judge as 'fun' is not considered a proper justification. Taking into account, and taking stock off the fact that every violation, even when justified, increases our architectural debt.
Architecture principles are therefore to be considered the default action to be taken, the default direction to head for. It's a matter of "This is how we do it, unless...". There are sometimes obvious 'unlesses', as in "We use Linux, unless Linux is not an option". But in that same vain, the principle could be: "We use Linux, unless Linux is not an option, then we use Windows". In which case there is no unless, there's no excuse to not use Linux or Windows. Every principle of this kind is clearly formulated as such. When there's no room to maneuver, there's just no room to maneuver.
Lastly, regarding architecture principles, we have to understand that principles will change, they will be revisited over time. As our mission, vision, strategy or goals change, our principles may have to change as well. As our world changes, our principles will change as well. They're not carved into stone, they're written using Permanent Markers. And we all now that permanent markers on a whiteboard can be erased with whiteboard markers.
Changing our principles or violating them, results in architectural debt. And as with financial debt, there is an interest to be paid. The more debt we have, the more our software costs. This is very much like technical debt that accumulates during software development, but where the interest paid on technical debt is typically analog to the interest on a mortgage or even a personal loan with a bank, architectural debt is close to the interest a loan-shark issues. And not paying of those debts, well the analogy continues there as well.

Without any further ado, let's start our journey...
Iwan

July 12, 2016

API Versioning, another religious war

Summary: When you ask your best friend, e.g. Google, for an answer as to what is really the best way to handle different versions of the same interface, you'll find out that there is no straight answer. Actually it is a religious war and many of the  arguments given for either of the various ways of versioning interfaces are actually just opinions on aesthetics. Below you'll read my reasoning for what my views are on the various options you'll have to version your service interfaces. Probably you'll find other ways of skinning this cat as well.


One of the core aspects that we need to decide upon when working on our web-services is decide on how we will handle different versions of the services.
There are two dimensions to this:
  1. Production vs. Non-Production (We're not doing DTAP but PorN) See the relevant principle here: Everything is Production or Not Principle
  2. Current version of the web service and the next version of the web service.
Although these dimensions seem to be different, in fact we're talking about one and the same challenge we'll have to overcome.
Basically we have a version of a service in production, and one version in development (in case we need to change the service). Once that development version reaches production, we have two versions in production according to this principle Service Interface Compatibility Principle. As long as no customer can access the version that is in development, this version is not in production, according to principle RBAC is everywhere, every service can only be used by a user with the right role. Somebody not being a developer cannot use a service that is in development. This is an important notion because it removes the necessity of a separate infrastructure to separate production from non-production, although it still might be a good idea to have some separation.
As a consequence, we can deploy a service and limit access to the service through Role Based Access Control and since development of a service always results in a new version of that service, we can see the solution to dimension 2 as a solution for dimension 1, essentially allowing us to see both to be the same.
Looking at service versioning, we have to distinguish between service interface and service implementation. Since both have their own life-cycle, we can treat them separately. In addition, when we talk about service versioning we are mainly concerned about the impact of a new version of a service onto the consumer of that service, so we're concerned about the service interface and not so much with the service implementation. So within the scope of this post, we're discussing the version of the interface and not its implementation.
Furthermore, when we talk about services, we talk about RESTful services. And finally, we talk about the version of the published interface which is different from the version of the source code implementing that interface or the service attached to it.
When the interface of a service changes, we either deal with a change that breaks the consumer, or one that doesn't break the consumer. At all times we strive for the latter, since not breaking the consumer means no impact on the consumer. Changes that extend the resource, are changes that have no impact, since consumers of RESTful services are to ignore what they don't know. So any new fields in the resource representation will be ignored. Consumers that ignore these fields will not be able to benefit from the change. These are syntactical changes we want, and versioning has negligible impact on the consumer, the consumer does not need to be aware of the change.
Changes to the syntax of the resource representation we don't want but are inevitable, are those that change existing fields. For example they change the type of a field from an integer to a float. In this case we need to make sure that the consumer is not confronted with the change without it changing as well. Hence either the service should no longer be accessible, resulting in an error at the consumer, limiting damage. Or by being backwards compatible and thus returning the old representation to that consumer.
As a third change, we have semantic changes, which are changes to the actual resources. For example a generic resource turns out to have become more specific and we start limiting representations to just those specific resources. For example we have the concept of Customer which is a Company with which we have a Contract, and then we also have Customers that are not companies but Consumers, although still Customers, they're not the same. As the semantics of the resource has changed, we can't talk about the resource in relation to the changing interface as if it were the same resource. The actual resource has changed, so has its representation and therefore it impacts the consumer, which will break. In this case, again, we need to make the old service to become unavailable or we keep on supporting it.
There are in essence three major philosophies when it comes to API or service versioning:
  1. Include a version in the URI that identifies the resource, e.g. https://www.foobar.com/api/<version>/<resource>
  2. Include a version in the URI that identifies the resource, using a request parameter, e.g. https://www.foobar.com/api/<resource>?version=<version>
  3. Include a version in the Accept-header of the request, thus using http Content Negotiation, Accept: application/vnd.<resource>.<version>+json
Of these three cases of changing interfaces, the last one is the easiest to address. Since the change results in a new resource type, the identifier of the resources, the URI, must be changed. This results in a URI in accordance with: http://www.foobar.com/api/<version>/<resource>. Although the location of the version indicator is arbitrary, the best practice is to have it as close to the domain as possible. Typically right before or right after the resource. The philosophy here is that we're talking about a new resource and not a new version of an existing resource. Hence the version indicator in front of the resources. Alternatively, the version is omitted and a new resource name is used. This is preferred when the resource should have a new name. In the example above the URI could change from http://www.foobar.com/api/customer to http://www.foobar.com/api/customer/consumer and http://www.foobar.com/api/customer/company.
Note that it remains a challenge to decide what the old URI will return.
The first and second change types are actually similar and should indicate a new version of an existing resource. When we encode the version in the URI, it makes most sense to do it after the resource indicator; http://www.foobar.com/api/<resource>/<version>. The problem here becomes immediately clear as it very much resembles the version in the previous scenario. Keeping these the same will be confusing. Alternatively, this would be a good candidate for the Accept-header option, keeping the URI the same and only use the accept-header for content negotiation. The resource stays exactly the same, so the identifier of the resource as well. The version of it's representation changes though, i.e. the indicator in the request depicting what format is accepted by the consumer, is explicit. Accept: application/vnd.<resource>.<version>+json.
There is a rather major drawback with this approach in that it becomes rather complicated to quickly test the solution, since from a browser, the http-header is almost never open for manipulation. So this solution doesn't allow for usage from the browser address-bar. This is typically solved by supporting both versioning strategies simultaneously. Which allows for two major advantages, besides support for programmable consumers and browsers;
  1. The URI approach for versioning will return the relevant documentation of the API for that particular version, if that version exists or an http error when it doesn't.
  2. The baseline URI can remain and stay usable. Access to the resource is through http://www.foobar.com/api/<resource> and the acceptable version by convention when none is specified in the header is the first version of the resource, or alternatively, the oldest supported version in case versions are at some point dropped.
By following the above, the intentions of services and therefore API's remain.

When you ask your best friend, e.g. Google, for an answer as to what is really the best way to handle different versions of the same interface, you'll find out that there is no straight answer. Actually it is a religious war and many of the  arguments given for either of the various ways of versioning interfaces are actually just opinions on aesthetics.
Above you're reading my reasoning for what my views are on the various options you'll have to version your service interfaces. Probably you'll find other ways of skinning this cat as well.
My advice to you is to closely look at your specific situation, what you want from your interfaces, the need for (backwards) compatibility and then choose wisely.

July 4, 2016

Why Uber is so applicable in the agile delivery of software

After a short week abroad and various discussions with some excellent developers over there, it is clear to me; Uber is not just very convenient when you want to go from A to B in Cairo, but it is also extremely applicable when discussing the way we develop web-services.
Let me explain to you how Uber got into being. In fact, how Uber Black got into being. It all happened in New York City, a buzzing city where it pays not to have a car and have somebody else drive you. Reason being that parking in NYC is rather problematic if not costly. So when you walk around in the Big Apple, you're bound to see those yellow cabs, the iconic taxis in New York City. And while you're at it, you'll see those large limousines, Lincoln Towncars mainly. These are black, and these are very convenient, luxurious means of getting around in New York. The problem with these limo's is that you have to call them, they're not allowed to respond to the cab-hailing crowd on the sidewalks. The crowd is for the yellow cabs, the customers of the limo's are at home. You have to call them. They're somewhere out there and you have to wait for them to arrive. And that's where the problems start since neither driver nor drivee knows where the other person is. So when it takes too long for the limo to arrive, you're bound to become impatient and call another one, or just walk out the door and hail a yellow cab. They're in abundance. So eventually the limo driver shows up at your doorstep with you already gone. A situation that's not cool for the driver and so next time he hits a traffic jam, he'll just ignore you and wait for another ride, even though you're all patience and waiting for the limo to arrive... soon. It's a bad experience for everybody.
Uber solved this by providing both customer and driver with an app that shows exactly where the other person is. So you know where the heck the driver is and the driver knows exactly where he has to pick up his customer. Furthermore, as everywhere in the world, customers in New York don't trust the cab-meters so there's always a dispute about the cost of a ride. Another problem that was solved by Uber as they want you to state where you want to go and by means of the GPS of your phone they know where you are. So you get a quote of the price and that's it. No more disputes about your fare and since you've provided your credit card, no need for change. Oh, and those weird, rude and above all smelly drivers are getting a bad rating, so when a badly rated driver is responding to your request for a car, you just cancel the ride and try again.
Image result for lincoln towncarSo now let me explain the way Uber works, from a consumer perspective, for those that are not (yet) familiar with the disruptive nature of Uber; First of all, you need to have an account with Uber, that holds your name and your payment method, as well as your phone number. So basically Uber wants to be able to know you, wants to know how you'll be paying for the services and how to contact you. Once you've got your account all setup, you can use their service. Even in cities without limo's you can use Uber, it's called UberX and it's an alternative to other taxi services.
When you need a car, you typically start the App on your phone and it recognizes where you are, based on your GPS location and it asks you where you want to go. Then you can see the cost of the fare and when you're okay with this, you request a car. This is where the fun starts, because a driver accepts the ride and you can see who it is. And you can see his rating. You like it, you ride it.
As soon as you get to your destination, all is done. No need to pay, because you're already set up to pay by credit card. And you're asked to rate the driver and maybe put some explanation on why you rate him the way you rated him.
Basically this is exactly how we develop or should web-services. I'm sure I don't have to explain this uncanny analogy. But I will, while I'm at it. Why stop?
When we develop web-services, we know where we are and where we want to go next. Actually, it's so much like traveling by any means other than driving yourself. We always need to know where we want to go. It is the first thing you do when you take a bus, a train or a taxi. You decide where you want to end up. Since it's pointless to just start driving, moving around and around and only stop when you've reached you're destination. Fun when you're backpacking, but very inefficient when you're not.
So basically, when we develop web-services, we start within finishing as we start with defining what we want. These are the requirements. Mind that the more specific the requirement, the more likely we get what we need. So next we check what it's going to cost to get there. Determining the cost of creating the service will allow us to decide whether it's worth it. We already know how to pay for it, typically it's in terms of time. Then, if all checks out, we request an implementation. There's a lot of different ways to develop a service and we have to decide whether we go for a quick online solution, a more solid standard product, or a custom made solution. It's basically all about the rating of the driver, nothing more. Then we develop. Once we get to our acceptance testing we verify whether the destination is exactly where we wanted to be in the first place. The more stars the closer to what we wanted.
So let's put a little agility in to the mix. The Uber driver is using a navigation tool on his phone to determine where he needs to go and when he strays from the route, the navigation tool will make sure to get him back on track. But the awesome part here is that the navigation is turn by turn, in other words, only at specific points on the route, it will provide input on how to adjust the course. This is what we do as well during the development of products. We have defined points in time to determine whether or not we are on the right track. And just as the customer can tell the Uber driver that she wants to go somewhere else, we can adjust our destination as well. Mind that the customer of the Uber driver can't tell him verbally, but instead has to provide a new destination in the Uber app. Reason for this, is that both the customer and the driver know exactly what the new destination is by using the exact same terminology. And the Uber driver is adjusting his route to get her there. In effect, the customer will tell the driver under what circumstances she's happy to accept the end of the ride, i.e. she's driven to her (adjusted) destination. We do the same, we change our to be developed product, by redefining the requirement and accept the product when the adjusted requirements are met.
Now folding the Uber analogy and the Agile software delivery into a single, stronger, strain of software engineering DNA, we have to look into some additional little tidbits.
For one, to get software delivery in an agile way really to work, you need to make sure that you deliver the features in a way that they are useful, which means that it is best not to focus on functionality but on behavior. This allows everybody to consider the software developed to be regarded as an actor in the business of the company. The difference is that you not only have the basic functionality of the Uber driver to get you at your destination, but you can also define how to get you there by means of non-functionals. So how fast to get you there, whether or not to stay on the highways as much as possible, etc. When describing behavior, the non-functionals are an integral part of the behavior instead of yet another set of requirements, typically those that are left out when discussing the system and only brought in at the end, right after we find out the system is not performing.
Just like we have, often untold, additional requirements for our driver that are typically related to his behavior, we have these as well for our services. And just like we first verify the by Uber proposed driver and cancel the trip when we don't want that driver, we need to do the same with our services. There are always many ways to solve the business service puzzle, but most will be rejected because they don't expose the right behavior.