A Majestic Monolith in Clojure

Datetime:2017-04-18 06:10:00         Topic: Clojure  JavaScript          Share        Original >>
Here to See The Original Article!!!

Usually sequels are horrible, but sometimes they turn out ok. Hopefully this will be closer to the latter.

The web can be a beautiful place with a hint of javascript, not too much, not too little. Kind of like salt in good, home cooking vs. the sodium extravaganza that is fast food. There’s something great about server rendered HTML and something like turbolinks . It’s just fast enough to give users the experience they want, and the code is so simple it gives devs the experience they want.

There’s a yuge difference between large software companies like Facebook or Google and indie hackers like me. What works for a large company isn’t going to work for me and why would it? The constraints in large teams of software developers are much different than the constraints when you’re just hacking trying to get a customer or two. Usually large companies have existing products to try to improve without causing regressions, so the goals there are correctness and communication among the large team. Indie hackers like myself are mostly concerned with speed and time to market, with a few weeks of nights and weekends being all the time we can spend on trying to validate our businesses ideas, serve customers and get a single one to pay up.

This is where majestic-web comes in. It starts to mirror rails even more than that other thing I wrote. Although the names might have changed to protect the innocent and there aren’t any generators (macros?) yet. Let’s take a look at the new structure.

your-project-name
├── Procfile
├── README.md
├── profiles.clj
├── project.clj
├── resources
│   ├── migrations
│   │   ├── 20170410191739_add_hstore_ext.edn
│   │   └── 20170410191739_create_users_table.edn
│   └── sql
│       └── users.sql
├── src
│   └── your-project-name
│       ├── components.clj
│       ├── core.clj
│       ├── db.clj
│       ├── env.clj
│       ├── logic
│       │   ├── sessions.clj
│       │   └── users.clj
│       ├── middleware.clj
│       ├── responses.clj
│       ├── routes
│       │   ├── home.clj
│       │   ├── login.clj
│       │   ├── logout.clj
│       │   └── signup.clj
│       ├── routes.clj
│       ├── server.clj
│       └── utils.clj
└── test
└── your-project-name
├── db_test.clj
├── logic
│   ├── sessions_test.clj
│   └── users_test.clj
└── server_test.clj

So the main difference between the majestic lein template which, in hindsight, was poorly named and majestic-web which may also be poorly named is that the whole stack is represented here, not just a RESTful API. That’s right it might seem like heresy in 2017 but the server is using hiccup to respond to compojure routes with *gasp* full pages of HTML . There are quite a few things missing from a project generated from this template:

  • GraphQL/Relay/Falcor/REST
  • React/Preact/Inferno/Angular/Vue/Marko
  • Webpack/Babel/Rollup/Google Closure/Browserify
  • Typescript/Flow
  • Clojurescript/Elm/Scala.js
  • Microservices/Kafka/Queues/Containers
  • Docker/Orchestration/Kubernetes

And without the additional complexity of all of those things you as an indie hacker can move very quickly toward what I imagine is your goal of getting a web app up and running, ready to delight and take payment from any and all potential customers.

Let’s take a deeper dive into the structure. There are a few files here that are a little different than traditional MVC which will hopefully help you move faster.

I do like one thing about react, components. Small reusable components do help you move faster, it’s just that it’s all wrapped up in javascript tooling, configuration and the virtual dom. Virtual DOM by the way is another thing that isn’t in here, thank goodness . Components are essentially partials on crack, more reusable in more places so you don’t have to think about styles and can layout a page really quickly in hopefully both mobile and desktop browsers.

Small functions that return hiccup!

Routes basically amount to a system wide description of which urls people can visit and which ones require auth.

All application routes are here

Routes basically amount to a system wide description of which urls people can visit and which ones require auth.

Each route has file in the routes folder and a function for each get/post request. Another thing that’s kind of unnecessary here, this idea that http methods map to database functions, we don’t need REST where we’re going, only GETs and POSTs.

Here’s what the whole app looks like, middleware and all:

How many times can you type the word “middleware”

There are three functions for restarting on code changes from the repl for when wrap-reload can’t get it done on each request, and then there’s the run! function which is what gets run in production. They’re pretty similar, but I kept them separate because I don’t always want the app hanging out in an atom in “production” and I do want the app to force ssl on every request.

There’s some more stuff in there, middleware, tests, responses, utils, but that’s pretty much it, not a lot to it, really.

Here’s a good guide on how to get up and running with this quickly:

# Develop
lein new majestic-web majestic
createdb majestic_development
cd majestic
lein migrate
lein repl
# Wait for it...
(start)
# Deploy
heroku create majestic
git push heroku master
heroku addons:create heroku-postgresql
heroku config:add SECRET=$(openssl rand -base64 8 |md5 |head -c16)
heroku run lein migrate

Letting go and admitting that react.js and most other newer web technologies are unnecessary for a struggling indie hacker was hard to do. But once I did, sales, marketing, content, design, everything became easier, and I could move alot faster.

Let’s make the web great again.








New