The good old terminal
Before we get in to the cool stuff, it's important to gain some perspective on the problem we're trying to solve. It is, in fact, a real problem dating back to the early days of computers.
Back in the 1970s, in the early days of computers, it was quite common to see terminals in offices much like the one shown in the following image:
The nature of these terminals was to be as dumb as possible. They didn't do any computation, nor did they hold any state. The terminal only reflected what the server wanted the terminal to show on screen, so in many ways they were just really fancy television sets. Any input from the user's keyboard was sent to the server, and the server interpreted the user input, updated the users' terminal session, and sent the screen update back to the terminal, as shown in the following diagram:
This model proved very helpful; technically, we, as developers, had everything on our server and didn't have to think about any rich clients holding stakes and making it all the more complex. We only needed to scale the server, and potentially deal with multiple servers and keep them in sync, or work against a centralized data source. However, it didn't prove useful for a good user experience. The terminals were limited to text only, and the types of user interface one could create were limited, often ending up being very data-centric and keyboard-friendly.