# Tutorial: so you want to write a frontend? If you are here, you may want to develop your first webapp, or perhaps you already are a webapp developer and want to get better at it. In this tutorial we will offer you as much *understanding* as we possibly can. In our experience, the most daunting part about achieving mastery with webapps is understanding how it all fits together, and why things are done in a certain way. This tutorial replaces a more conventional tutorial format that merely shows how to develop webapps with [gotoв](https://github.com/fpereiro/gotob). Instead of this, we first offer **a conceptual introduction** to webapps (*web applications*, in case you're not familiar with the abbreviation). After the main conceptual pieces are in place, we then show the main problems that appear when one implements the frontend of a webapp; gotoв appears on the scene as a possible solution to these problems. The purpose of this tutorial is to give you as much conceptual and practical understanding as possible, so that you can become a better web developer. This tutorial requires only basic knowledge of HTML, JavaScript and programming. If you are just beginning and you want to understand the basic concepts of a webapp, you may find it useful. If you are a more experienced developer that is interested in reconsidering the concepts of the frontend from the ground up, you might be interested in it too. ## Part 1: a conceptual introduction to webapps In the first part of the tutorial, we present a *conceptual* introduction to webapps. Before even seeing a line of code, it can be extremely helpful to understand the basic concepts that explain the why, how and what of webapps. We will cover concepts such as *the virtual world*, *devices*, *application*, *user interface*, *logic*, *server*, *user*, *frontend*, *backend*, *HTML*, *JavaScript* and *framework*. By the end of this part, you should have a high-level understanding of how they all fit together. After all of this makes sense, it will be *far easier* to understand the details of how to implement a frontend. New knowledge can only be created as connections to knowledge you already have; our hope is that by giving you a short, yet rich web of concepts to understand webapps, the implementation details will become easier to understand, connect and remember. ### Chapter 1: an introduction to the digital world Let's start at the beginning. Why do we even care about webapps? How are they meaningful to our lives? We currently live in the [digital age](https://en.wikipedia.org/wiki/Information_Age). As such, our lives happen in two worlds: the *physical world* and the *digital world*. The physical world needs little explanation: it consists of all that was there before the digital age. The digital world, however, is what is new for us as a species. Despite being the newcomer, the digital world is now everywhere - in fact, unless you printed this tutorial on paper, you're right now immersed in the digital world! The digital world came of age in the 1970s, with the development of [microcomputers](https://en.wikipedia.org/wiki/Microcomputer) and the [internet](https://en.wikipedia.org/wiki/Internet). It became massive in the early 1990s, with the development of the [web](https://en.wikipedia.org/wiki/World_Wide_Web), and experienced its tipping point with the development of [smartphones](https://en.wikipedia.org/wiki/Smartphone) in the late 2000s. Cheap, powerful and interconnected computers made the digital age happen. As of the early 2020s, the digital world has become central to our lives. Through the digital world, most of humanity performs now a great deal of four essential activities: - **Storage of information**: the digital world is where most of our externally stored information now lives. (Externally stored means information stored outside of our own brains). Our external memories are by now overwhelmingly digital. - **Economic production**: work of all kinds happens now either exclusively through the digital world or is at least partially controlled or informed by it. - **Creation**: art and science are increasingly created and distributed through the digital world. - **Social interaction**: human interactions at all levels (person to person, small groups, large groups, national and international communities) are increasingly shaped by interactions happening in the digital world. In short, the digital world touches almost every aspect of our existence, both individual and social. Gaining understanding of it empowers you to: - Judge better: by understanding the digital world, you can make informed decisions (personal and political) concerning it. - Shape it directly: it is possible for anyone to build apps that can make a contribution to the digital world. By building an app, you might positively impact the lives of others. In the next chapter, we will understand what the virtual world is made of. ### Chapter 2: an overview of the digital world We exist in a physical world. The digital world exists within the physical world, but we cannot access it directly. To access the digital world, we *use digital devices*. ``` ┌──╌ Physical world ╌───────────────────────────────────────────┐ │ │ │ ┌──╌ Human ╌───┐ ┌──╌ Digital world ╌───┐ │ │ │ │ │ │ │ │ │ <──────│────╌ Digital ╌────┼───────────> │ │ │ │ │ devices │ │ │ │ └──────────────┘ └──────────────────────┘ │ └───────────────────────────────────────────────────────────────┘ ``` The digital world consists of three elements: - **Digital devices**, such as computers, tablets and phones. - **Applications**, which are programs that run on digital devices. - **A network** that interconnects all digital devices. ``` ┌──╌ Digital world ╌─────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌──╌ Device (hardware) ╌──────────┐ ┌──╌ Device (hardware) ╌──────────┐ │ │ │ │ │ │ │ │ │ ┌─╌ Application (software) ╌─┐ │ │ ┌─╌ Application (software) ╌─┐ │ │ │ │ │ <────────────────────│─┼──╌ Internet ╌────┼──┼─────────> │ │ │ │ │ └────────────────────────────┘ │ (network) │ └────────────────────────────┘ │ │ │ └─────────────────────────────────┘ └─────────────────────────────────┘ │ └────────────────────────────────────────────────────────────────────────────────────────────┘ ``` What each element stands for? Digital devices are **hardware** and represent the immediate bridge between the physical and the digital world. Applications are **software** and through it the devices can do unlimited things. Finally, the network enables **connectivity** between devices (and applications) existing in different parts of the physical world. While the devices and the network are essential to the digital world, as users our attention is focused on the applications. Right now, you're looking at words on a screen (unless you printed this tutorial on paper, you crazy person); it is almost certain that you are paying much more attention to the text and what surrounds it than to your actual screen or keyboard, or to the fact that you're connected to the internet. Applications are our true windows to the digital world. They act as our digital eyes, hands and ears. Applications don't run directly on the device. Rather, they run on a piece of software called the *operative system* (OS, for short), which in turns runs on the device. While the OS is software, from the perspective of an application developer, it could be considered as hardware: the OS is taken "as is" and cannot be easily (or at all) modified. So, for practical purposes, the device and its OS are a bundle on which applications run. ``` ┌──╌ Digital world ╌─────────────────────────────────────────┐ │ │ │ ┌──╌ Device ╌────────┐ ┌──╌ Device ╌───────┐ │ │ │ │ │ │ │ │ │ ┌──╌ OS ╌───────┐ │ │ ┌──╌ OS ╌──────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌─╌ App ╌─┐ │ │ │ │ ┌─╌ App ╌─┐ │ │ │ │ │ │ │ <────┼──┼─┼──╌ Internet ╌─┼──┼──┼────> │ │ │ │ │ │ │ └─────────┘ │ │ (network) │ │ └─────────┘ │ │ │ │ │ └───────────────┘ │ │ └──────────────┘ │ │ │ └────────────────────┘ └───────────────────┘ │ │ │ └────────────────────────────────────────────────────────────┘ ``` But for practical purposes, just think of it as: ``` ┌──╌ Digital world ╌─────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌──╌ Device + OS ╌───────────────┐ ┌──╌ Device + OS ╌───────────────┐ │ │ │ │ │ │ │ │ │ ┌─╌ Application (software) ╌─┐ │ │ ┌─╌ Application (software) ╌─┐ │ │ │ │ │ <────────────────────│─┼──╌ Internet ╌────┼──┼─────────> │ │ │ │ │ └────────────────────────────┘ │ (network) │ └────────────────────────────┘ │ │ │ └─────────────────────────────────┘ └─────────────────────────────────┘ │ └────────────────────────────────────────────────────────────────────────────────────────────┘ ``` Before we close this chapter, we need to cover the relationship between the application and the network. The network connects an application running on a certain device with another (or the same) application running on *another* device. Connectivity is what joins distinct devices into a connected whole - rather than having small digital islands (each device), by connecting them we create an entire digital world. Devices not only communicate one-on-one, but can also communicate with multiple devices at the same time. ``` ┌──╌ Digital world ╌───────────────────────────────────┐ │ │ │ ┌──╌ Phone 1 ╌─┐ ┌──╌ Phone 2 ╌─┐ │ │ │ │ │ │ │ │ │ ┌─╌ App ╌─┐ │ │ ┌─╌ App ╌─┐ │ │ │ │ │ <──────│─┼──────╮ ╭────────┼──┼───> │ │ │ │ │ └─────────┘ │ │ │ │ └─────────┘ │ │ │ └──────────────┘ ╎ ╎ └──────────────┘ │ │ │ │ Internet │ │ (network) │ │ │ │ ┌─╌ Computer ╌─┐ ╎ ╎ ┌──╌ Server ╌─┐ │ │ │ │ │ │ │ │ │ │ │ ┌─╌ App ╌─┐ │ │ │ │ ┌─╌ App ╌─┐ │ │ │ │ │ <──────│─┼──────╯ ╰────────┼──┼───> │ │ │ │ │ └─────────┘ │ │ └─────────┘ │ │ │ └──────────────┘ └──────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ ``` This completes our introduction to the digital world. We will now shift our focus to applications. ### Chapter 3: introduction to applications As we saw in the previous chapter, applications are central to us because they act as the true windows to the digital world. But what *is* an application? It's perhaps best to start with a concrete example on which to illustrate the concepts of this chapter. For this purpose, let's pick a typical stopwatch app, like the one that comes built-in in your phone. ``` ┌──╌ Stopwatch app ╌─────────────────────────────┐ │ │ │ │ │ 00:00:00 │ │ │ │ ┌─────────┐ │ │ │ START │ │ │ └─────────┘ │ │ │ └────────────────────────────────────────────────┘ ``` An application is a program made of three parts: - **User interface (UI)**: this is what the user *sees*. In the stopwatch app, the UI would consist of the clock and the `START` button. - **Logic**: this is what determines *what* the app can do and *when* it can do it. In the stopwatch app, the logic determines that you can start the clock if it's stopped or paused, but not if it's already going. - **State**: this is what determines the *current situation* of the app. In the stopwatch app, the state consists of the time currently shown on the clock, as well as whether the stopwatch is stopped, running or paused. We venture to say that if a program has all three things (UI, logic and state) it is an application. All programs have logic, but not all of them have UI and state. ``` ┌──╌ UI ╌──────────┐ ┌──╌ Logic ╌───────┐ ┌──╌ State ╌───────────────────┐ │ │ │ │ │ │ │ - Clock display │ │ - Available │ │ - Time shown │ │ - Buttons │ │ operations │ │ - Status of clock │ │ │ │ - Move clock │ │ (running, paused, stopped) │ │ │ │ forward │ │ │ └──────────────────┘ │ │ └──────────────────────────────┘ | └──────────────────┘ | | | | | | | | | | v v v ┌──╌ Stopwatch app ╌─────────────────────────────┐ │ │ │ │ │ 00:00:00 │ │ │ │ ┌─────────┐ │ │ │ START │ │ │ └─────────┘ │ │ │ └────────────────────────────────────────────────┘ ``` The *UI* performs two functions: - Allows the user to **see** information: how much time has elapsed? Is the stopwatch running or not? What are the available operations? - Allows the user to **interact** with the app: start, pause and stop the stopwatch. In that way, the user can change the information of the app (that is, to change the state of the app). The *logic* determines the UI and what is possible to do with it: - When the stopwatch is stopped, the logic only allows you to start the stopwatch. - When the stopwatch is going, the logic only allows you to either pause it or reset it. The logic also determines the time displayed in the clock: - When you click on the button for stopping the stopwatch, the logic resets the clock. - When the stopwatch is going, the logic constantly updates the clock. - When the stopwatch is paused, the logic keeps the clock unchanged. The *state* is what tells you *where the app is at*. For example, in the stopwatch app, the state is made of the following: - Current time: *00:00:00* or more. - Current mode of the clock: *stopped*, *paused* or *playing*. The state of the app determines both how the UI looks and what operations the logic will perform. We would not go too far if we consider that an application is considered to be a *mathematical function of its state* (if you are wary of mathematics, please don't skip this section, we'll make it as clear as we can!). Think of a mathematical function as a little box which, when receiving an input, immediately produces an output. You don't necessarily care what is inside the box. What is most important is that, when you give a certain input X to the function, it produces a result Y. A function can be then understood as a process that transforms an input X into a result Y. ``` function (x) -> y ``` Notice that the input to the function is shown above between parentheses (`(` and `)`). The result obtained from passing `x` as input to the function goes after the arrow `->`. Let's take the example of the square-by-two function: ``` square-by-two (1) -> 1 (because 1 * 1 is 1) square-by-two (2) -> 4 (because 2 * 2 is 4) square-by-two (3) -> 9 (because 3 * 3 is 9) ``` The same happens with the stopwatch: ``` stopwatch (clock is at 00:00:00 and clock is stopped) | | v ┌──╌ Stopwatch app ╌─────────────────────────────┐ │ │ │ │ │ 00:00:00 │ │ │ │ ┌─────────┐ │ │ │ START │ │ │ └─────────┘ │ │ │ └────────────────────────────────────────────────┘ stopwatch (clock is at 02:00:00 and clock is running) | | v ┌──╌ Stopwatch app ╌─────────────────────────────┐ │ │ │ │ │ 02:00:00 │ │ │ │ ┌─────────┐ ┌────────┐ │ │ │ PAUSE │ │ STOP │ │ │ └─────────┘ └────────┘ │ │ │ └────────────────────────────────────────────────┘ stopwatch (clock is at 02:00:00 and clock is paused) | | v ┌──╌ Stopwatch app ╌─────────────────────────────┐ │ │ │ │ │ 02:00:00 │ │ │ │ ┌─────────┐ ┌────────┐ │ │ │ START │ │ STOP │ │ │ └─────────┘ └────────┘ │ │ │ └────────────────────────────────────────────────┘ ``` In the examples above, we consider `stopwatch` to be a function. The input we pass to the function is the *state*. What's then the result? The UI! ``` app (state) -> UI ``` The *state* determines how the app looks at any given moment. If the app changes, it is because the state was changed. Two things can change the state: - A user interaction. For example, the user clicking on a button. - A logic operation. For example, the clock moving one second forward. As we mentioned before, when the state changes, the UI changes. So the UI changes both in response to user interactions and logic operations. After the UI changes, both the user and the logic may have new operations available. In this way, an app constantly changes. You could call it the *fundamental cycle of an application*: ``` ┌───────────┐ ┌────────────┐ ┌─────────────┐ ┌───────────┐ ┌────────────┐ │ Initial │ │ Initial │ │ Change to │ │ New │ │ New │ │ state │---> │ UI │---> │ the state │---> │ state │---> │ UI │ │ │ │ │ │ │ │ │ │ │ └───────────┘ └────────────┘ └─────────────┘ └───────────┘ └────────────┘ ``` We've covered lots of ground in this chapter. The main takeaways are: - An app is made of 1) UI, 2) logic, 3) state. - The state determines the UI. - Both the user and the logic can change the state. In the next chapter we will cover three more fundamental concepts: *data*, *servers* and *user accounts*. ### Chapter 4: data, servers and user accounts In this chapter we will review three concepts that will put you "on the other side" of this tutorial. If you understand these three pieces of the puzzle, it's a fair bet to say you'll be able to grasp the rest of the concepts in this tutorial quite easily. The concepts are three: *data*, *servers* and *user accounts*. From the perspective of applications, each of them creates the need for the following one. For example, without data, servers are not really necessary. Without servers, user accounts are mostly useless. But indeed, data is the lifeblood of the digital world. As a result, data, servers and user accounts are fundamental concepts to be understood. So here we go! To follow along, we will change our example from the stopwatch app to a simple todo list app: ``` ┌──╌ Todo list app ╌────────────────┐ │ │ │ ┌─────────┐ │ │ │ | │<-- input box │ │ └─────────┘ │ │ ┌───────────────┐ │ │ │ CREATE TODO │ │ │ └───────────────┘ │ │ │ │ LIST OF TODOS: │ │ │ │ │ │ │ └───────────────────────────────────┘ ``` The todo list app has: 1. An input box, where you can write a todo item. 2. A button for saving the todo item in the list. 3. The actual list of todos. If we add a couple of todos, the app will look like this: ``` ┌──╌ Todo list app ╌────────────────┐ │ │ │ ┌─────────┐ │ │ │ | │ │ │ └─────────┘ │ │ ┌───────────────┐ │ │ │ CREATE TODO │ │ │ └───────────────┘ │ │ │ │ LIST OF TODOS: │ │ ┌────────┐ │ │ - Write tutorial │ DELETE │ │ │ └────────┘ │ │ │ │ ┌────────┐ │ │ - Bake birthday │ DELETE │ │ │ cake └────────┘ │ │ │ │ │ └───────────────────────────────────┘ ``` When you finish a todo, you can simply delete it, so that your list will only contain things that you haven't done yet. The app is quite rudimentary, but it is enough to illustrate all the elements we need to understand in this chapter. Let's start with **data**. Data is information that is meant to *persist*. In the stopwatch example, you probably would not be surprised if the time on the clock was resetted if you either close the app or restart your phone. With the todo list, however, you probably expect the app to *remember* your list of todos - otherwise, why bother writing them down? The data is, then, information that the app must remember indefinitely. Data is the *permanent part* of the *state*. As we defined it on the last chapter, the *state* is what tells you *where the app is at*. The data, then is that information that determines where the app is at *and* persists over time. ``` ┌──╌ State ╌──────────────┐ │ │ │ - Non-persistent info │ │ │ │ ┌──╌ Data ╌─────────┐ │ │ │ │ │ │ │ - Persistent info │ │ │ │ │ │ │ └───────────────────┘ │ │ │ └─────────────────────────┘ ``` Some parts of the state are not permanent and therefore are not data. Let's see an example: ``` ┌──╌ Todo list app ╌────────────────┐ │ │ │ ┌─────────┐ │ │ │ buy a t │ │ │ └─────────┘ │ │ ┌───────────────┐ │ │ │ CREATE TODO │ │ │ └───────────────┘ │ │ │ │ LIST OF TODOS: │ │ ┌────────┐ │ │ - Write tutorial │ DELETE │ │ │ └────────┘ │ │ │ │ ┌────────┐ │ │ - Bake birthday │ DELETE │ │ │ cake └────────┘ │ │ │ │ │ └───────────────────────────────────┘ ``` Notice that we entered `buy a t` in the input box of the app. If, however, we close the app (or restart our phone/computer) before hitting the `CREATE TODO` button, that half-formed todo item will disappear when we open the app again. Before we closed the app, `buy a t` was part of the state, but not part of the data. ``` ┌──╌ Todo list app ╌──────────────┐ │ │ │ ┌──╌ State ╌───────────────┐ │ │ │ │ │ │ │ - Half-entered todo │ │ │ │ │ │ │ │ ┌─╌ Data ╌─────┐ │ │ │ │ │ │ │ │ │ │ │ - Todo list │ │ │ │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ └───────────────────────────┘ │ └─────────────────────────────────┘ ``` Now, where is the data stored? Since the app needs to "remember" the data, it must write the data somewhere, so that then it can read it back up when necessary. The most natural place to store data is *inside the device itself*. All phones, tablets and computers have [storage media](https://en.wikipedia.org/wiki/Computer_data_storage) from which apps can read and write data. Storing the data in your device, however, has two problems: - If you lose or damage the device, your data is lost. To remediate this, you would have to do periodic backups of your data. - Your data is tied to one device. To remediate this, you would have to carry around an updated copy of your data in a portable storage device. Granted, for a simple todo list, you might not care if you lose the data - you might be much more aggravated by the fact that you lost your phone! And you might not be interested in using the todo list app from other devices like your computer. But for many other applications, you do care about not losing your data, and you care about accessing your data from different devices. Servers are the solution to this problem. But what is a server? A server is a device (more specifically, a computer), that is constantly on and connected to the internet. In other words, it is a a computer that is always on and always connected. Unless it is undergoing temporary maintenance, and assuming it didn't malfunction, a server will always be ready to operate. An application can store its data on a server. Going back to our todo list example, whenever you add or remove an item from the list, the app can send the entire todo list to the server instructing it to keep a copy of the list. When the app is restarted, the app can ask the server for a copy of the list. ``` App storing data on the server (saving data): ┌──╌ App ╌─────────┐ ┌──╌ Server ╌─────────────┐ │ ─────┼──╌ todo list ╌────┼─────> │ └──────────────────┘ └─────────────────────────┘ App retrieving data from the server (loading data): ┌──╌ App ╌─────────┐ ┌──╌ Server ╌─────────────┐ │ <─────┼──╌ todo list ╌────┼───── │ └──────────────────┘ └─────────────────────────┘ ``` Going back to the todo list app, imagine that we now have a server that is able to store the todo lists for each of the app users. Now, the data is no longer tied to the device: - If you lose your device, there's a copy of your todo list still on the server. ``` ┌──╌ New device╌───┐ ┌──╌ Server ╌─────────────┐ │ <─────┼──╌ todo list ╌────┼───── │ └──────────────────┘ └─────────────────────────┘ ``` - If you use the app from more than one device, each device can have the last version of the list by synchronizing the list with the server. ``` For example, you first update the list from your phone. ┌──╌ Phone ╌───────┐ ┌──╌ Server ╌─────────────┐ │ ─────┼──╌ todo list ╌────┼─────> │ └──────────────────┘ └─────────────────────────┘ Then, you open the list in your computer. ┌──╌ Computer ╌────┐ ┌──╌ Server ╌─────────────┐ │ <─────┼──╌ todo list ╌────┼───── │ └──────────────────┘ └─────────────────────────┘ ``` Developing and maintaining a server is not easy, but it massively increases the value of an application for users, even only for the fact that they persist data and allow the app to be used from different devices. (Servers actually enable the generation and processing of data that is not directly created by the user, which can also add huge value to an application - we go into that into a small aside section at the end of this chapter). A server is meant to serve multiple users of an app, not just one. Maintaining a server for each user is neither economically feasible not technically necessary. A single server (or a single group of servers) can serve thousands or even millions of users! ``` ┌──╌ Phone 1 ╌─┐ ┌──╌ Phone 2 ╌─┐ │ │ │ │ │ ┌─╌ App ╌─┐ │ │ ┌─╌ App ╌─┐ │ │ │ <──────│─┼──────╮ ╭────────┼──┼───> │ │ │ └─────────┘ │ │ │ │ └─────────┘ │ └──────────────┘ ╎ ╎ └──────────────┘ ┌─────────┐ │ App │ │ Server │ └─────────┘ ┌╌ Computer 1╌─┐ ╎ ╎ ┌─╌ Computer 2╌┐ │ │ │ │ │ │ │ ┌─╌ App ╌─┐ │ │ │ │ ┌─╌ App ╌─┐ │ │ │ <──────│─┼──────╯ ╰────────┼──┼───> │ │ │ └─────────┘ │ │ └─────────┘ │ └──────────────┘ └──────────────┘ ``` Going back to the example of the todo list app, earlier we said that "*we now have a server that is able to store the todo lists for each of the app users*". If the server is to store and retrieve todo lists for each user, *the server needs to have a concept of what a user is*. In other words, when your phone asks the server for the latest version of the todo list, the server must know that it is *your* list and not anyone else's. This brings us to the third and last concept of the chapter: user accounts. An user account is a way in which a server can identify an user. The most basic version of a user account is the combination of an *username* (which identifies the user) and a *password* (which is a secret combination of digits and characters, ideally only known by the user). More sophisticated user accounts involve an email address and possibly other ways of proving identity (see, for example, [multi-factor authentication](https://en.wikipedia.org/wiki/Multi-factor_authentication)). Conceptually, it all boils down to the same thing: a username (or user identifier, such as an email address), plus a secret piece of data. When a device sends both to the server, the server will be able to identify the user that's using the device. ``` ┌╌ Mono's Phone ╌──┐ username = mono ┌──╌ Server ╌─────────────┐ │ ─────┼──╌ password = 1234 ╌────┼─────> │ └──────────────────┘ └─────────────────────────┘ ┌╌ Mono's Phone ╌──┐ success! ┌──╌ Server ╌─────────────┐ │ <─────┼──╌ now I know you ╌────┼───── │ └──────────────────┘ are the user "mono" └─────────────────────────┘ Side note: please don't use 1234 as your password. It is really, really easy to guess. ``` If someone who is not the user `mono` would try to gain access to the server by guessing the password, if they get the password wrong, the server will not recognize this person as `mono`; instead, the server will reply with an error. ``` ┌╌ Shady's Phone ╌─┐ username = mono ┌──╌ Server ╌─────────────┐ │ ─────┼──╌ password = 4321 ╌────┼─────> │ └──────────────────┘ └─────────────────────────┘ ┌╌ Shady's Phone ╌─┐ failure! ┌──╌ Server ╌─────────────┐ │ <─────┼──╌ wrong password ╌────┼───── │ └──────────────────┘ you are not "mono" └─────────────────────────┘ ``` Once a server knows that a certain device is sending requests on behalf of user X, it will allow that device to read and write the data associated with user X. This works not unlike a locker box: each user has its data on a certain section of the server. The server, if properly programmed, will only give access to a certain box to the owner of the box. ``` ┌╌ Mono's Phone ╌──┐ username = mono ┌──╌ Server ╌─────────────┐ │ ─────┼──╌ password = 1234 ╌────┼─────> │ └──────────────────┘ └─────────────────────────┘ ┌╌ Mono's Phone ╌──┐ success! ┌──╌ Server ╌─────────────┐ │ <─────┼──╌ here is the data ╌────┼───── │ └──────────────────┘ belonging to "mono" └─────────────────────────┘ ``` An application server then performs at least two functions: - Store a list of usernames and associated secrets, to be able to identify if a certain device belongs to a user. - Manage data for each user: send it to the device associated with a user when it is requested and update it when the user device sends new data. ``` ┌──╌ Server ╌────────────────┐ │ │ │ ┌╌ User accounts ╌┐ │ │ │ │ │ │ │ - mono / 1234 │ │ │ │ - tom / foo │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ ┌╌ User data ╌┐ │ │ │ │ │ │ │ - mono: ... │ │ │ │ - tom: ... │ │ │ │ │ │ │ └─────────────────┘ │ │ │ └────────────────────────────┘ ``` **Very, very important side note**: *NEVER* store passwords directly on the server. Instead, store a [hash](https://en.wikipedia.org/wiki/Cryptographic_hash_function) of the password. Most people reuse their passwords, so if you store their password (instead of a hash) and someone hacks into your server, that someone can also gain access to other accounts owned by your users. Well, we've come a long way: we went from a simple app (the stopwatch) which stored no data and required no server or user accounts. Then we reviewed an app with data (the first version of the todo list) that didn't require a server or user accounts. Finally, we saw how adding a server and user accounts can greatly enhance the todo list app (and most apps). From now on, we will consider only apps that require data, servers and user accounts. We're now ready to dive into web applications! But before we jump into chapter 5, here's an (optional) aside, which explains other ways in which servers can make an app more useful. ### Aside: servers for data not directly generated by the user If servers only existed to manage the data produced by an user interacting with an app, that would be enough to justify the existence of servers. But it turns out that servers enable the possibility of creating and managing many other types of data that, while not generated by the user herself/himself, can still be consumed by the user. These types of data fall into two categories: - Public (or semi-public) data. Examples: stock market data, weather data, digital media (books/music). - Data generated by other users: Example: one-to-one messages, public comments/posts. Servers thus enable two things: 1) access to public digital data; and 2) digital communication between users. In the case of public information, the data can either be stored on the application server itself; or it can be stored in a different server, which is in communication with the application server. ``` If the stock data is stored directly on the app server: ┌╌ Phone ╌──────┐ ┌──╌ Server ╌────────┐ │ │ │ │ │ ┌─╌ App ╌─┐ │ What is │ ┌─╌ Stock data╌─┐ │ │ │ ─────│──┼───╌ the price ╌─────┼──┼───> │ │ │ └─────────┘ │ of General │ └───────────────┘ │ │ ^ │ Motors' stock? │ | │ │ | │ │ | │ └───────┼───────┘ └───────────┼────────┘ | | ╰─────────────╌ 49.36 USD ╌────────────────╯ If the stock data is stored on a public data server ┌╌ Phone ╌──────┐ ┌─╌ Server ╌┐ ┌──╌ Data Server ╌───┐ │ │ │ │ │ │ │ ┌─╌ App ╌─┐ │ What is │ │ What is │ ┌─╌ Stock data╌─┐ │ │ │ ─────│──┼───╌ the price ╌────┼────> ───│──╌ the price ╌───┼──┼───> │ │ │ └─────────┘ │ of General │ │ of General │ └───────────────┘ │ │ ^ │ Motors' stock? │ ╭────╮ │ Motors' stock? │ | │ │ | │ │ | | │ │ | │ └───────┼───────┘ └───┼────┼──┘ └───────────┼────────┘ | | | | ╰─────────────╌ 49.36 USD ╌───────╯ ╰─────────╌ 49.36 USD ╌─────────────╯ ``` Notice that the `49.36 USD` piece of information wasn't generated by the user, but it still can be very useful to the user. User communication, if it happens within a single app, it can be managed by the server itself. ``` ┌╌ Phone of user A ╌──┐ ┌──╌ Server ╌────────────┐ │ │ │ │ │ ┌─╌ App ╌──────┐ │ Send a │ ┌─╌ Data of user B ╌┐ │ │ │ ──────────│───┼───╌ message ╌────┼──│──────> │ │ │ └──────────────┘ │ to user B │ └───────────────────┘ │ │ │ │ │ │ │ │ │ └─────────────────────┘ └────────────────────────┘ ┌╌ Phone of user B ╌──┐ ┌──╌ Server ╌────────────┐ │ │ │ │ │ ┌─╌ App ╌──────┐ │ Here are │ ┌─╌ Data of user B ╌┐ │ │ │ <─────────│───┼───╌ your new ╌───┼──│────── │ │ │ └──────────────┘ │ messages │ └───────────────────┘ │ │ │ │ │ │ │ │ │ └─────────────────────┘ └────────────────────────┘ ``` For most applications, a large portion of the data associated with an user will either be public data or data originating from other users. These two sources of data are combined with the user's own data (including their preferences on how their data should be displayed) to make the totality of a user's data in the context of an application. ### Aside: servers and control In addition to providing an "always-on" repository of data, servers have another critical quality: control. Unless your server gets compromised, you control the logic executed there. This is a simple way to prevent (for example) that a user would read data that doesn't belong to them. It also allows to enforce consistency of the data, meaning that all the data in your server follows a certain structure. ### Chapter 5: introduction to web applications So far, we have been learning about applications in general. In this chapter, we'll start to go into the specifics of *web* applications. Before web applications, only *native* applications existed. A native application, as we saw in chapter 2, is a program that runs on top of the combination of a device plus its operative system. ``` ┌──╌ Device + OS ╌───────────┐ │ │ │ ┌─╌ Native application ╌─┐ │ │ │ │ │ │ └────────────────────────┘ │ │ │ └─────────────────────────────┘ ``` Most of the applications in your computer and your phone are native applications. They are written to be specifically tailored to your device and operative system. With the advent of the [World Wide Web](https://en.wikipedia.org/wiki/World_Wide_Web) in the early 1990s, a new and interesting native application made its appearance: **[the web browser](https://en.wikipedia.org/wiki/Web_browser)**. Both the World Wide Web (web, for short) and the web browser (browser, for short) were originally meant to display pages with static content (such as text and images). Sometime later (circa 1995), browsers expanded their reach: not only were they useful for displaying static content, but also for conducting online retail. While the browser became massively popular back then, its uses were still limited. Around this time, the two most popular browsers were [Netscape Navigator](https://en.wikipedia.org/wiki/Netscape_Navigator) and [Internet Explorer](https://en.wikipedia.org/wiki/Internet_Explorer). In the early 2000s, gradually and unexpectedly, the browser became an **application platform**. This means that the browser started to be able to run applications inside itself! These applications working inside a browser are called *web applications* (webapps, for short). ``` ┌──╌ User device + OS ╌────┐ │ │ │ ┌──╌ Browser ╌───────┐ │ │ │ │ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ └────────────────────┘ │ │ │ └──────────────────────────┘ ``` At first sight, this looks more complicated than the previous diagram. Before, we only had two things: the combination of device+OS, and the native app itself. But now, we have three things: device+OS, browser and webapp. Why complicate things with webapps if native apps work just fine? Wouldn't this make webapps harder to build, since they have to keep track of more things (user device + OS + browser)? Actually, no: because a browser offers a relatively consistent set of tools with which to implement apps, the apps don't really care on which user device+OS they are running. So, for webapp developers, the graph looks like this: ``` ┌──╌ Browser ╌─────┐ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ │ │ └─────────────┘ │ │ │ └──────────────────┘ ``` This looks like the first graph, only that we have replaced the user device + OS bundle for the browser. However, browsers are quite alike. With some (very annoying) exceptions, what works in a browser will work in another. While this was not very true in the mid-1990s, it is very much true in the early 2020s. So the graph above starts to look like this: ``` ┌──╌ Any browser ╌─┐ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ │ │ └─────────────┘ │ │ │ └──────────────────┘ ``` And because practically all devices now come with at least one browser installed, the graph looks like this: ``` ┌─╌ Any device + any OS ╌──┐ │ │ │ ┌──╌ Any browser ╌───┐ │ │ │ │ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ └────────────────────┘ │ │ │ └──────────────────────────┘ ``` Webapps are the first applications that can run on any device and OS, with the same code, as long as this device + OS has a (decent) browser installed. This allows webapps to run almost anywhere, and with the app code not having to be tailored to a specific combination of device and OS. In a word, webapps are **portable** across devices & OSes. ``` ┌──╌ Android phone ╌──────┐ ┌──╌ Apple phone ╌────────┐ │ │ │ │ │ ┌──╌ Any browser ╌───┐ │ │ ┌──╌ Any browser ╌───┐ │ │ │ │ │ │ │ │ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ │ │ │ │ └────────────────────┘ │ │ └────────────────────┘ │ │ │ │ │ └──────────────────────────┘ └──────────────────────────┘ ┌──╌ Computer + Windows ╌──┐ ┌──╌ Apple tablet ╌────────┐ │ │ │ │ │ ┌──╌ Any browser ╌───┐ │ │ ┌──╌ Any browser ╌───┐ │ │ │ │ │ │ │ │ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ ┌─╌ Webapp ╌──┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ │ │ │ │ └────────────────────┘ │ │ └────────────────────┘ │ │ │ │ │ └──────────────────────────┘ └──────────────────────────┘ ``` Webapps have a second, perhaps greater advantage over native apps: you don't need to install them. All native apps come either pre-installed with the OS, or are installed by the user. For an app creator, this means that if your app is not pre-installed with the device+OS, your users must find it and install it on every device on which they want to use it. With webapps, all a prospective user has to do is to go to click on a link, and the app will automatically load in their browser. **No installation needed!** ``` ┌──╌ Any browser ╌─┐ ┌──╌ Any browser ╌─┐ │ │ │ │ │ │ click on │ ┌─╌ Webapp ╌──┐ │ │ ───────┼───╌ link to ╌───> │ │ │ │ │ │ coolapp.com │ └─────────────┘ │ │ │ │ │ └──────────────────┘ └──────────────────┘ ``` The third advantage of webapps is **the power of the browser as an application platform**. The browser is an extremely powerful native app that can do many things. To name a few: - Transfer data from/to a server. - Play and record audio and video media. - Read and write files to an user's device. - Draw complex animations. Webapps leverage the browser's capabilities to implement complex functionality with relative ease, compared to native apps. While the browser is usually never the best platform for any given use case (except perhaps for showing static content), it *combines* multiple capabilities that are well implemented. The fourth and last advantage of webapps concerns governance. The web is **decentralized and based on open protocols**. In practice, this means that no single company or government controls the web and browsers. This is in sharp contrast with most devices and OS, which are controlled by specific companies. Because the web is decentralized, its survival and evolution is unconstrained and is not wholly dependent on the organization that controls it. This bestows great power to both users and makers of webapps. To sum up: webapps are applications that run inside a browser. They have four advantages over native apps: 1. Portability. 2. No install required. 3. A powerful application platform (the browser) 4. Decentralization and open protocols. In the next chapter we'll start to understand how webapps work. ### Chapter 6: how do webapps work? A webapp is not one program, but rather the combination of two programs: - The **frontend**, a program that runs on a **browser**, which in turn runs in a **user device**. - The **backend**, a program that runs on a **runtime**, which in turn runs in a **server**. ``` ┌──╌ User device ╌─────────┐ ┌──╌ Server ╌──────────────┐ │ │ │ │ │ ┌──╌ Browser ╌───────┐ │ │ ┌──╌ Runtime ╌───────┐ │ │ │ │ │ │ │ │ │ │ │ ┌─╌ Frontend ╌─┐ │ │ │ │ ┌─╌ Backend ╌─┐ │ │ │ │ │ <──────┼──┼──┼────╌ web ╌────┼──┼──┼──────> │ │ │ │ │ └──────────────┘ │ │ │ │ └─────────────┘ │ │ │ └────────────────────┘ │ │ └────────────────────┘ │ └──────────────────────────┘ └──────────────────────────┘ ``` A web development team needs to write both programs to develop a complete webapp. This is true not just of webapps, but of any app which uses servers. Both programs that make the webapp, the frontend and the backend, communicate through the web. The main functions of the frontend are: - Provide a user interface. - Show information to the user. - Collect data provided by the user and send it to the backend. The main functions of the backend are: - Provide information to the frontend. - Validate, collect and store data. The *frontend* doesn't directly run on the *user device*. Rather, as we saw on the last chapter, it runs on a web browser, which is a program that runs on the user device. Likewise, the *backend* doesn't directly run on a *server*. Rather, it runs on a *[runtime](https://en.wikipedia.org/wiki/Runtime_system)*. The runtime is a program that itself runs on the server. Examples of runtimes for backends are [node.js](https://en.wikipedia.org/wiki/Node.js) and [PHP](https://en.wikipedia.org/wiki/PHP). It is a little mind-bending, but it really works that way: both the browser and the runtime are programs that run programs. As we mentioned in the last chapter, the web works through *standards*. Standards are a way of doing things that follow certain rules. If you follow the rules of web standards, you can create a web app that can be part of the broader web, without requiring permission from any organization. Standards are pretty much like a language. To understand others and be understood, you need to speak a common language. No one is forcing you to speak any specific language, but to speak to someone, you need to do so in a language they understand. Web standards are the language of the web. By using them, your app can be part of the conversation. The web is actually a collection of standards. The four most important ones are: - [Hypertext Transfer Protocol](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) - also known as HTTP. - [Hypertext Markup Language](https://en.wikipedia.org/wiki/HTML) - also known as HTML. - [Cascading Style Sheets](https://en.wikipedia.org/wiki/CSS) - also known as CSS. - [Javascript](https://en.wikipedia.org/wiki/JavaScript) - also known as JS. All of these standards, plus many others, make up the web. The web runs on top of the internet. And guess what? The internet itself is also powered by standards, such as [DNS](https://en.wikipedia.org/wiki/Domain_Name_System), [TCP/IP](https://en.wikipedia.org/wiki/Internet_protocol_suite), [WiFi](https://en.wikipedia.org/wiki/Wi-Fi) and [Ethernet](https://en.wikipedia.org/wiki/Ethernet). This is a good moment to explain the relationship between the internet and the web, from the perspective of webapps. The best way to understand it is through an analogy: - The internet is the *highway system*. - The web is the *vehicles* that run on the highway. - The frontend and the backend are *locations* that can be connected through vehicles running in the highway. Without a highway system (internet), the web cannot work. But once the highway is in place, the vehicles (web) can carry information from one location to the other. #### How is the frontend loaded? Getting the backend to run is simple: you copy the backend program to a server and run the backend using the runtime. The backend is a program that will run constantly and forever, until you stop it. Once you set it running, it will be listening to incoming requests. It is esential that your server should receive the requests directed to a given web domain. For example, if your app's domain is `myapp.com`, your server should be configured so that it receives all the requests sent to `myapp.com`. We won't go into details here, because this tutorial is focused on the frontend and this topic squarely belongs to the backend. The gist of it is that, from the perspective of the web, `myapp.com` should *point* to your server. The frontend works differently. When the user opens a new tab to go to a webapp, the frontend is not there yet. It must be *loaded* onto the browser first. How does this happen? The diagram above explains the main steps: ``` Step 1: ┌──╌ Browser ╌─────────┐ ┌──╌ Backend ╌─────────────┐ │ ─────┼──╌ request URL ╌────┼─────> │ └──────────────────────┘ (myapp.com) └──────────────────────────┘ Step 2: ┌──╌ Browser ╌─────────┐ ┌──╌ Backend ╌─────────────┐ │ <─────┼──╌ main HTML file ╌─┼───── │ └──────────────────────┘ └──────────────────────────┘ Step 3: ┌──╌ Browser ╌─────────┐ ┌──╌ Backend ╌─────────────┐ │ ─────┼──╌ request CSS ╌────┼─────> │ └──────────────────────┘ & JS files └──────────────────────────┘ Step 4: ┌──╌ Browser ╌─────────┐ ┌──╌ Backend ╌─────────────┐ │ <─────┼──╌ CSS & JS files ╌─┼───── │ └──────────────────────┘ └──────────────────────────┘ Step 5: ┌──╌ Browser ╌─────────┐ │ Frontend is loaded! │ └──────────────────────┘ ``` - Step 1: - The user opens a tab in their browser and navigates to an URL where the webapp is available. This URL can be written manually, or it can be followed through a link. The browser doesn't care. - The browser finds the backend that corresponds to that URL and requests an HTML file. This file is the *main file* of the webapp. - Step 2: - The backend receives the request for the main HTML file. It finds the file and sends it back to the browser. - The browser receives the main HTML file. - Step 3: - Almost always there will be links to CSS & JS files within the main HTML file. For example, a `` tag can request a certain CSS file; and a ` ``` In the example above, [jQuery](https://en.wikipedia.org/wiki/jQuery), one of the first JS frameworks and still one of the most popular ones, is loaded. After that, the frontend code of the app is loaded in the file `frontend.js`. Nowadays, there are more powerful (and complex) ways of loading JS libraries. However, they still boil down to JS files being loaded by the browser. JS, Ajax and the first generation of JS frameworks grew hand in hand in the second half of the 2000s. Some webapps already started to boast complex and high-quality UIs. For many teams, however, the complexity of the client became problematic. Most of the problems were related to two basic concerns: 1. **Generating HTML to update the page**: as we said above, after an Ajax interaction, the page usually needs to be updated. This requires us to generate HTML that reflects the updated page. HTML is text, so it is possible to create HTML by putting together strings. But this is time consuming and error-prone, because it doesn't use templates or other abstractions that can better express how the HTML should be produced. 2. **Updating certain parts of the page at the right time**: after an Ajax interaction, some parts of the page have to be updated. To decide which parts should be updated, and based on which information, is also something that becomes complex if implemented on a case-by-case basis. The two basic concerns might sound quite familiar to you. Indeed, we have covered them in chapter 7! They are **templating** and **state management**. To deal with them, web frameworks emerged in the late 2000s and early 2010s. These frameworks offered their own solution to these two concerns. Some of these frameworks were **server-side**, which means that all the templating and some of the state management happened in the server. In practice, this means that the updated parts of the page are generated in the server and then put in place by JS. These frameworks are powered by other programming languages, such as PHP, Ruby or Python. Other frameworks, in contrast, were **client-side**. This means that these frameworks are 1) written in JS; and 2) perform their operations in the browser, not the server. Client-side frameworks appeared to solve these two main concerns strictly in the client. The first framework of this kind was [Angular](https://en.wikipedia.org/wiki/AngularJS), developed by Google and first released in 2010. It was followed by [React](https://en.wikipedia.org/wiki/React_(JavaScript_Library)), developed by Facebook and first released in 2013. Both frameworks are widely used and others have followed in their steps. Server-side and client-side web frameworks continue to exist and evolve to the present day. Yet, no matter how it is implemented, almost all contemporary webapps are powered by Ajax and JS. This chapter concludes our conceptual introduction to web applications. If you've made it this far, congratulations! In the second part of the tutorial, we switch to a hands-on approach and start building a few simple webapps. Through those examples, we'll come to understand better a few fundamental problems of frontend development that seem to emerge in almost all webapps, as well as how gotoB solves them. ## Part 2: deriving gotoB Originally, this part of the tutorial was going to be about how to develop a frontend with gotoв. But eventually we decided instead to do something different: start developing small apps with no tools at all, and **understand firsthand the raw problems we face when implementing a frontend**. We then slowly introduce gotoв to solve some of these problems for us. In this way, we first aim to understand fully the problems we encounter, rather than covering them up with a solution. We also hope this approach will make both the tutorial and gotoв itself far easier to understand and remember. ### Chapter 1: setting up the basics Let's start by setting up the basics of an app. You only need the following: - A computer. - A text editor. - A web browser. #### Step 1-1: create a folder to contain the files of your application You can call it `app` - put this folder somewhere where you can easily find it later. #### Step 1-2: create a base HTML file ([HTML](1-2.app.html)) As we saw in chapter 6 of part 1, all webapps start with a single HTML file that is loaded by the browser. We will now write this base HTML file. With your text editor, create a new file named `app.html` within the work folder you created on Step 1-1. In it, place the following content: ```html
``` Let's break this down: 1. `` declares the page to be [HTML5](https://en.wikipedia.org/wiki/HTML5). 2. `` and `` delimit the entire contents of the page. 3. `` and `` delimit the head of the page. 4. `` and `` delimit the body of the page. 5. Inside the head there are two `` tags. The first one allows to cleanly display non-[ASCII](https://en.wikipedia.org/wiki/ASCII) characters, which is something essential. The second one allows for creating applications that will look good on mobile devices. 6. Inside the head there's a `` tag which an loads an external CSS file called [Tachyons.io](https://tachyons.io). While this is not strictly necessary, it is extremely useful because it 1) makes CSS behavior more consistent across different browsers (leveraging [Normalize.css](https://necolas.github.io/normalize.css/)) and 2) gives us CSS classes with which we can build a decent-looking UI without writing our own CSS. 7. Inside the body there's a `