Tag: #coding

Story Stains: Full Stack Enums

Another post about building Story Stains, the previous one can be found at "Story Stains: Frontend".

Enums

Enums are a way of having multiple options programmatically, when a Boolean (true or false) isn't expressive enough. Think traffic lights: Red, Orange, Green, Http Status Codes: Unauthorized, Not Found, OK,..., and Countries: Germany, Poland, Great Britain, England? UK?...

Some things seem obviously able to fit into an Enum data type, until they don't. Emotions are what I was tackling. How many emotions can you feel when you watch a great film? Grief, Fear, Joy, Melancholy. The list may be large but it seems possible to do a suitable search in a dictionary or thesaurus and have a finite list, that's unlikely to change much. So I thought to use an Enum in my backend.

Database storage

How do you store an Enum in a database? Postgres actually supports Enums, but the backend is where the API lives so surely it should be stored there? I decided to use an extra table, I wanted to store a name and a description for each emotion, pretty easy. I'll then have the Enum stored in the backend so I don't need to do database lookups, clever right?

But if the backend is the ultimate source of truth of the enum, how do I keep them in sync? Write a little sync function! So I wrote a little sync function to keep the database in sync with the emotions on start up, easy.

My staging app keeps failing in the sync check...

More Data

Story stains is meant to be somewhat of a mood tracker for the stories you read or watch. What do mood trackers have? Cute little icons to represent the moods. So I need more info in the Enum, using strum I can add many more fields to my Enum, so why not one for an SVG location as well. I could store the whole SVG, but that would only make sense in the database, and that's not the source of truth is it?

Well, when I started adding the emotions to the review API, then I was doing joins on the Emotions table. So for that part of the API the Database table is the source of truth. My sync check seems a little silly now.

More emotions

The first twenty one emotions I decided on were rather extreme: Cruelty, Horror, Betrayal,Disgust,... Reviewing the subtle short story 'I stand here ironing', I'm not sure I felt any of those. I need more emotions, and preferably a quicker way to add them than refactoring an Enum and with a linked migration in the database each time. Time to delete some enums.

Story Stains: Frontend

Another post about building Story Stains, the previous one can be found at "Story Stains: Backend".

Flutter

Last year I took a in Angular from Udemy, but for this project as Angular appears to be slowly dying, I decided to use another possible Google dead-horse, Flutter.

This time I didn't use a book, or tutorial or such to start building the application. For one, I couldn't find a good up to date tutorial and I somehow expected a quite prescriptive development environment, which was not what happened. In retrospect, I think building the app as a pure HTML/CSS website first could have been quicker. Perhaps that's what I'll do for future projects, or even for this project's web frontend later.

From my anecdotal experience so far, Flutter appears to have a lot of developers from Asia and South America, unlike other tech communities heavily focused in the US. The community also feels smaller than rust considering the number of Medium articles or blog posts. Sometimes that's useful, as there are fewer answers to your googled questions, but sometimes annoying as they can not fit into your specific use case.

At the beginning I would take examples from the Flutter Cookbook, but I still ended up using an example project from f and CodeIdeal's realworld example for a larger architecture example. When I started trying to make the UI look like my sketches, I checked examples from the Flutter Gallery.

I didn't expect the level of complexity there is for frontend development, but there are several layers: Loading from the network, state management, User interface logic and the displaying UI. I have more respect than before for UI developers since there are so many decisions to be made. One of the first in Flutter is choosing from loads of state management libraries. I started with GetX but struggled with the lack of documentation and eventually swapped to using just the provider package. It seems like [Riverpod(https://riverpod.dev/) is becoming somewhat of a replacement for provider and should be looked out for.

Even with the new to me complexity, I'm still quite impressed with how easy it is to build in Flutter. From my git logs, it took me from 30th May to 9th June to with no flutter experience to have authentication, create, edit and read my initial API. With the material UI as an initial basis, it doesn't look like a dog's dinner either.

Some other problems are the lack of testing and documentation for all but the larger packages on pub.dev. Most examples written in blog posts, also lack tests. It can be a problem when looking for good test examples outside of the main Google supported packages. Many tests took me a long time to write, simply because I could not find a good example for a particular widget or provider. I'm also not sure about a sensible testing design pattern with the provider package, many tests I end up mocking unrelated providers simply so they don't fail on construction.

Story Stains: The Backend

Another post about building Story Stains, the previous one can be found at "Story Stains: An Idea forms".

Rust

I like to follow trends as much as the next guy, so I'm writing the backend in rust.

There were two main resources that I used:

  • 'Zero To Production In Rust' (zero2prod), a great book about building a backend service from scratch using actix. It's what I based most of my server code on. I enjoyed how each tiny step is broken down and that it's written in a test driven methodology.

  • RealWorld App, a community show case of examples in building a Medium clone. You can see code examples for the backend and frontend based on a single API. In particular a rust version by snamiki1212.

As I wanted to be mobile first, (most of my day to day is only phone after all) I didn't want to build a server side html renderer, as in zero2prod. So I used the API design from the RealWorld App to start.

I also swapped out the session based authentication from the zero2prod in favour of JWT. Likely, it's something I plan to change in the future for an oauth2 implementation. Although any article on Hacker News about authentication has many negative opinions on oauth2 complexity and the ease of badly implementing JWT, so that might change my mind. Generally, I enjoy using my Google account as a login, so I will aim for that in the future.

Mistakes

An aim of Story Stains is to teach myself programming a full stack application with deployment. I expect to make mistakes and learn from them.

One mistake was strictly following the RealWorld App's API design. All of the POST or PUT methods involve sending a wrapper object, i.e.

{
    user: {
        username: 'fred',
        password: 'totallynotarobot'
    }
}

Rather than:

{
    username: 'fred',
    password: 'totallynotarobot'
}

It led me to write, in both the backend and frontend code, a lot of similar into_inner() methods.

Another mistake is using actix or rust in the first place. I chose them because I wanted to learn rust and I enjoyed the zero2prod book, and I have learnt a lot. Often, however, I yearn for the readymade admin interface, pre made queries and ORM from Django. The rust and actix ecosystem doesn't give you nearly as much hand holding and requires you to spend a lot of time fitting parts together.

I found this apparent when adding the emotion feature to the API and found I was writing a lot of repetitive code. I will aim to refactor it out and aim for DRY (don't repeat yourself), but I'm essentially writing part of an ORM. For a one man band or small start-up, that's a lot of work.

Before I felt quite sceptical about no-low-code backends like Firebase and it's competitors, but I can really feel it's appeal. The want to focus on business logic rather than application logic is high.