Skip to content

Commit 60d5c78

Browse files
committed
Move ADRs to date based naming
We may also want to remove `index.md` and `template.md` at some point, but keeping for now pending larger conversations about how `docs/decisions/` should be structured. Related to navapbc/template-infra#401
1 parent 612ac3d commit 60d5c78

6 files changed

+107
-108
lines changed

template/docs/decisions/{{app_name}}/0000-use-markdown-architectural-decision-records.md renamed to template/docs/decisions/{{app_name}}/2022-09-23-use-markdown-architectural-decision-records.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ Which format and structure should these records follow?
77

88
## Considered Options
99

10-
* [MADR](https://adr.github.io/madr/) 2.1.2 – The Markdown Architectural Decision Records
11-
* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) – The first incarnation of the term "ADR"
12-
* [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) – The Y-Statements
13-
* Other templates listed at <https://github.com/joelparkerhenderson/architecture_decision_record>
14-
* Formless – No conventions for file format and structure
10+
- [MADR](https://adr.github.io/madr/) 2.1.2 – The Markdown Architectural Decision Records
11+
- [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) – The first incarnation of the term "ADR"
12+
- [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) – The Y-Statements
13+
- Other templates listed at <https://github.com/joelparkerhenderson/architecture_decision_record>
14+
- Formless – No conventions for file format and structure
1515

1616
## Decision Outcome
1717

1818
Chosen option: "MADR 2.1.2", because
1919

20-
* Implicit assumptions should be made explicit.
20+
- Implicit assumptions should be made explicit.
2121
Design documentation is important to enable people to understand the decisions later on.
2222
See also [A rational design process: How and why to fake it](https://doi.org/10.1109/TSE.1986.6312940).
23-
* The MADR format is lean and fits our development style.
24-
* The MADR structure is comprehensible and facilitates usage & maintenance.
25-
* The MADR project is vivid.
26-
* Version 2.1.2 is the latest one available when starting to document ADRs.
23+
- The MADR format is lean and fits our development style.
24+
- The MADR structure is comprehensible and facilitates usage & maintenance.
25+
- The MADR project is vivid.
26+
- Version 2.1.2 is the latest one available when starting to document ADRs.

template/docs/decisions/{{app_name}}/0001-connexion-replacement.md renamed to template/docs/decisions/{{app_name}}/2022-09-27-connexion-replacement.md

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@ We aren't looking to move off of Flask at the moment as we feel that would be a
1414

1515
## Decision Drivers
1616

17-
* Connexion requires you to specify an OpenAPI spec but passes the request objects as the raw JSON. We currently use Pydantic to convert this into a Python object for additional validations & for ease of use, but this effectively means we need to define any models twice.
18-
* Defining the OpenAPI specs first instead of defining the data models in code has often been more frustrating. While one goal of doing it this way was the ability to create mock endpoints while development is ongoing, this can also be easily handled by just making the endpoint return a static response in-code.
19-
* Connexion's defaults for validation leave a lot to be desired. While we currently override these, it adds a lot of boilerplate to this template library, and isn't immediately obvious.
20-
* Code first is recommended by Swagger when building internal APIs that need to be built quickly: https://swagger.io/blog/api-design/design-first-or-code-first-api-development/ which is often the case for our endpoints that aren't directly exposed to users.
17+
- Connexion requires you to specify an OpenAPI spec but passes the request objects as the raw JSON. We currently use Pydantic to convert this into a Python object for additional validations & for ease of use, but this effectively means we need to define any models twice.
18+
- Defining the OpenAPI specs first instead of defining the data models in code has often been more frustrating. While one goal of doing it this way was the ability to create mock endpoints while development is ongoing, this can also be easily handled by just making the endpoint return a static response in-code.
19+
- Connexion's defaults for validation leave a lot to be desired. While we currently override these, it adds a lot of boilerplate to this template library, and isn't immediately obvious.
20+
- Code first is recommended by Swagger when building internal APIs that need to be built quickly: https://swagger.io/blog/api-design/design-first-or-code-first-api-development/ which is often the case for our endpoints that aren't directly exposed to users.
2121

2222
## Considered Options
2323

24-
* [APIFlask](#apiflask) **Recommended Approach**
25-
* [Flask OpenAPI3](#flask-openapi3)
26-
* [Flasgger](#flasgger)
27-
* [Flask Smorest](#flask-smorest)
28-
* [APISpec](#apispec)
29-
* [Flask RESTX](#flask-restx)
30-
* [APIFairy](#apifairy)
24+
- [APIFlask](#apiflask) **Recommended Approach**
25+
- [Flask OpenAPI3](#flask-openapi3)
26+
- [Flasgger](#flasgger)
27+
- [Flask Smorest](#flask-smorest)
28+
- [APISpec](#apispec)
29+
- [Flask RESTX](#flask-restx)
30+
- [APIFairy](#apifairy)
3131

3232
## Decision Outcome
3333

@@ -130,12 +130,12 @@ def create_user(user: User):
130130
```
131131
</details>
132132

133-
* Good, because the documentation is immensely thorough, and does a great job of explaining all the customization options while providing sane defaults.
134-
* Good, because you can [register custom error processors](https://apiflask.com/error-handling/#custom-error-response-processor) which would allow us to reuse and adapt our existing error processors - although it looks like the defaults are more sane - as all errors, not just the first get added to the error response.
135-
* Good, because [authentication looks to be flexible](https://apiflask.com/authentication/), and allows you to define it as if you were writing the OpenAPI.
136-
* Good, because the [API uses Marshmallow](https://apiflask.com/schema/) for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - and additionally supports [Marshmallow Dataclass](https://apiflask.com/schema/#use-dataclass-as-data-schema) which is a wrapper that allows you to interact directly with dataclass objects which further improves runtime typing.
137-
* Meh, because methods end up with several decorators, although you can [group route methods into classes](https://apiflask.com/usage/#use-class-based-views) and make them share decorators (eg. set the authentication decorator on the class).
138-
* Bad, because APIFlask 1.0 only released in May 2022, with the first beta release about a year earlier, so the project is still somewhat young.
133+
- Good, because the documentation is immensely thorough, and does a great job of explaining all the customization options while providing sane defaults.
134+
- Good, because you can [register custom error processors](https://apiflask.com/error-handling/#custom-error-response-processor) which would allow us to reuse and adapt our existing error processors - although it looks like the defaults are more sane - as all errors, not just the first get added to the error response.
135+
- Good, because [authentication looks to be flexible](https://apiflask.com/authentication/), and allows you to define it as if you were writing the OpenAPI.
136+
- Good, because the [API uses Marshmallow](https://apiflask.com/schema/) for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - and additionally supports [Marshmallow Dataclass](https://apiflask.com/schema/#use-dataclass-as-data-schema) which is a wrapper that allows you to interact directly with dataclass objects which further improves runtime typing.
137+
- Meh, because methods end up with several decorators, although you can [group route methods into classes](https://apiflask.com/usage/#use-class-based-views) and make them share decorators (eg. set the authentication decorator on the class).
138+
- Bad, because APIFlask 1.0 only released in May 2022, with the first beta release about a year earlier, so the project is still somewhat young.
139139

140140

141141
### Flask OpenAPI3
@@ -205,11 +205,11 @@ if __name__ == "__main__":
205205

206206
</details>
207207

208-
* Good, because the API model definitions use Pydantic, which is a well-supported library we are already familiar with.
209-
* Good, because the API definitions are minimal and pretty intuitive to read.
210-
* Bad, because the documentation isn't fully detailed, and the errors that occur when trying to get the API running aren't very clear. In ~30 minutes of debugging, I hadn't figured out how to get the API to fully run.
211-
* Bad, while it generates swagger docs, and can display example responses, it doesn't appear that you can specify example requests or parameters. This effectively makes Swagger unusable.
212-
* Bad, because it appears that the library is primarily [maintained by one person](https://github.com/luolingchun/flask-openapi3/commits/master), and appears to still be going through early implementation fixes.
208+
- Good, because the API model definitions use Pydantic, which is a well-supported library we are already familiar with.
209+
- Good, because the API definitions are minimal and pretty intuitive to read.
210+
- Bad, because the documentation isn't fully detailed, and the errors that occur when trying to get the API running aren't very clear. In ~30 minutes of debugging, I hadn't figured out how to get the API to fully run.
211+
- Bad, while it generates swagger docs, and can display example responses, it doesn't appear that you can specify example requests or parameters. This effectively makes Swagger unusable.
212+
- Bad, because it appears that the library is primarily [maintained by one person](https://github.com/luolingchun/flask-openapi3/commits/master), and appears to still be going through early implementation fixes.
213213

214214
### Flasgger
215215

@@ -221,9 +221,9 @@ Note that Flasgger has several different ways to define the schema. This specifi
221221

222222
No example implementation as the ones presented in the docs didn't actually function out of the box.
223223

224-
* Good, because there is a lot of variety in how you set up your schema, although most require defining the JSON/YAML yourself.
225-
* Bad, because the non-JSON/YAML approaches don't appear to be the main purpose of this API, and little documentation/examples exist regarding their usage.
226-
* Bad, because it seems the approach for running using [Marshmallow for the schema](https://github.com/flasgger/flasgger#using-marshmallow-schemas) isn't valid anymore as the parameters that Flask takes in don't match the example. From reading various other docs, Flask seems to have had a major version update that changed it a bit in recent years, so that is likely the cause.
224+
- Good, because there is a lot of variety in how you set up your schema, although most require defining the JSON/YAML yourself.
225+
- Bad, because the non-JSON/YAML approaches don't appear to be the main purpose of this API, and little documentation/examples exist regarding their usage.
226+
- Bad, because it seems the approach for running using [Marshmallow for the schema](https://github.com/flasgger/flasgger#using-marshmallow-schemas) isn't valid anymore as the parameters that Flask takes in don't match the example. From reading various other docs, Flask seems to have had a major version update that changed it a bit in recent years, so that is likely the cause.
227227

228228
### Flask Smorest
229229

@@ -304,11 +304,11 @@ if __name__ == "__main__":
304304

305305
</details>
306306

307-
* Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
308-
* Good, because it is fairly straightforward and just seems to work as expected.
309-
* Bad, because the documentation is pretty minimal beyond getting OpenAPI running. Seems like this is just an OpenAPI wrapper with no other additional features.
310-
* Bad, because it is pretty barebones. It just sets up a swagger endpoint and does the object validation, but doesn't handle anything beyond that regarding authentication.
311-
* Bad, because even the maintainers recognize it needs a [bit more work](https://github.com/apiflask/apiflask/discussions/14#discussioncomment-571898)
307+
- Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
308+
- Good, because it is fairly straightforward and just seems to work as expected.
309+
- Bad, because the documentation is pretty minimal beyond getting OpenAPI running. Seems like this is just an OpenAPI wrapper with no other additional features.
310+
- Bad, because it is pretty barebones. It just sets up a swagger endpoint and does the object validation, but doesn't handle anything beyond that regarding authentication.
311+
- Bad, because even the maintainers recognize it needs a [bit more work](https://github.com/apiflask/apiflask/discussions/14#discussioncomment-571898)
312312

313313
### APISpec
314314

@@ -422,10 +422,10 @@ if __name__ == "__main__":
422422
```
423423
</details>
424424

425-
* Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
426-
* Good, because it gives a lot of flexibility for defining the OpenAPI docs, [including security](https://apispec.readthedocs.io/en/latest/special_topics.html#documenting-security-schemes).
427-
* Bad, because you still have to specify some of the OpenAPI docs as a comment on the function. The primary gain is being able to use Marshmallow to define the schema models, but the routes are still largely yaml.
428-
* Bad, because apispec doesn't actually run the swagger docs, it just generates them. You would need to use one of the other approaches here in tandem.
425+
- Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
426+
- Good, because it gives a lot of flexibility for defining the OpenAPI docs, [including security](https://apispec.readthedocs.io/en/latest/special_topics.html#documenting-security-schemes).
427+
- Bad, because you still have to specify some of the OpenAPI docs as a comment on the function. The primary gain is being able to use Marshmallow to define the schema models, but the routes are still largely yaml.
428+
- Bad, because apispec doesn't actually run the swagger docs, it just generates them. You would need to use one of the other approaches here in tandem.
429429

430430
### Flask RESTX
431431

@@ -499,11 +499,11 @@ if __name__ == "__main__":
499499
```
500500
</details>
501501

502-
* Good, because the way it organizes namespaces (ie. tags), and parameters is intuitive and fairly readable.
503-
* Good, because it provides implicit [masking logic](https://flask-restx.readthedocs.io/en/latest/mask.html) that makes masking responses easy which is helpful when working with PII.
504-
* Bad, because while you define a model, you define it as a dictionary, not a class, and thus end up working with just dictionaries. If we wanted any well-structured classes, we'd need to define that separately.
505-
* Bad, because they have an entire section of documentation about [request parsing](https://flask-restx.readthedocs.io/en/latest/parsing.html) that is deprecated - and seems to have been replaced quite some time ago (not well maintained?).
506-
* Bad, because the last release was over a year ago, and there have only been a very small number of commits this year.
502+
- Good, because the way it organizes namespaces (ie. tags), and parameters is intuitive and fairly readable.
503+
- Good, because it provides implicit [masking logic](https://flask-restx.readthedocs.io/en/latest/mask.html) that makes masking responses easy which is helpful when working with PII.
504+
- Bad, because while you define a model, you define it as a dictionary, not a class, and thus end up working with just dictionaries. If we wanted any well-structured classes, we'd need to define that separately.
505+
- Bad, because they have an entire section of documentation about [request parsing](https://flask-restx.readthedocs.io/en/latest/parsing.html) that is deprecated - and seems to have been replaced quite some time ago (not well maintained?).
506+
- Bad, because the last release was over a year ago, and there have only been a very small number of commits this year.
507507

508508

509509
### APIFairy
@@ -594,9 +594,8 @@ if __name__ == "__main__":
594594
```
595595
</details>
596596

597-
* Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow).
598-
* Good, because the decorators are named fairly intuitively and help make the methods clearer.
599-
* Bad, because it insists Marshmallow "just works" but.. doesn't (see the hacky `jsonify` I had to do in the example). The very unhelpful error messages it gave about `jsonify` not existing were very frustrating.
600-
* Bad, because the documentation doesn't have any fully working examples making it difficult to figure out a minimal viable implementation. It is written as if you're adjusting a fully-formed Marshmallow-based Flask app, and not starting from scratch.
601-
* Bad, because there doesn't appear to be a ton of support - no questions posted anywhere, and only one article about it.
602-
597+
- Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow).
598+
- Good, because the decorators are named fairly intuitively and help make the methods clearer.
599+
- Bad, because it insists Marshmallow "just works" but.. doesn't (see the hacky `jsonify` I had to do in the example). The very unhelpful error messages it gave about `jsonify` not existing were very frustrating.
600+
- Bad, because the documentation doesn't have any fully working examples making it difficult to figure out a minimal viable implementation. It is written as if you're adjusting a fully-formed Marshmallow-based Flask app, and not starting from scratch.
601+
- Bad, because there doesn't appear to be a ton of support - no questions posted anywhere, and only one article about it.

0 commit comments

Comments
 (0)