This article is about the tech stack I’m using for WingTask in 2022.
Language and framework for client-side web application
WingTask is a web application designed to provide a mobile client for Taskwarrior command line application. Making a web app behave like a native app is the reason I felt I needed to build an SPA, and after some testing comparing what it felt like using an SPA vs. a server side app I was convinced SPA felt more like a native app. After a lengthy evaluation and initial trial with React I decided instead to build WingTask with Elm. Elm is attractive in a lot of the same ways that RubyonRails is attractive, it provides a complete frontend stack with opinions. Elm had a steep learning curve in that I’d never worked with any type of functional programming language, but after the learning curve was surpassed, Elm became an advantage in that I can depend on it not to allow runtime errors. Errors do happen since a compiler cannot check for all types of correctness but I do appreciate that I deal with certain types of errors and not other types.
Progressive Web App
Set of W3C standards that allow web applications to behave more like native apps on mobile devices
I drank the kool-aid and elected to build WingTask as a progressive web app with the idea that WingTask would be installable to a phone or tablet and have a “mobile like” experience to the end user. I have mixed feelings now about this idea because it turns out that not being installable through an app store is a huge barrier to adoption. Google allows progressive web apps to be installed through the Google Play Store but apple does not allow the same in their App store. This isn’t the only difference between Google and Apple when it comes to PWA specs, the sense I got after seeing the differences between what Google supports vs. what Apple supports is that the entire idea of a web app that mimics features of a native app so that the two are indistinguishable is really an idea pushed by Google and pushed against by Apple. The reasons for this are not really that hard to understand just choose the most obvious one which is that Google makes money of web usage and Apple makes money off their devices and the native apps on those devices. Apple makes money and retains greater control by steering people towards native apps that It’s my opinion that the only reason they support any PWA features at all is simply to provide a talking point for anti-trust cases. The bottom line for me as a developer is that I feel caught in the middle of a conflict between two gods who have little concern for the ants they step on while they battle one another.
Set of W3C standards for creating and extending HTML elements
I feel like telling the world that web components are the most awesome browser standard that you aren’t using but I get a sense the world just really doesn’t care. Web components are the basic building block of WingTask. In fact WingTask is an app that really is a conglomeration of web components.
I wrote some in-depth articles about my use of web components.
Why Web Components Work For Me Ten Things on Using Web Components in Elm
Templating system for any type of file including HTML
Tailwind CSS & Tailwind UI
Utility-first CSS framework and set of components using that framework
TailwindCSS is the foundation of my design system. I chose to use TailwindCSS because I wanted a limited palette of CSS in the form of type scales, spacing scales, and pre-selected colors. At first I had some reservations about whether I would like utility classes “littering” my markup, but over time those reservations have melted away and I find the utility class method fits in well with my component based design philosophy.
I wrote in-depth about why TailwindCSS is foundational in my development process.
Why I’m Having So Much Success with TailwindCSS
TailwindUI is a paid library of components created using TailwindCSS. I like to use Tailwind components as a starter kit for getting me started quickly with building common things that an app needs such as alerts, buttons, and list views. I rarely use a component without changing it, and I feel it helps me get started faster.
Icons created by Tailwind labs
HeroIcons is an icon library created by Steve Schoger. I use HeroIcons because I find them extremly easy to work with since they are all available as SVG.
CSS Grid and Flexbox
CSS 3 web layout models
Flexbox / CSS Grid
Set of icons created by Tailwind labs
Creating a responsive mobile first application means being able to do some tricky things with layout. Mastering CSS Grid and flexbox was crucial to being able to feel like I could have a single layout that supports mobile, tablet, and desktop. The app shell for WingTask is using CSS grid. Components mainly use flexbox with some parts in CSS Grid, the ratio is about 85 / 15.
Front end style guide
The biggest game changer in my frontend development journey is Storybook. Storybook allows me to develop small atomic components that then get combined into bigger components until I have views for WingTask that are both responsive and support a wide variety of different states. Being able to develop all these different pieces discretely is key to making keep my sanity in this technological version of chinese plate spinning.
I wrote a couple of in-depth articles on how I use Storybook.
Storybook is an Essential Tool
Storybook and Elm
Server-side web application framework
WingTask backend is a RubyonRails 7 app that serves as the endpoint for data requests from WingTask frontend, recently the backend was converted from api only to a full-fledged Rails app in order to serve an admin section. Almost all requests to the api are passed through to taskwarrior via wrapped command line calls, and the responses are usually just passing the results (json formatted) as part of the response body.
Package manager for Ruby
I created a couple of internal ruby gems that provide a wrapper for sending commands to taskwarrior’s command line interface.
Web application server
I started using Passenger when it first came out so many years ago and it’s been the app server I use for all my personal projects because I never really have to think much about it. I know there are some faster app servers that can be tweaked for more performance and I always figured I would use one of those when Passenger wasn’t good enough and that moment never came.
Both the frontend and backend of WingTask are wired up to send errors to Sentry. I find Sentry does a good job of making it easy to capture unexpected errors, as well as present them in a way that makes it easy to figure out what fixes should be. Recently, I’ve noticed that it truncates error messages too much and I’m wondering what I can do about that.
Jenkins is the latest addition to the WingTask infrastructure stack. Right now it’s being used for continuous integration making it so that I can depend on tests to let me know if the app is behaving in ways that I expect. Eventually, I plan to expand the role of Jenkins so that it also deploys WingTask automatically.
It took me years to find the monitoring solution that I would stick with and Prometheus is the winner. Prometheus sends me an alert if any of my sites go down including checking that https protocol is working with valid certs. It monitors if I’m running out resources such as RAM or storage, and it’s setup to notify if any expected service such as Apache or Postgres goes down for any reason.
Age old webserver that gets the job done. I remember the rise of Nginx included many articles describing how it is a superior web server to Apache and I resolved that if some issue with Apache came up, then I would consider switching to Nginx, that moment never came now and my use of Apache is approaching two decades.
My stack may seem antiquated in that I don’t use containers and I don’t deploy to AWS or Azure. Included in my “not cool anymore” tools is Opscode Chef. Years ago I traded a good chunk of time in return for being proficient with Chef and I feel the bargain was a good one. I manage at most about 10 servers at a time. Chef is more than adequate to meet my small web app needs.
Sending email is a complicated affair these days and I’ll always happily use a 3rd party service provider like Sendgrid rather than deal with the lunacy of trying to manage it myself.
WingTask mostly stores persistent data on the file system because that’s how Taskwarrior stores the data. A postgres DB is used but just barely as it’s only a single table for users.
Source code management
Version control built by Linus Torvalds turned out to be a pretty neat thing.
Virtial private server hosting
Server hosting is paid out of my pocket so I try hard to make sure that I’m getting the most bang for my buck when it comes to hosting. Linode fills the role just fine.
Virtial private server hosting
I’m starting to migrate towards Digital Ocean from Linode because the prices are the same but I like the integration of services at Digital Ocean better. Eventually I want to get to a multi server setup behind a load balancer for WingTask
Zurb Foundation 6
Foundation 6 was the training wheels framework that taught me how to do responsive design. Eventually I mastered CSS Grid and Flexbox so that I no longer felt I needed Foundation.
The first version of WingTask used Material Design because it was an attractive way to get an initial version launched without having to take on the burden of the design. I had to concede that Material Design is a poor choice if you also intend to support IOS. Even google doesn’t use Material Design anymore for IOS apps. I eventually dropped Material Design in favor of building a custom UI for WingTask that was not so dependenty on the underlying OS.
WingTask used BEM to make sure class collisions never happened and for this purpose BEM was a success. After the switch to TailwindCSS the need for BEM fell away. I still use classes for CSS styling and JS hooks but the total number is so reduced that name collision is no longer an issue.
Sass figured prominently in the first version of WingTask, I like it quite a bit when compared to writing plain CSS. This is another tool I no longer use since my switch to web components and TailwindCSS.