Thursday, October 13, 2011

All web applications are stateful

I recently read some blog posts (1 and 2) about web application development and the evolution from thin clients to fat clients, from server-centric to client-centric dynamic applications.

Traditionally web clients have been dummy and known basically nothing. Now the demands are the opposite. Servers are stateless or dummy and clients contain all state and logic. Everything should be "web scale". Systems should be able to handle millions of requests per second. Well, of course not everyone is building Facebook or Twitter, but that is the trend.

In my mind all this winds up to one big challenge: where is the state of functionality handled? Is it on server, on the client, or on both? There exists a number of frameworks with different state abstractions from "share nothing" stateless frameworks (e.g. Play) to stateful frameworks (e.g. Context and Lift). They all approach this dilemma in different ways.

So, I decided to make some comments on the matter. Basically, I'm trying to remind that even if application is built with "share nothing" mindset, it does not mean that state does not exist. It is still everywhere and it requires a lot of thought.

I should note that this post contains a lot of questions without answers. I'd be happy to hear your thoughts.

Where is the state of data?

Web applications are not built for nothing. They are most likely modifying data in different ways. It is also likely that the data is shared amongst multiple users. This creates state; the shared state of data.

In my understanding, the basic idea with stateless client-centric approaches is that client basically fetches all the data that is needed for functions and it is manipulated locally. Then at specific points the local data is synchronized with the server and exposed to others. Now, my concerns are:

  1. How much information must be fetched from the server? If database contains millions of records, does the client need all of them or just some subset? How does the client know what is the correct subset?
  2. If the client has only a subset of information in use, how does it know how the "unknown" part of the data affects it?
  3. How does the client know when something changes? It is obvious that client's own changes are easy to synchronize, but how about changes made by others?
  4. How is the changeset fetched? How does the client know what changes to fetch instead of downloading everything just in case?

In more traditional approaches the client has a web page that contains the relevant data given from server and nothing more. Then, when some actions are made a form or similar is submitted. Server handles it and new page with brand new state is returned. Also if there are conflicts during form submit it is the responsibility of the server to do something with it. In any case the state is cleaned and a new page is shown.

But if server is only providing data, collections of objects, how does the client keep track on everything? And if something nasty would happen, how does the client know about it? And what do you do if that is the case? How do you clean the state in the client? Reload perhaps...

Where is the state of business logic?

I believe that one driving force to fat clients is that business logic could be done on clients and it would reduce the amount of needed processing power on server. I may understand this incorrectly, but if such scenario is assumed, doesn't it lead to logic duplication?

The point is that client cannot be trusted and it does not know everything. For instance, it is a basic understanding that data validation made on client must be revalidated on server. It is just too easy to bypass all client validations. So, it quickly leads in a situation that logical decisions should also be revalidated on server.

Also the shared application state among different clients is a challenge. Let's say that the application would be some kind of calendar based reservation system for hairdressers. It allows clients to choose a hairdresser and then create, remove or rearrange reservations online. So, if the client has all the power on manipulating reservations, how is it restricted and controlled?

Server should probably validate the manipulation so that no duplicate reservations can happen and that client cannot forge reservations in some odd manner. Maybe in some case the client cannot find times for the hairdresser she would like to have. So she simply reserves time to someone but forges the hairdresser id. With luck, she might just bypass something and the existing reservation is replaced with new one on the server.

So, basically I have a feeling that with fat clients, developers end up writing a lot of duplicate validation on server. And not only field validation, but also logic validation.

Signaling exceptional states

This topic does not concern only stateless applications, but is a comment about one general issue. If something goes awry, how do you tell it to the client?

This dilemma is universal because almost every request/response-case is built in a same way. Client creates a request and sends parameters with it. Server takes the request and calculates response and returns it. If something goes wrong, exceptions are thrown and logs are filled with stack traces.

So, how is exceptional state returned to client? In my understanding restful approaches normally use HTTP 4xx codes for it. But how do you tell what went wrong and what to do about it?

Signaling multiple state changes

Signaling multiple states changes is also a big issue and is in close relation with exceptional states. How must a request/response be formulated so that it can give different kind of answers?

