Skip to content

Commit

Permalink
Going to hard wrap markdown decision docs for easier reading in diff …
Browse files Browse the repository at this point in the history
…/ non-soft wrap environments.
  • Loading branch information
zorn committed Jul 25, 2024
1 parent 093cb71 commit b170534
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
35 changes: 27 additions & 8 deletions docs/decisions/1-timestamps.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,47 @@

# Problem Statement

Out of the box, when you use the Ecto [`timestamps/1` function][1], you end up with `:naive_datetime` values for in-memory entities. This lacks the level of timezone precision we would prefer.
Out of the box, when you use the Ecto [`timestamps/1` function][1], you end up
with `:naive_datetime` values for in-memory entities. This lacks the level of
timezone precision we would prefer.

[1]: https://hexdocs.pm/ecto/Ecto.Schema.html#timestamps/1

## Solution

Our upcoming Ecto schemas will use `timestamps(type::utc_datetime_usec)` to be explicit about UTC and use microseconds for more precision.
Our upcoming Ecto schemas will use `timestamps(type::utc_datetime_usec)` to be
explicit about UTC and use microseconds for more precision.

When creating the database columns in our migration files, we will also use `timestamps(type::utc_datetime_usec)`. This results in the database column having a type like `timestamp without time zone NOT NULL`.
When creating the database columns in our migration files, we will also use
`timestamps(type::utc_datetime_usec)`. This results in the database column
having a type like `timestamp without time zone NOT NULL`.

Take note this Postgres column type does not have any timezone information. We assume the database will always store timestamp values in UTC (which is a community norm).
Take note this Postgres column type does not have any timezone information. We
assume the database will always store timestamp values in UTC (which is a
community norm).

## Other Solutions Considered

### `timestamptz`

We could have used a database migration style with `timestamps(type: :timestamptz)`, which would store timezone information in the Postgres database, **but** that also encourages people to store non-UTC timestamps in the database. For clarity, we would prefer the database always be UTC.
We could have used a database migration style with `timestamps(type:
:timestamptz)`, which would store timezone information in the Postgres database,
**but** that also encourages people to store non-UTC timestamps in the database.
For clarity, we would prefer the database always be UTC.

This is not an irreversible decision and can be adjusted if wanted.

### What are timestamps?

An argument can be made that the timestamp columns of the database are metadata of the implementation and should not be viewed as domain-specific values. The logic goes: If you want to track when your domain entities are created with your specific domain perspective, you should have `created_at` and `edited_at` columns. Those database-specific `inserted_at` and `updated_at` columns may change due to implementation needs and not accurately represent the actual domain knowledge.

That said, for the sake of simplicity, we are **not** going to introduce `created_at` and `edited_at` and will continue to make the `inserted_at` and `updated_at` values available to the Elixir code. Should these columns deviate from the domain interpretation, we can add those other columns later.
An argument can be made that the timestamp columns of the database are metadata
of the implementation and should not be viewed as domain-specific values. The
logic goes: If you want to track when your domain entities are created with your
specific domain perspective, you should have `created_at` and `edited_at`
columns. Those database-specific `inserted_at` and `updated_at` columns may
change due to implementation needs and not accurately represent the actual
domain knowledge.

That said, for the sake of simplicity, we are **not** going to introduce
`created_at` and `edited_at` and will continue to make the `inserted_at` and
`updated_at` values available to the Elixir code. Should these columns deviate
from the domain interpretation, we can add those other columns later.
31 changes: 23 additions & 8 deletions docs/decisions/2-ballot-and-vote-schema-shape.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,35 @@

## Ballots

The `Flick.RankedVoting.Ballot` schema captures a simple one-question ballot using fields for `question_title` and `possible_answers`.
The `Flick.RankedVoting.Ballot` schema captures a simple one-question ballot
using fields for `question_title` and `possible_answers`.

We could have solved "possible answers" in the data model in multiple ways but have picked this specific style with intent.
We could have solved "possible answers" in the data model in multiple ways but
have picked this specific style with intent.

We expect `possible_answers` to be a comma-separated list of values and have some basic validations around this. This decision was made with frontend practicality in mind. We've simplified the frontend UI by eliminating the need for a second layer of `inputs_for` for an alternative `PossibleAnswer` `embeds_many` schema design.
We expect `possible_answers` to be a comma-separated list of values and have
some basic validations around this. This decision was made with frontend
practicality in mind. We've simplified the frontend UI by eliminating the need
for a second layer of `inputs_for` for an alternative `PossibleAnswer`
`embeds_many` schema design.

Additionally, early drafts of this schema allowed a ballot to have multiple questions, but again, we've chosen to simplify for now.
Additionally, early drafts of this schema allowed a ballot to have multiple
questions, but again, we've chosen to simplify for now.

## Votes

When capturing votes, one might imagine a vote to have a `ballot_id` and then a list of ordered `answer_id` values. Given the above-described storage of `possible_answers`, we don't have answer id values.
When capturing votes, one might imagine a vote to have a `ballot_id` and then a
list of ordered `answer_id` values. Given the above-described storage of
`possible_answers`, we don't have answer id values.

When we capture a vote, we store an answer as a string value, the same string defined in the possible answer.
When we capture a vote, we store an answer as a string value, the same string
defined in the possible answer.

This will duplicate the answer strings many times in the database; however, given the expected early usage of this app and the fact that a UUID value can cost as much as many of these smaller answer values, this is an acceptable tradeoff for now. If we want to refactor, we can do so in the future.
This will duplicate the answer strings many times in the database; however,
given the expected early usage of this app and the fact that a UUID value can
cost as much as many of these smaller answer values, this is an acceptable
tradeoff for now. If we want to refactor, we can do so in the future.

To prevent recorded votes from becoming misaligned with edited answers, we'll introduce a publish event for a ballot, [making it non-editable by users](https://github.com/zorn/flick/issues/13).
To prevent recorded votes from becoming misaligned with edited answers, we'll
introduce a publish event for a ballot, [making it non-editable by
users](https://github.com/zorn/flick/issues/13).

0 comments on commit b170534

Please sign in to comment.