Two majestic monoliths being majestic together and my car. I like clojure. I also like , and . The clojure community has made a ton of great libraries that are all very simple. Unfortunately when I started putting them together, it took me a lot of time to understand the different decisions each library author made and how they worked together to get to a place where I had a working scaffold for my own full stack . I had some success doing this, but it still felt like I was playing catch up to all the great stuff other communities had. Not to mention every time I needed something else, like server reloading on each request, or refreshing code from the repl, it was another dependency and another namespace and another set of docs to read. So after slapping dependencies together in my for the nth time, I made a clojure library and a leiningen template to help me launch projects faster. I should warn you, the first time I’ve tried this but it is the most comprehensive one, and maybe I can convince some great clojure devs to help me out. noir luminus create-react-app rails bespoke framework programming project.clj this isn’t What do you get out of it? A single namespace for (almost) everything: (:require [coast.core :as coast]) Pretty good postgres support Conventions, not configuration ( ) this sounds familiar HTML helper functions (link-to, form-for… and that’s it for now 😐) A beautiful ⎍ majestic monolith What don’t you get? Microservices (never) Background Jobs (yet) Datomic/other data stores (yet) Clojurescript (maybe) Javascript frameworks ) (never Spec (yet?) Some kind of integrated testing (or something) (yet) What does a basic example look like? You can try it without the lein template if you want, just do this from your terminal: mkdir simplecd simpletouch deps.ednecho '{:deps {coast {:mvn/version "0.6.1"}}}' >> deps.ednmkdir srctouch src/simple.clj Then fill in simple.clj with the code below It’s just clojure functions and maps built on top of existing libraries! That’s right, coast is not only a clever to rails, it’s also me on the hard work of others! There’s a whole long list of libraries made and maintained by super talented developers that coast uses and gives credit to in the README. homage literally coasting Run the above code with and now you’re ready for WORLD DOMINATION. Compete with google time? ✅ ✅ clj -m simple What happens if you start a fresh project? Now this is where the lein new coast your-proj stack gets really full. ├── Procfile├── README.md├── profiles.clj├── project.clj├── resources│ └── public│ ├── css│ │ └── app.css│ └── js│ └── app.js├── src│ └── your_proj│ ├── components.clj│ ├── controllers│ │ ├── errors_controller.clj│ │ └── home_controller.clj│ ├── core.clj│ ├── routes.clj│ └── views│ ├── errors.clj│ └── home.clj├── target│ └── classes└── test└── your_proj└── core_test.clj The default template is chock full of good stuff. I’m going to start with the aliases which should probably live somewhere else but for now they’re in your project. Deal with it 🕶. Postgres Database Aliases lein db/createlein db/droplein db/migrationlein db/migratelein db/rollback You can probably guess what’s going to happen when you navigate to your newly created project directory and type these things in. is going to create a new postgres database with a name like . will drop this database. runs all migrations that haven’t run yet, rolls a migration back one at a time. will create a new migration file in like this: lein db/create your_proj_dev lein db/drop lein db/migrate lein db/rollback lein db/migration create-posts resources/migrations/{timestamp}_create_posts.edn -- upcreate table posts (id serial primary key, title varchar(255) not null, body text not null, created_at timestamp ); without time zone default (now() at time zone 'utc') -- downdrop table posts; So the goal is to follow rails conventions, plural names for tables, id column for primary key, created_at timestamp. So far things are pretty straightforward, and that’s boring so this is where things get kind of weird and start to diverge from rails quite a bit. , so the models happen in two parts across two files. There is no ORM here, only a VRM MVC: Models There are no objects, no methods, and no dynamic sql generation (kind of), only static. Which means you have to write sql yourself. But it’s ok, coast has your back. OH NO! lein sql/gen posts This command takes the name of a table and generates sql in . Which looks like this resources/sql/posts.sql _-- name: all_ * posts created_at **desc select from order by **_-- name: find-by-id-- fn: first_ * posts id = :id select from where id = :idreturning * -- name: where-- fn: first where This SQL is just sitting here, doing nothing. Now it’s time to generate the “model” which is just a file with regular clojure functions. lein model/gen posts Which will create a new file: : src/my_proj/models/posts.clj Yay functions for the database! That’s pretty much all there is to the models, I would like to add some spec-driven validation, but I haven’t done that yet, so that stinks. MVC: Controllers Controllers are just like they are in other full stack frameworks, functions that glue your models and your views together. lein controller/gen posts Gives you this: It’s all regular forms POSTing form data to the server and then redirecting. Just like pappy used to do! I might try to make a generator for RESTful or maybe GraphQL endpoints in the future, but for now, things are just going to have to be fast and simple. MVC: Views Usually I just pass the whole request map into the view functions, which kind of kills separation of concerns, but I’m ok with that for some reason. Here’s what a generated view file looks like: Who’s concerns are they anyway, am I right? lein view/gen posts Pretty basic 💁♀️ In the end This is a good starting point for something like a “full stack” clojure framework. Definitely not as robust or simple as something like luminus, but it might just be easier mostly because it’s early days and there’s no clojurescript (or javascript framework, which is a huge plus) and just one supported database… there’s a lot to do still. I don’t have a grand plan for this thing other than I want there to be multiple options when considering clojure web development, not just luminus, libraries or GTFO 👋. Hopefully coast on clojure won’t be the simplest option, but it might just be the easiest option. I’ve already made a few sites with this framework, of course none of them have had any traction yet 😢 (that’s classic me), but it works for the most part. Give it a shot! Coding clojure is great, but sometimes you just need to get outside and disconnect. That’s why I’m making (using coast), it’s a list of the best places to get away, get out of your comfort zone and get outside. outsidelist.com