Posts Tagged ‘FSM’

Idempotence In System Architecture

Friday, October 3rd, 2008

A useful paradigm that should be consid­ered when a stateful software system is to be designed is idempo­tence. Leaving aside its exact defin­i­tion in mathe­matics and computer science, idempo­tence can be roughly described as a system charac­ter­istic whereby, calling an opera­tion multiple times is equiv­a­lent to doing it exactly once.

For instance, setting the value of a variable X is an idempo­tent opera­tion, because setting its value to be Y several times has the same effect as setting it just once. On the other hand, incre­menting its value is not an idempo­tent method because the result depends on the number of times the opera­tion is called.

Imple­men­ta­tion

Before delving into why you might want to have idempo­tence, let’s have a look at how it can be imple­mented. One way of doing it is like this:

Design a state machine

A state machine identi­fies every unique state that the system can exist in, with a clear indica­tion of which states the system can transi­tion to from any given state, and under what conditions.

Design a minimal API

An appli­ca­tion program­ming inter­face is the gateway for external systems to interact with the service. We start by designing a minimal API, identi­fying all the methods that could change the state of the system. It is best not to clutter the API with non-critical methods at this stage.

Expressed differ­ently, an API method repre­sents a single transi­tion in the state diagram. For example, a system could have states such as Ready­ToP­ur­chase and TaxAdded. The addTax() method, if successful, provides the transi­tion from the first state to the second. This method can never be applied a second time, because by then the system has already moved on to the next state.

An impor­tant restric­tion on the API is that if the state has some attrib­utes, they must be maintained metic­u­lously and checked against incoming requests. Suppose the addTax() method takes a parameter called amount. If the method is called again with the same amount, then the expected response is success, since the system is indeed in a state that the function call was supposed to move it to. However, if amount is different, then the response should be a failure, or at least some kind of partial failure — other­wise, the client will assume that the new tax amount had been added. A state should never change its internal attrib­utes once they have been set.

Transi­tions should be atomic

It goes without saying that transi­tions need to be atomic, so that multiple requests do not corrupt the state while the system is transi­tioning. This can be achieved easily by acquiring a lock on a mutex at the start of a transi­tion, and releasing it on completion.

Why Idempo­tence?

Naturally, it is a good idea to ask why we are putting in so much effort. While this may seem inordi­nately complex at first, you will soon discover that such a design actually simpli­fies the system tremen­dously when there is a great deal of concur­rency. When there are a large number of processes or threads commu­ni­cating with each other and the number of messages exchanged is huge, idempo­tence provides a guarantee of sorts about what the system can or cannot do. The state machine approach allows you to simply worry about the system in its current state, rather than the system as a whole. As a debug­ging technique, the devel­oper simply needs to say, “This was the previous state A, and now it has moved into this new state B — what combi­na­tion of parame­ters caused such a transi­tion?” Idempo­tence makes this approach even more robust, ensuring that the system works in the face of message dupli­ca­tion and errors.

This robust­ness also allows the design to sacri­fice a reliable commu­ni­ca­tion layer in exchange for speed. For example, TCP (which has a larger overhead) can be replaced with UDP, since the appli­ca­tion is resilient to message loss and duplication.