Posts Tagged ‘coupling’
The human web and christmas gifts
You have been buying books at amazon.com for 5 years now: typing http://www.amazon.com in your browser, searching for your book, adding it to the cart and entering your credit card information.
But this year, on December 15th 2009 something new happens. Amazon has launched an entire new “christmas discount program” and in their front page there is a huge ad notifying their clients about this new item.
How do you react?
“Contract violated! I am not buying anything today.”
The key issue in loosely coupled systems is the ability to evolve one side without implying in any modifications on the other part.
As some Rest guys agree, hypermedia content was the factor which allowed such situations to happen in the human web without clients screaming “i don’t know what to do now that there is a black friday clearance!” or “there is a new link in this page, let me email the ‘webmaster’ and complain about it“.
In the human web, some contracts are agreed upon and validated through end-to-end tests. Some companies will use tools as selenium-rc, webdriver or cucumber to drive their tests and ensure that expected behaviour by their clients does not break with a new release of their software.
Those tests do not validate all content, though, giving space for what is called forward-compatibility: the system is free to create new functionalities without breaking previous expected behaviour.
But my rest-client is not human
In the non-human web, the most well known media type used is xml, although not hypermedia-capable. There are a couple of ways to create forward or backward-compatible schemas that check xml structures, but – unfortunately – usually
fixed schemas will not invest part of its contract in order to making it forward-compatible: its an optional feature.
One option is to create “polymorphic” types through xsd schemas, which will get nasty if your system evolves continuously – not once every year – and you find yourself in a schema-hell situation.
One easy solution is to accept anything in too many places, which seems odd.
What are we missing then? According to Subbu Allamaraju, in RESTful applications, “only a part of the contract can be described statically, and the rest is dynamic and contextual”: you tell your client that they can believe you will not break the statically contract – you might use some schema validation to do that – and it’s up to you on the server side to not do it on the dynamic part.
Some might think it sounds too loose… let’s recall the human web again:
- xhtml allows you to validate your system’s fixed contract
- it’s up to you not to remove an important form used throughout the buying process
So, what are the dynamic parts of my “contract”?
In a RESTful application the contract depends on its context, which is highly affected by three distinct components:
1. your resource’s state
If a person had his application denied to open an account, your resource representation will not offer a “create_loan” request. A denied application is an information regarding its state.
While your company and application evolves, its common to find ourselves in a position where new states appear.
2. your resource’s relations
In a book store (i.e. amazon a few years ago), a book might have a category associated with it so you can access other similar books:
<book> <name>Rest if you do not want to get tired</name> <link rel="category" href="http://www.caelumobjects.com/categories/self-help" /> </book>A couple years later, your system might add extra relations, as "clients which bought this book also recommend"
<book> <name>Rest if you do not want to get tired</name> <link rel="category" href="http://www.caelumobjects.com/categories/self-help" /> <link rel="recommendation" href="http://www.caelumobjects.com/books/take-a-shower-with-a-good-soap-if-you-need-to-rest" /> </book>
When your company and application evolves, its common to find ourselves in a position where new relations appear.
3. your resource’s operations
In a REST application, your resource operation’s are represented by HTTP verbs: supporting a new one will not affect clients which use all other available verbs so far.
In the RPC/Webservices world, new operations would be implemented creating new remote procedures or services.
But how can my clients be sure that I will not break the dynamic contract?
Pretty much in the same way that you do in the human web: it’s your word.
In the human web, how do we guarantee that we will not remove or break some functionality the user expects to be there? We end-to-end automatically test its behaviour.
Our word (our tests) is the only reason to rest without worries that we will not break our client’s expectations. The same holds on the non-human web.
The dynamic contract should be throughly tested in order to not break our client’s expectations.
There are other approaches (as client-aware contracts) which might add some extra coupling between both sides.
HTTP+XML+ATOM gives us the possibility to work with both the fixed (schema validated) and dynamic (test validated) contract.
That’s the good points of using schemas, but its not everyone that use them in a flexible and backward compatible way. Even those who use might have a little bit of hard time to support it, i.e. having to maintain more than one entry point for each version of their schemas.
That’s when we can use the good points of the schema validation, as Bill pointed out, with the easy evolution advantages of a dynamic contract: as we do in the human web.
By using dynamic contracts as xml+atom following the Must Ignore rules, forward and backward compatibility is gained by default, independent on what the user does – assuming that tests are a must in any solution.
Dynamic contracts also give hints for frameworks, as they guide you on what your user can and can not do or access, but maybe not for tools, in a different fashion of what fixed contracts do: with a fixed schema I would be able to pre-generate my classes, while with dynamic schemas I the framework inject methods.
That’s why we try to take an approach which force programmers to adopt xml+atom. The entry point on the Restfulie framework is loosely evolution.
Its first example, the documentation and its examples do not focus on how easy it is to use nice URIs and the 4 most famous http verbs, but how easy it is to evolve your system using hypermedia and http: uri’s come soon afterwards.
And it seems to be working fine to far, the first developers using it in live systems have already supported hypermedia content as a way to guide clients through their systems.
Restfulie support in dynamic contracts
Matt pulver’s extension to Rails allows one to instantiate types with regards to their active record relations and attributes, but it requires every xml element to be present (strong coupling to the data structure presented by the server).
Using Jeokkarak (korean hashis), Restfulie instantiate objects matching your local data structure, supporting fields defined in your attributes and inserting extra fields for those elements unknown to your model.
For example, if you have a model as:
class Bill attr_accessor :value, :to_date end
And the following xml:
<bill> <value>100</value> <to-date>10/10/2010</to-date> <taxes>0.07</taxes> </bill>
The result is a dynamic object capable of answering to:
bill = Bill.from_web uri puts bill.value puts bill.to_date puts bill.taxes
If your model was ready to accept such xml, Restfulie will do the job, whilst if it doesn’t recognize the attribute, it will still be available to you.
That’s the default Restfulie behaviour: to allow the other part to evolve their dynamic contract (and even parts of the fixed one) by default, without any extra effort from your side.