The tech stack I choose to build my email courses project
Tech Stack I choose for my email courses project
Table of contents
- Programming language: Ruby
- Web framework: Ruby on Rails
- Persistence: SQLite
- Background running jobs
- Admin: Avo
- CSS: Tailwind and TailwindUI
- Import maps
- Views: ERBs and Phlex
- Static pages: Sitepress
- Debugging: Debug gem
- Asset pipeline: Propshaft
- Beautiful web UX: Hotwire
- Environment variables: direnv
- Code Quality: Rubocop + Rubycritic
- Code editor: RubyMine
- Versioning: Github
- Sending emails: Postmark
- Hosting: Hetzner and Hatchbox
- Analytics: Plausible
- Image storage: Cloudflare R2
I am building a new project: Ruby and Ruby on Rails Courses over Email.
In the beginning, I had to choose the tech stack for it. Here is an exploration of what criteria I considered, what I chose, and why.
When I think about the tech stack I want to use for this project, I have to consider the following:
The most important part is time. This is a side project; thus, it receives a small part of my effort. This is a fixed allocation that I can put among spending time with family, having a full-time job, and taking time for myself.
I think about time in two ways:
The time I have to build the project
The time I will have to maintain the project
Speed of change
The second most important thing is being able to change. That includes releasing new features or reacting to users’ needs or wants.
What’s important here is the speed of change: How fast can I release something to production?
On the third place are costs: hosting, emailing, and additional services used to build the project.
I have not yet allocated a budget for this project but will do so over the next weeks. Having a budget will help to validate if the idea is feasible and sustainable over the long run.
Programming language: Ruby
I am using Ruby. It is the language the I know best and it is also a language that allows me enough flexibility to write code that is easy to change and quick to adapt.
Web framework: Ruby on Rails
I am using Ruby on Rails. I briefly considered Hanami 2 as it is fresh, and I wanted to pick it up, but considering the time and speed of change, there is not much room to learn a new framework. At the same time, Ruby on Rails comes with a lot of battery included, and that is what I need in this project where I plan to focus on the product and content.
I am using SQLite. Ruby on Rails now has good support for SQLite in production, and Stephen Margheim has a lot of easy-to-follow and to-the-point articles for configuring it. Choosing SQLite reduces the time allocated to maintenance, so it is an easy win.
I am not concerned with scalability as I don’t see this project needing more than a server.
I also added the
Activerecord-enhancedsqlite3-adapter that adds support for generated columns, deferred foreign keys, PRAGMA tunning, and extensions loading.
For backup, I am using litestream gem, which makes working with
Background running jobs
I use litestack gem that comes with everything, including Jobs, Caching, Search, and Metrics.
I am considering for jobs to move to SolidQueue at some point.
I am using Avo to build the Admin UI that I will use to manage the content. Avo looks excellent; it is modern and fast, and I don’t want to spend time building a UI for myself to manage the content.
It is already built, it has a feel of Railsy while configuring it, and it is flexible enough so that if I need more custom things, I can do them.
The best benefit is that I get time back to invest in the content instead of the development of an admin.
CSS: Tailwind and TailwindUI
Rails 7 also comes with an already integrated Tailwind, and it works with import maps.
I like Rails import maps, and I am picking other UI-related gems only if it works with import maps. That is because I don’t want to run
nodejs or have any
node_modules installed. It adds to maintenance, and I like to minimize maintenance tasks.
Views: ERBs and Phlex
First, I will create the general views as HTML ERB files. This is because it is close to HTML, will have low maintenance, and can be changed quickly. It also helps with copying/pasting elements from TailwindUI without making too many changes.
I will organize (or extract) standard components by using phlex. Phlex is closer to my backend background, so I can keep writing Ruby while building UI elements.
phlex-rails has also a good integration with
Lookbook and so I can easily preview my components.
How I use this mix is like this: the general structure of the page is done with HTML ERB, but the elements inside are mostly done with Phlex.
I use Minitest, the default testing framework for Rails.
I like Minitest in my side projects for two main reasons:
It comes default with Rails and runs fast
It is not a DSL, but it is just Ruby code. So it will be easy to return to it and not spend time remembering a DSL.
There is one gem that I usually install for tests and that is
minitest-stub-const. Stubbing constanta can also be done without this gem, but I kept using this gem.
Static pages: Sitepress
For static pages, like homepage, or the blog section I am using sitepress. It has an easy integration with Rails and helps move from static files to dynamic options easily. I also like that it has Frontmatter support and comes with a way to work with each page’s meta-data.
It is a maintenance and low configuration solution: Install it, write things in
.html.md files, and all will work.
Debugging: Debug gem
Debug gem is now the default debugger gem for Rails, and I like it a lot.
A lot of development is happening, and new features are always added. I started moving away from
puts debugging to real debugging, and I even use the debugger to inspect object states while I do code design.
debug gem is part of Ruby, I think it can be a safe bet for the future with little maintenance or overhead required. I am using it in all my projects.
Asset pipeline: Propshaft
On multiple occasions,
propshaft mentioned that it would become the default in Rails, so I chose it because I think it will make upgrading Rails easier. I also like that
propshaft is simple and does one thing well.
Beautiful web UX: Hotwire
Of course, Hotwire is my choice for building web UX. It comes with Rails by default, and it has a lot of good integrations. It allows me to build promising web UX without the mental overhead of learning more JS or a new JS library.
When I need to write some JS, I like to use Stimulus because it gives me a place and a way to organize JS code. This is important for a project you don’t open daily to know exactly where to find each piece of code.
Environment variables: direnv
I started using
direnv a while back, mostly because I needed to share some environment variables between projects. So I can put a
.envrc file in the top folder for a group of projects and have those environment vars available in all subfolders.
It removes the need to use the
dotenv gem and also decreases the chances of accidentally committing your
.env file if you put the
.envrc in the parent folder and not the code folder.
I mostly organize my projects like this:
I can add the
.envrc file under
projects/shortruby/apps and have the common development environment variables shared between multiple projects.
Code Quality: Rubocop + Rubycritic
I use Rubocop to enforce a coding style that I like and made for myself. It is well-supported by any editor and allows me to configure it as I see fit. In my case, I lean toward using new Ruby syntax so the cops are configured to allow that.
I added to it the following gems:
rubocop-rails - “Automatic Rails code style checking tool”
rubocop-performance - “A collection of RuboCop cops to check for performance optimizations in Ruby code”
rubocop-minitest - “Automatic Minitest code style checking tool”
rubocop-capybara - “Code style checking for Capybara test files (RSpec, Cucumber, Minitest)”
rubocop-rubycw - “Integrate RuboCop and ruby -cw. You can get Ruby's warning as a RuboCop offense by rubocop-rubycw”
I also use Rubycritic to keep complexity low. I don’t refactor for every code smell, but it is good to have an excellent overview of what complexity each change might add to the existing codebase.
You can see how I configured all these tools in my article about First commits.
Code editor: RubyMine
I am using
RubyMine as my primary code editor with
IdeaVim plugin enabled. I worked with it quite a lot in the last few years and am fast when using it. Helps with debugging and go to definition.
I have some experience with both Github and Gitlab. But I think GitHub is a good choice here due to its UI simplicity. I don’t want to spend time in configuration and the UI/UX choices are great. The PR flow is quick and easy to set up, and for my needs, I only use GitHub actions to run simple tasks. I think Gitlab has a more powerful CI but I don’t think I need it right now.
Sending emails: Postmark
For sending emails, I choose Postmark. It is easy to set up and offers API-sending email and SMTP services.
I don’t know if Postmark will be used to send the course content. But it will be used to send all transactional emails related to the project.
I am considering ConverKit to write and send the actual email content. This will depend on their API support for the features I plan to build for my users: restart an email course, choose periodicity, and more.
Hosting: Hetzner and Hatchbox
I am using VPS Hetzner as they have a good price and being in EU it helps me with registering the invoice to my accounting.
I am using deployment Hatchbox for ease of use. I enabled automatic deployments to make a deploy with
git push - simple and effective.
I discovered Plausible while learning Elixir and Phoenix and started using it for all my side projects. I like the simplicity, and it is also a good price for what it is offering.
Image storage: Cloudflare R2
I started looking for an AWS S3 alternative primarily due to the time spent configuring IAM and other stuff that always needed to be done when setting up a new account.
I discovered Cloudflare R2 last year (cloudflare.com/developer-platform/r2), and I started using it. Again, I like the simplicity (it can be configured in minutes) and can be used for ActiveStorage. What I plan to build, where I will mostly upload and display images, worked perfectly and for an excellent price.
AWS S3 could be better for more complex tasks, but if the only need is to upload images and display them publicly while being a solo developer, the R2 is a good choice.
These are the tools I use and why I chose them to build the email courses project
I don’t think there exists a thing called “the best tech stack,” but depending on my knowledge and purpose, I can create an excellent tech stack to help me deliver fast and with good code quality.
Enjoyed this article?
🎥 Follow me on my YouTube channel for short videos about Ruby