The thing is that normally the client is expecting to have a certain type of response and nothing else. This is especially challenging in Javascript, because if the return value is JSON, client cannot automatically tell what entity it represents. It must be assumed.

This issue arises especially from the user interface. The more dynamic application is the more it will have multiple sections on the page that may update themselves independently. To support all the changes, multiple type of information is needed.

This issue may sound distant with traditional MVC-based approaches, where it is expected to have one answer to one request. But as soon as you start doing something with component based frameworks, the issue quickly becomes closer. The mindset changes and you start thinking: "Couldn't I just change also that thing?".

So, how is it done? Can one request return multiple responses, or does the client need to make multiple requests? How does the client know what requests to make and how to interpret the responses?

To session or not to session?

The extreme part of stateless approaches are saying that no sessions should ever be used. Session affinity is a bad thing and prevents scalability.

If server based sessions are not used, it automatically creates an obvious question: How does one handle user authentication? How does the server know if the client is allowed to access certain parts of the system?

One solution is just to use cookies that hold user id or similar. But can client tamper that information somehow? When that question arises, it is quickly obvious that the cookie must somehow be encrypted or signed so that only the server knows how to use it.

Now, if server does not keep any record of the cookie's state how do one expire the restricted access? How do you logout? The point is that if server does not keep any state, even with expiration time for the cookie, client can always recreate it and keep logged in forever.

Well, the answer is probably some kind of encrypted and time stamped cookie that is renewed at server whenever it is accessed. And during logout cookie is simply expired at server.

But still, how does one force expiration? The session can always be discarded by the server, but how do you discard the knowledge of the cookie's content in the client? If the client just keeps recreating the last known working cookie, how does the server know that is not valid anymore?

So, what might happen is that developers end up writing some custom database based solution that keeps track of accepted cookies or user's expected state; the state of the session.

A real-life case of the state problem

For the last part, I decided to share a real-life puzzle that I encountered recently regarding state.

I'm currently porting my clients codebase to Context and I encountered a situation that actually made me write this post. The system contains a search page for certain items. In a sense it is just basic stuff with search form and paged results etc.

Now the twist is that when the first results of the search are shown it is possible to create a report for the full set of the matching items. The report itself is nothing fancy really, just some statistics and numbers. But the key point is that generating the report takes time.

If there are a lot of matching items it may take over a minute to finish the report. It is CPU-intensive, database-intensive and IO-intensive. It takes time to crawl the database and crunch the numbers. It would also be nice that not every user is able to start generating their reports in parallel. It would just starve the system.

So all this screams for one thing: a background job. Search page should create a job-on-demand and wait for the results to emerge into existence and finally show them. And if there are multiple jobs they are processed serially. But all this creates a new state, the state of the job on the server. It is not the client doing the crunching, it is the server. So, how is it handled?

In Context that problem is relatively simple. All that is needed is to create a proper object to hold the state and progress of the job, give it to thread pool and associate the object to page state. After that it is trivial to poll the server periodically and check how the report is generating. When everything is finished results are shown in client. The job lives in the page state, and when the web page is closed, the job is also ready for garbage collection.

But how about stateless application? How are following questions solved?

  1. Where does the job live? Where is it kept?
  2. How is the job accessed? How does the client know what is the correct job?
  3. How is the progress of the job tracked? Is it possible to tell user that for instance 40% of the job is done at certain moment of time?
  4. How is it prevented that one user cannot see other users jobs?
  5. How do we know when the results of the job have been consumed and can be discarded on server?

Also, if you are having clustered application more questions must be tackled:

  1. Which server is doing the crunching?
  2. How is the background job invoked?
  3. How is the data accessed if every request goes to random server?

I have no answers to these questions. There may be a number of solutions, but I have a feeling that it requires some kind of external server and that the data must be saved temporarily to the database.

Well, that's about it. I hope that these thoughts are helpful on your journey on web application development whatever programming language or framework you are using.

2 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. Great Post Sharing Thanks

    For More Information You Can Visit This Website Web Application Development Solutions

    ReplyDelete