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
>| Date |`01/04/2025`_when the decision was last updated_|
5
+
>| Date |`17/04/2025`_when the decision was last updated_|
6
6
>| Status |`Proposed`|
7
7
>| Deciders |`Team`|
8
8
>| Significance |`Structure`|
@@ -30,7 +30,7 @@ We're deciding initial technologies for the service. We're working under the ass
30
30
[Reasons for adopting a framework are outlined in the quality framework.](https://github.com/NHSDigital/software-engineering-quality-framework/blob/6d5453d3ee0f9c7af1a4b48d2ec8cb72d9826460/practices/structured-code.md?plain=1#L24) Our app is not trivial enough to build without a framework, and we are assuming it will be fairly typical for a web application running
31
31
in the cloud: a stateless service that renders HTML from tempalates, an ORM that connects to a Postgres database, etc.
32
32
33
-
We're initially intending to productionise the [manage screening events prototype](https://github.com/NHSDigital/manage-screening-events-prototype). We're anticipating building an additional gateway service that would be deployed inside trusts' networks, which this app would communicate with via a queue or API (to be decided later).
33
+
We're initially intending to productionise the [manage screening events prototype](https://github.com/NHSDigital/manage-screening-events-prototype). We're anticipating that we may build an additional gateway service that would be deployed inside trusts' networks, which this app would communicate with via a queue or API, but this is to be decided later.
34
34
35
35
36
36
## Decision
@@ -39,16 +39,20 @@ We're initially intending to productionise the [manage screening events prototyp
39
39
40
40
### Drivers
41
41
42
+
- We're building a web application with an accessible frontend, not a microservice
42
43
- Convention over configuration: the framework should provide reasonable, secure defaults, and be familiar enough for new team members joining the team
43
44
- Easy to get started with
44
45
- Easy to extend while maintaining separation of concerns
45
46
- Limited boilerplate
46
47
47
48
### Options
48
49
49
-
We are considering the two most common frameworks in Python: Django and Flask. Both are stable, established frameworks, with large open source communities. Flask is on the Technology Radar, and is being used for several APIs. Django is not on the radar but is used by the [Transformation directorate website](https://github.com/nhsx/nhsx-website).
50
+
We considered the two most common frameworks in Python: Django and Flask. Both are stable, established frameworks, with large open source communities. Flask is on the Technology Radar, and is being used for several APIs. Django is not on the radar but is used by the [Transformation directorate website](https://github.com/nhsx/nhsx-website).
51
+
52
+
In addition to this repo, we created a [technical spike for Flask](https://github.com/NHSDigital/manage-breast-screening-flask-spike).
50
53
51
54
#### ORM
55
+
52
56
Django has a built in ORM and migrations framework. The Django ORM uses the simpler [ActiveRecord pattern](https://www.thoughtfulcode.com/orm-active-record-vs-data-mapper/), whereas a Flask app would use SQLAlchemy, which implements the Data mapper pattern.
53
57
54
58
Django's ORM is well documented and easy to get started with:
@@ -63,24 +67,34 @@ In general, Django encourages a tightly coupled model layer, but this comes with
63
67
the view / form / model abstractions work well together. It is possible to abstract away the ORM behind a service layer, but then you lose a lot of these helpful abstractions (e.g. model forms, pagination helpers etc).
64
68
65
69
#### Templating
70
+
66
71
Django has its own templating language, but it also supports Jinja.
67
72
With a few minor adjustments, we can reuse the NHS.UK frontend templates.
68
73
69
74
Flask uses Jinja by default.
70
75
76
+
#### Routing
77
+
78
+
Flask has a fairly robust routing system, using "blueprints" to organise and group routes in different parts of the app. Django has a comparable system which is also flexible and easy to keep organised.
79
+
71
80
#### View logic
81
+
72
82
Django includes [Generic class-based views](https://docs.djangoproject.com/en/5.1/topics/class-based-views/generic-display/), which can be used to reduce boilerplate in the view layer. The trade-off is they are a bit more unintuitive to work with compared to function based views. We have the option of using either or both.
73
83
74
84
Django has a [form abstraction](https://docs.djangoproject.com/en/5.2/topics/forms/) that simplifies the rendering and processing of form pages. The form layer is completely decoupled from the model layer, but you would typically use model forms as described above.
75
85
76
86
If we decide to build APIs, we can use [Django Rest Framework](https://www.django-rest-framework.org/) - a framework built on top of Django that handles serialisation/deserialisation, API authentication, and OpenAPI specifications.
77
87
78
88
#### Authentication system
89
+
79
90
Django comes bundled with an [authentication system](https://docs.djangoproject.com/en/5.1/ref/contrib/auth/) which handles accounts, permissions, and user sessions.
80
91
81
92
We would be using this in combination with an OIDC library such as [Django-AllAuth](https://docs.allauth.org/en/latest/) or [Authlib](https://docs.authlib.org/en/latest/client/django.html).
82
93
94
+
Flask would need auth built out manually using a library like flask-OAuth.
95
+
83
96
#### Learning curve
97
+
84
98
Django is a larger framework, so there is more to learn, but less moving parts.
85
99
86
100
Since the framework has more conventions for doing things than flask, it is easier to move between Django
@@ -89,48 +103,58 @@ projects, and if you get stuck it's a bit easier to find people who've solved th
89
103
We have some Django knowledge on the team already, and Django is conceptually very similar to other major web frameworks such as Rails, which the team is already familiar with.
90
104
91
105
#### Code structure
106
+
107
+
Flask is completely flexible and unopinionated, meaning that every decision about where to put things will be up to this team. This could lead to a project structure that has more of a learning overhead for new developers.
108
+
109
+
Django has a more prescriptive structure, which potentially means a project structure that is more familiar to new developers.
110
+
92
111
Django encourages you to factor your Django project into modular [apps](https://docs.djangoproject.com/en/5.2/ref/applications/), rather than a single monolithic package. An app may correspond to a [bounded context in domain-driven design](https://martinfowler.com/bliki/BoundedContext.html) or a cross-cutting capability.
93
112
94
113
[It is possible to write apps in such a way that can be reused and configured in other projects.](https://docs.djangoproject.com/en/5.2/intro/reusable-apps/).
95
114
96
115
There is a large ecosystem of 3rd party apps available.
97
116
98
117
#### Security
118
+
99
119
Django has built in protections for common web app vulnerabilities, such as XSS, SQL injections, CSRF.
100
120
101
121
There is guidance and checklists in the [Django security guide](https://docs.djangoproject.com/en/5.2/topics/security/) and [How to deploy Django](https://docs.djangoproject.com/en/5.2/howto/deployment/).
102
122
123
+
Flask has basic session management and XSS protection via its use of jinja2 templates. Other protections would need to come from external libraries, which we'd need to select manually based on a list of common vulnerabilities.
124
+
103
125
#### Testing
126
+
104
127
Django comes with very good [testing tools](https://docs.djangoproject.com/en/5.2/topics/testing/tools/). Out of the box you can test database interactions (rolling back to a fresh state between tests), and emulated HTTP requests.
105
128
106
129
By default Django uses unittest as the test framework, but you can easily swap this out for [pytest](https://pypi.org/project/pytest-django/).
| Security | Built in security features and guidance | -- |
118
-
| Testing | Good testing tools included | -- |
131
+
Flask also comes with a [test client](https://flask.palletsprojects.com/en/stable/testing/).
119
132
120
-
### Outcome
133
+
#### CLI
134
+
135
+
Flask has a basic CLI tool that allows for running a dev server, displaying app routes, and running a shell in the app context. All other convenience commands would need to be implemented manually.
136
+
137
+
Django has the manage utility for running administrative tasks, including running a server, migrations, an application shell, inspecting the database schema, etc. One notable absence is printing out app routes.
121
138
122
-
TBD.
139
+
#### Summary of differences
123
140
124
-
This decision will be relatively hard to move away from once we start building out the app, which is why we've spiked out two options to compare side by side.
141
+
The following is the minimum set of concerns that would require us to hand-roll our own setup under Flask (and for which Django already provides a solution):
125
142
126
-
### Rationale
143
+
- Project structure
144
+
- ORM / database setup
145
+
- Form rendering
146
+
- Security protections comparable to the built-in Django protections
147
+
- Helper scripts for common tasks
148
+
149
+
### Outcome
127
150
128
-
Provide a rationale for the decision that is based on weighing the options to ensure that the same questions are not going to be asked again and again unless the decision needs to be superseded.
151
+
We decided to use Django on the basis that:
129
152
130
-
For non-trivial decisions a comparison table can be useful for the reviewer. Decision criteria down one side, options across the top. You'll likely find decision criteria come from the Drivers section above. Effort can be an important driving factor. You may have an intuitive feel for this, but reviewers will not. T-shirt sizing the effort for each option may help communicate.
153
+
- The above represents a sizable amount of time and effort recreating things that are already available in Django
154
+
- It would involve the use of various Flask extensions in varying states of maintenance, as opposed to a single, well-maintained framework
155
+
- The security protections in particular are an area where it would be preferable not to roll our own, given the potential for leaving attack vectors open
131
156
132
157
## Consequences
133
-
(If we pick Django...)
134
158
135
159
Engineers on the team will need to learn Django. Some suggested learning resources:
136
160
-[Django documentation and first steps guide](https://docs.djangoproject.com/en/5.1/)
0 commit comments