You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -6,44 +6,182 @@ _Immutable Web Applications_ is a framework-agnostic methodology for building an
6
6
7
7
- Minimizes risk and complexity of live releases.
8
8
- Simplifies and maximizes caching.
9
-
- Minimizes the need for servers and systems administration.
9
+
- Minimizes the need for servers and administration of runtime environments.
10
10
- Enables continuous delivery through simple, flexible, atomic deployments.
11
11
12
12
## Principles
13
13
14
14
The methodology is based on the principles of ___strictly separating___:
15
15
16
+
- Dynamic content from static content.
16
17
- Configuration from code.
17
18
- Release tasks from build tasks.
18
-
- Dynamic content from static content.
19
19
20
20
These principles are inspired by [The Twelve-Factor App](https://12factor.net/).
21
21
22
-
## Concepts
22
+
## Decomposing a web application
23
23
24
-
The following concepts define the core requirements for an _Immutable Web Application_. They are framework and infrastructure agnostic.
24
+
The _Immutable Web App_ methodology was developed by through a process of decomposing web applications based on the principles declared above and then reconsidering the relationship between the different components. Before defining the methodology, this document will step through the decomposition. It starts with a monolithic web application.
25
25
26
-
### _Permabundles_
26
+
### The Monolithic Web-Application
27
27
28
-
Permabundles are the static assets that make up a single-page application.
28
+
There generally are three types of network traffic commonly made in by web application from the browser:
29
29
30
-
- They must be available at a [permalink](https://en.wikipedia.org/wiki/Permalink) that is uniquely versioned or fingerprinted and _independent of the web application environment(s)_.
30
+
#### static assets
31
31
32
-
- They must be configured for long-term caching. (`cache-control: public, max-age=31536000, immutable`)
32
+
- javascript, css, images, bundled assets
33
+
- long term cached
34
+
- artifacts live on the client
33
35
34
-
-__They must not contain any environment-specific configuration.__
An `index.html` exists for each deployment environment.
41
+
#### the document
39
42
40
-
- They must contain fully-qualified references to the _permabundle_ assets.
43
+
- typically in the form of `index.html`
44
+
- no caching
45
+
- returned for all routes that aren't physical files
41
46
42
-
- They must never be cached by the browser or a public cache that cannot be purged on-demand. (`cache-control: no-store`)
47
+
> An image of typical network traffic for a simple single page application
43
48
44
-
-__They must define all environment-specific configuration.__
49
+
A monolithic web application will handle the requests for all three types of requests. Express, a very popular node framework for building web applications, generally supports handling all three types of requests. Running the `express-generator` will create an application skeleton that supports routes for each:
A monolithic web application will also include a web application framework, like Angular, for building the single-page application assets. Using Express and Angular together in a single code base will results in a multi-stage build:
80
+
81
+
- First the static Angular apps are generated and
82
+
- Then the assets are embedded in the creation of the executable package (docker image, rpm).
83
+
84
+
The package is then typically stored in a versioned repository of packages before it is deployed to a runtime environment.
85
+
86
+
> An image of the monolith build process: code => build static assets => build docker image with assets baked in => publish image to docker repo => deployed to server
87
+
88
+
#### Characteristics of the monolithic web application
89
+
90
+
- separation release tasks from build tasks (good)
91
+
- high cohesion between the backend and frontend contract (good)
92
+
- ability to test the same build artifact in multiple environments (good)
93
+
- if the backend goes down, so does the frontend - serving static assets is much more reliable then dynamic backends, and gracefully handling backend outages is a better user experience than 404s and 500s (bad)
94
+
- zero downtime deploys can be tricky considering caching and existing browser sessions (bad)
95
+
- complicated project dependencies that represent two very different jobs (bad)
96
+
- building a static web application assets
97
+
- running a web server
98
+
99
+
### Separate frontend from backend
100
+
101
+
The first stage of decomposition is to separate the client from the server. This aligns with the principle of strict separation of dynamic content from static content.
102
+
103
+
> An image of the two separated build processes:
104
+
> code => build static assets => publish to static web server with routing rules
105
+
> code => build docker image => publish image to docker repo => deploy to server
106
+
107
+
#### The static web application
108
+
109
+
code base generates static assets,
110
+
111
+
The static assets can be deployed to a static web server that will have much higher reliability than the backend.
112
+
113
+
The static web apps should generally be cached for the long term, the backend should have caching turned off.
114
+
115
+
#### The backend api
116
+
117
+
code base generates an executable package.
118
+
119
+
generally you can read up on 12 factor app for help here, as it has been decoupled from many of the web application specific concerns
120
+
121
+
#### Characteristics of the frontend/backend web application
122
+
123
+
deployments require a little more careful sequencing to avoid zero-downtime. The backend may need to support multiple versions of an app as the frontend is deployed from one version to another. this is good, because it makes an preexisting problem more visible.
124
+
125
+
Code bases for generating the backend and the code base for generating the static application is separated.
126
+
127
+
Client side assets are often environment specific and deployed right after they are built as a part of a release.
128
+
129
+
### index.html as a special file
130
+
131
+
The second stage of decomposition continues to emphasize the strict separation of dynamic content from static content by separating `index.html`.
132
+
133
+
The document, `index.html`, is a bit of a special case. It may be a static file from the perspective of a specific deployment, but over the lifetime of multiple deployments, it is a dynamic file... evident by the fact that it cannot be cached at any location by the browser. Moreover, it has routing responsibilities that are unlike any of the other static assets or apis.
134
+
135
+
> An image of the three separated build processes:
136
+
> code => build static assets => publish to static web server
137
+
> code => build docker image => publish image to docker repo => deploy to server
138
+
> index.html => publish to static web server that always returns index.html
139
+
140
+
#### `index.html`
45
141
46
-
_The `index.html` of your Angular app might look like this... it's all configuration!_:
142
+
can be hosted by a static web server that for whatever path it is requested it always returns `index.html`
143
+
144
+
#### `static assets`
145
+
146
+
it allows us to simplify the hosting of all other static assets, all other static assets can be hosted in a completely different domain, and cached for long term if they are versioned or fingerprinted
147
+
148
+
#### Characteristics of the index/frontend/backend web application
149
+
150
+
assets can be build prior to deployment, a live release is effectively the act of updating `index.html`, but opportunities for testing them are limited.
151
+
152
+
### Separating code from config
153
+
154
+
Now that the app is decomposed into long term cached static assets, backend apis, and the special case of `index.html`, the relationships between the three parts look like this:
155
+
156
+
> An image of the three components and lines showing their dependencies (BEFORE)
157
+
158
+
-`index.html` has a strict dependency on static assets
159
+
160
+
- javascript in the static assets has strict dependencies on the backend apis (based on how modern web app frameworks handle configuration)
161
+
162
+
```typescript
163
+
// This file can be replaced during build by using the `fileReplacements` array.
164
+
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
165
+
// The list of file replacements can be found in `angular.json`.
166
+
167
+
exportconst environment = {
168
+
production: false
169
+
};
170
+
```
171
+
172
+
- the backend apis generally have no dependencies on either the static assets or index.html
173
+
174
+
The environment configuration that creates a strict dependency between the javascript and the api violates the principle of strict separation of configuration from code. This practice forces the static assets to be rebuilt for each environment and for any configuration change. Rebuilding the static assets introduces risk and promotes a workflow that does not distinguish between build tasks and deploy tasks, adding even more risk and complexity to releases.
175
+
176
+
By expanding the perception of dynamic and static, index.html can be perceived as static from the perspective of one deployment, but dynamic over the lifetime of multiple deployments. Similarly, Javascript that contains configuration is static from the perspective of one environment, but it is _conceptually_ dynamic over multiple environments because of the differences in configuration. This dynamic quality is addressed by building the assets multiple times and publishing to multiple locations.
177
+
178
+
Moving the configuration out of the static javascript allows it to be _truly_ static. __It can be generated once, published once, cached forever and used in multiple different environments with multiple configurations.__
179
+
180
+
Where does the configuation live? It must live in a location that is dynamic (and therefore never cached), it must be unique to the environment and unique to the deployment. `index.html` has all of these qualities. If configuration is moved into `index.html`, the relationships now look like this:
181
+
182
+
> An image of the three components and lines showing their dependencies (AFTER)
183
+
184
+
Consider what it looks like to have all environment configuration defined on the global scope of the `index.html` generated by the `angular-cli`:
47
185
48
186
```html
49
187
<!doctype html>
@@ -60,7 +198,7 @@ _The `index.html` of your Angular app might look like this... it's all configura
60
198
<!-- environment variables -->
61
199
<script>
62
200
env = {
63
-
API:'https://api.immutablewebapps.org',
201
+
API:'https://immutablewebapps.org/api',
64
202
OAUTH:'https://oauth.immutablewebapps.org',
65
203
GA_TRACKING_ID:'UA-98765432-1'
66
204
}
@@ -69,17 +207,50 @@ _The `index.html` of your Angular app might look like this... it's all configura
- It is strikingly similar to a kubectrl deployment YAML or a docker-compose.yaml
225
+
226
+
MORE STUFF HERE
227
+
228
+
### Conclusions
229
+
230
+
## Concepts
231
+
232
+
The following concepts define the core requirements for an _Immutable Web Application_. They are framework and infrastructure agnostic.
233
+
234
+
### _Permabundles_
235
+
236
+
Permabundles are the static assets that make up a single-page application.
237
+
238
+
- They must be available at a [permalink](https://en.wikipedia.org/wiki/Permalink) that is uniquely versioned or fingerprinted and _independent of the web application environment(s)_.
239
+
240
+
- They must be configured for long-term caching. (`cache-control: public, max-age=31536000, immutable`)
241
+
242
+
-__They must not contain any environment-specific configuration.__
- They must contain fully-qualified references to the _permabundle_ assets.
249
+
250
+
- They must never be cached by the browser or a public cache that cannot be purged on-demand. (`cache-control: no-store`)
251
+
252
+
-__They must define all environment-specific configuration.__
253
+
83
254
## Workflow
84
255
85
256
The workflow is defined by its separation of build tasks and release tasks. Specifically, the publishing of permabundles as a _build_ and the publishing of index.html as a _release_.
0 commit comments