Majestic Monolith 2.0

Sean Walker
Aug 8, 2017 · 3 min read
A majestic monolith in Norway

Majestic is the monolithic web app lein template I created a few months ago, I’ve decided to change some things around in version 2.0, and here are the changes:

  • A focus on features over tech. Folders are related to features of your app, files are related to technology, and the file names are hilariously explicit
  • More separation between business logic (validation/prep before and after db interaction) and actual yesql functions.
  • SQL generation for CRUD

That’s only three changes but it’s still a lot to take in. Here’s some more detail.

Features over tech

The first thing is that folders that used to say components (views), logic (models + db), and routes have been turned inside out. So now you’ll see folders like this:

├── src
│ └── your-ns
│ ├── sessions
│ │ ├── html.clj
│ │ ├── http.clj
│ │ └── logic.clj
│ ├── users
│ │ ├── db.clj
│ │ ├── html.clj
│ │ ├── http.clj
│ │ └── logic.clj

This makes it much easier to find what you’re looking for.

How do I find where a user gets inserted into the db?

users.db/insert<!

How do I find where a user gets validated before that?

users.logic/validate

What function gets called when a new user tries to sign up, or what happens on POST /users?

users.http/create!

What happens when I visit /login?

users.http/form which calls users.html/form

That’s the other major change, instead of hiding technology behind different abstract words, I just call it what it is, routes are now http, models are db and logic files, and components are HTML. This makes it really straightforward to find out which part of the code does what thing.

Separation between database functions and business logic

The goal of this change is to separate code that acts on the data from the code that talks to the database. It’s better for testing, the less tests that rely on a database, the faster they go.

So before where everything was in one file, this time there are two files, db.clj and logic.clj. So for users, there might be some code to validate emails and validate that the password matches the confirm password on signup, that code goes in logic, not db. After the logic, the code that calls insert on the database is in db and is usually generated by yesql from resources/sql/users.sql. That part is kind of hard to follow, because it’s a macro defqueries that generates the functions from the sql, but I think the trade off is worth it.

SQL generation

Majestic 1.0 already had migration support through ragtime but this got a swift kick in the butt. There’s a few new command line commands:

lein db/migrate # this migrates the database forward
lein db/rollback # this rolls back the database one migration
lein db/migration name # this creates a new migration
lein db/crud table # this generates a yesql compatible sql file!

Better organization for more code generation in the future 😏. But the main thing is lein db/crud. This command generates sql for you! So let’s say you make a new table with

lein db/migration create-tags

Write the migration for creating your table

{:up ["create table tags (id uuid primary key, name text, created_at timestamp);"]
:down ["drop table tags;"]}

Then run the migration with

lein db/migrate

After that you’ll be pleasantly surprised to not write out a bunch of boilerplate sql because you can run this

lein db/crud tags

Now you have four functions that let you interact with your new table!

-- name: insert<!
insert into tags (id, name, created_at)
values (:id, :name, :created_at)
-- name: update<!
update tags
set name = :name
where id = :id
-- name: delete<!
delete
from tags
where id = :id
-- name: find-by-id
select *
from tags
where id = :id

Don’t forget to wire it up in tags/db.clj

(ns your-ns.users.db
(:require [yesql.core :as yesql]
[your-ns.db :as db]))

(yesql/defqueries "sql/tags.sql" (db/yesql-conn))

Wrapping Up

Those are the major changes in majestic 2.0, codename “towards a framework”. I’m hoping in majestic 3.0 to add more code gen that creates a basic set of files allowing you to crud a new table from the browser which admittedly will be very similar to rails, which I don’t think is a bad thing.

Sean Walker

Written by

Takes hikes ⛰ makes sites 👨‍💻

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade