Case Study: Hum - Policies made easy

Case Study: Hum - Policies made easy

Hum is a civics web app that gives a glimpse on the policy processes in Sweden. On Friday October 16 2020 the app went live. In the wake of its launch, this article will describe what the purpose of Hum is, as well as the development process behind it.

The idea for Hum came as a distilled version of a general task to build a civics app. In a blog post June 15th I wrote about sketching up an app. This blog post came to identify a need to focus on a civic competence of people who don’t regularly partake in political processes. Reflexivity came to be the focal point for the civics app. That meant that information should be delivered in a way that would put the receiver in the middle of it: “what would this information mean for me, the reader”? It also needed to be delivered in an easily understandable way, so its content needed to be held to snippets of information

A first sketch-up of the apps content is as shown in this image:
The calendar was held outside of the core of the app but was to be included as a reminder what policy processes ultimately were governed by the electorate. The theme component however is where the major of the content is. A theme steered the content. One policy, one institution and content for reflection was all to be held under the umbrella of a single theme. The theme would change every once in a while and so would the content for policy, institution and reflection. This umbrella came to be held conceptually as a “Hum” once the name was chosen. The component “From the archives” were scrapped at a later stage.

Choosing a name for the app was crucial for its identity and the design. Below are some initial sketches where I tried to identify additional components and some design considerations. In the image below there are many of the components that ended up in the final version: A theme introduction, some questions, a policy component with pro and con arguments, voting results for that policy, and an election calendar. These components would however see some fine-tuning.

Having an outline of the components and what they would contain, a name was chosen to nail down the app’s identity. In the blog post "A simple name for a civics app" I described how I chose the name Hum. The name works well in both English and Swedish and captures the values: fair, friendly and accessible. With this identity I returned to the drawing board and got another sketch, which I quite quick redrew. Here was the first Hum-design:
Second design draft.png 74.95 KB

This design is grey and cluttered, even though there is a lot of space. There is no clear visual hierarchy. It was a bit fun with talking bees but it was not more accessible this way. Realising that this design would not work I redrew it. The next design is more colorful and less cluttered. The visual hierarchy is clearer while having more content. Here’s the next design:
Final design draft.png 129.77 KB

Some colors would be changed from this design, and the header would be adjusted, but this is mainly how the final design would end up in production.

While I had a finished design I was not ready yet to start coding. What I needed was to identify the entities (or database tables) needed. This would be further complicated by the need to make entities able to be translated between languages. My initial entity diagram was as pictured:

A Hum entity would be the hub. Initially I thought to make a Hum instance reference another Hum to track different languages. The idea was to have a parent instance for English versions and each child represent a different language. What I ended up implementing was a version of this. Instead of a Hum having different versions I had the entities for theme, policy and institution implement this structure instead. This meant that each entity held its own translation - a structure that I thought was a bit cleaner. However it took me considerable effort to come to this solution.

With the database design ready I could start to develop the backend. My chosen technologies for this were PHP on Nginx, Symfony as MVC framework, Doctrine for ORM, MariaDB for database and API Platform for setting and managing API. This allowed me to publish the backend on a shared hosting I have used before and allowing for a quick and easy set up of API. Symfony also comes paired with Twig, a template engine, that I used for building an admin interface. The easy parts of this were building the entities and the API.

From a simple CLI for Symfony I could create the entities with their relations and mark them for API exposure. With all the entities created I could again use the CLI to create the corresponding database schema with Doctrine. The part that took most effort in building the backend was the admin interface. I built custom controllers to manage routes and CRUD instead of using the API. The API was to simply be used by the client-facing side of the app. Each controller (or route) was paired with views that I built with Twig. This also took me some effort but mostly it was just to insert the Symfony created forms in the right place. I did use some JavaScript in the Twig templates to handle when I would insert multiple images for blog posts, and in other places for some minor adjustments. At this point I had the backend finished. All that was left to do was the frontend.

I had planned to use React for the frontend. At first I had an idea to insert React through the Twig templates. I built up the skeleton of a React app inside the Symfony app when I drew the conclusion that this was getting too tangled in each other. I separated the React app from the Symfony app completely. The technologies I would use for the frontend was React Redux and Sass.

Redux is the state management solution where I would handle app wide state and actions. This would come in handy when switching back and forth between languages. React was a good solution to handle interactive components. Working out of the design that was the final draft made it easy to just add one component after another.

Once all the components were in place I took an afternoon to get acquainted with React Router for switching between the pages Home, Contact and About.

What took me the most effort in building the frontend was adding correct styles. Adjusting a style at one place would mean that I needed adjusting in many other places. One shortcoming of building the app from the design draft was that I had first made it the most appealing for desktops. This meant that when I started to make the React app responsive there were many things that I had to adjust for: Components needed to be moved from the sidebar onto the main column. The header was too high and took attention from the content when scrolling. To handle responsiveness I used CSS Grid for correct placement of components, and JavaScript to listen for scrolling to minimize header if needed.

The final touches came during launch week. That was when I used the plugin Lighthouse to audit the React app for accessibility and performance. This made it clear that some adjustments were needed: I paired labels with correct input fields, resized texts to be easier to read and converted font files from tff to woff for less network load. Performance could still be improved but I see a limitation in relying on API:s here. The web app could have been faster had I served the React app through Twig templates - this would have meant that the Symfony controllers could supply correct data directly to the app. However I like this way of separating the client-side from the backend.

Deploying the backend meant that the Symfony application was to be launched on a shared hosting. To do this in a secure way I split the codebase in two: public files were the only ones accessible from remote/public connections while the backend logic was placed in private space. This required that the index.php referenced the logical parts on their new path. The package.json was also updated so it would treat a httpd.www-folder as the public folder.

Once the backend structure was in place I created a database and ran a PHP script for Doctrine ORM to produce and insert the correct database schema in the production database.

Deploying the React app was as simple as updating the URL for the API and set the destination URL for the App itself. Then running 'yarn build' on the local machine produced everything needed. I used SFTP to move the needed files to the destination.

I am happy to have finished this project. It has taught me about design fundamentals, how to do a database design, setting up an API, and build a React Redux app that consumes this API. But most importantly it has shown that I can stick to a project and see it through. The next time I’m doing a similar project it will go smoother, but I’m sure there will still be challenges to learn from.

This has been a simple case study of my web app: Hum - policies made easy. If you enjoyed reading this please tell me or share this for others to read.