summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-09-21 00:25:05 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-09-23 18:59:57 -0400
commit8bb25062e5b804c27b58ae36f585f12b1c602487 (patch)
tree6d3153c321210a04b8149f3a1656e43dd7912d73
parent68a0f75e04e2557d63a7d60cd9a46ae715df3d15 (diff)
Small design doc
-rw-r--r--docs/design.md38
1 files changed, 38 insertions, 0 deletions
diff --git a/docs/design.md b/docs/design.md
new file mode 100644
index 0000000..1180b83
--- /dev/null
+++ b/docs/design.md
@@ -0,0 +1,38 @@
+# Internal design
+
+`hi`'s design is discovered and not planned. Do not take this as doctrine; continue to experiment on the structure as you find new needs.
+
+As of this writing, the basic flow of most requests hits several subsystems:
+
+* Axum handles parsing and delivering requests to endpoint handlers.
+* Endpoint handlers interact with an "app" method (mostly defined in `**/app.rs`) to carry out logic.
+* App methods interact with the database through "repo" methods.
+* Repo methods access the database, and carry out minor tasks directly adjacent to data access (ID generation being the main example).
+
+This approach helps enable testing (see [testing.md] and the implementation of most of the tests), and helps maintain some conceptual separation between what this service does and how each piece individually works.
+
+## Time
+
+Handling time in a service is always tricky.
+
+`hi` takes the approach that a request is considered to be serviced at one time, and that that time is determined when the request is received. The internals of `hi` - the "app" and data access types described below, as well as most other supporting tools - are written with an eye towards accepting the "current time" as an argument, rather than calling out to a clock for themselves.
+
+The "current time" for a request is determined in `src/clock.rs`, which runs on every request, and is available to the handler via the `RequestedAt` extractor defined in that module.
+
+One of the perks of this approach is that tests, which call extractors, app interfaces, and data access interfaces directly, can pass any time they please, which enables scenarios like "if I sent a message last year, it should have expired by today."
+
+## Errors
+
+In general, errors are reported back up as Rust values with full Rust semantics, and are converted to HTTP errors at the last moment (generally via `IntoResponse` implementations on internal error types). Where possible, I've preferred using newtype to wrap an underlying error over defining multiple "similar" error taxonomies, but the error handling is somewhat inconsistent, so don't take this too seriously.
+
+The key property that _does_ matter is making sure the errors making it out of
+
+## Code organization
+
+This project uses a hybrid organization approach.
+
+High-level concerns are grouped into modules. These are `crate::channel`, `crate::events`, `crate::login`, and others. Those modules generally contain their own app types, their own repo types, their own extractors, and any other supporting code they need. They may also provide an interface to other modules in the program.
+
+However, some cross-cutting parts of the system have been pulled out into top-level modules of their own. These are `crate::repo`, `crate::app`, `crate::clock`, and others. Reasons for doing this include having multiple equally-valid modules the code could have been put in, keeping the use of namespaces legible, and others.
+
+Trust your gut, and reorganize to meet new needs.