Giving the shoemaker shoes

I built this site because I'm a software developer. Like many software developers, I do a lot of work on web based applications. Unfortunately, many (but not all) engineers don't have a website of their own. That used to be me.

We build web apps with Single Page Application (SPA) frameworks these days. Then, we use static site generators to turn them into multi-page, static websites. Well...isn't that lovely. While I do think the SPA approach is an improvement over the architectures that preceded it, count me amongst the many skeptics of it's long term viability. Its reign as the de-facto way to build web apps won't last forever. In any case, this being 2020, I've chosen to build this thing using the tools du jour, and that includes the following:

  • Typescript
  • React
  • Emotion and react-spring
  • Gatsby

Typescript

Of the five items listed above, Typescript is the most important to me. So, this section is going to be the longest. I think Typescript has the most potential to endure for decades, as opposed to years. The Javascript ecosystem is notoriously fickle. Today, in 2020, React feels like the gold standard of web development tooling. It's easy to forget that it was released in 2013. That was 7 years ago...an eon in Javascript time...but not very long in the grand scheme of things.

What few people realize is that Typescript is actually older than React. It was open sourced in 2012. React surged in popularity in 2015 when large companies like Netflix and AirBnb adopted it. On the contrary, the Typescript hype train didn't depart until recently. But now that the train has left the station, it's accelerating rapidly.

The static vs. dynamic type checking dichotomy is about as old as computer programming itself. LISP, widely accepted as the first dynamically typed language, was created in 1959. That's just two years after FORTRAN, possibly the oldest language still in use today. And Typescript is far from the first attempt to bring static type checking to the web. Coffeescript, Elm, Dart, and Scala.js are just a few of many alternatives for those wishing to write statically checked code that transpiles to Javascript, and thus can run in the browser.

Two things make Typescript different. I'm not sure which is more important.

Syntax

The first is that Typescript "start's from the same syntax and semantics that millions of javascript developers know today" and "compiles to clean, simple javascript". That means that both Typescript source code and the code emitted by the compiler can be easily understood by anyone who knows Javascript. Javascript is already assuming a larger and larger role in every website, by virtue of the SPA approach I mentioned before. In 2020, front-end developers are Javascript developers. When it comes to adoption by the existing community of developers targeting browsers, being as close to plain Javascript as possible gives Typescript a distinct advantage over the languages mentioned above.

Flexibility

The second is Typescript's approach to static type checking. Typescript is a gradual type system, which means that some variables and expressions can be statically checked at compile time, while others can be left untyped and checked at runtime. Type checkers should to help engineers, not hinder them. Typescript's checker can be told to "go away" when its user can't wrangle the type system to their liking. That is not the case in most other languages. Python, from version 3.5 and later, supports a similar approach entitled type hints. It has a much lower barrier to entry, since there is no transpilation step. One can choose to write type hints or not. The Python interpreter ignores the extra syntax, and separate tooling can be stood up to do the type checking. Python, however, doesn't run in a browser (yet). So for now, those of us targeting the web have to make other choices.

I could say more about Typescript. The decisions that team has made with regard to soundness and completeness, as well as structural vs. nominal typing, are fascinating. In the end, however, the point is that we all want to maximize productivity and minimize bugs. Typescript helps, and that's all that matters.

React

For many, React is considered the top framework for front-end development in 2020. Angular and Vue lurk close behind, with Vue gaining momentum quickly. React is my favorite, and the one I have the most experience with. So it was a simple choice to use it for this project.

I've only built small, toy apps in Angular. I have had the opportunity to do substantial development in Vue over the last year. In fact, a post entitled "10 things I like and don't like about Vue" is high on my list of things to write about in the immediate future. Vue 3 might change things a lot. It's written in Typescript, supports JSX, and has a composition API similar to that of React's hooks. So, take the next few points with a grain of salt.

JSX

The main point of distinction I see with React is its approach to templating, or lack thereof. JSX was controversial when React first gained notoriety. In fact, it was my main point of hesitation when I started. Angular and Vue both use template engines to add Javascript "directives" to HTML. JSX is the opposite. It extends Javascript with syntax that looks like HTML. In short, templates add Javascript to HTML, JSX adds HTML to Javascript. The template approach in Angular and Vue is actually quite similar to the template approach of the MVC frameworks that preceded SPA's. Before I wrote Javascript apps, I worked on large enterprise web apps written in Java. The frustrations I encountered with Java Servlet Pages (JSP's) are the same as the ones I have with Vue and Angular templates. JSP's, in short, add Java to HTML. With all templating engines, the issues are the same:

  • It's not obvious what variables are in scope, and thus can be referenced in a template.
  • When things go wrong, template problems can be very hard to debug. Error messages typically come from the template engine itself, and thus can't be as accurate as messages thrown in user code.

JSX eliminates these issues. For those reasons, I personally find JSX to be a refreshingly unique take on a problem almost as old as the web itself.

APIs

React has always left important concerns such as routing and state management outside of the scope of the library. This has significant downsides. Routing and state management, in particular, are non-trivial aspects of any SPA. While "de-facto" solutions such as react-router and redux have emerged from the community, the fact that the React team itself does not maintain these projects causes real headaches in the real world. It's a legitimate reason not to choose React for a project, and in my opinion the library's biggest weakness.

That being said, recent releases have made things much better. The Context API released in React 16.3 does a lot for state management. In my last production React project, it was the only thing we used for state management. That says a lot about the quality of the API design.

The way we managed state in that app, however, would not have been possible if not combined with the hooks API released in 16.8. The hooks API is at minimum a unique approach, if not a groundbreaking one.

All three major libraries began with a class-based pattern whereby users extended from a base Component class provided by the library. Additionally, all three use some sort of component "lifecycle" API to impact the behavior of a component when different things happen. For instance, when it is loaded into the page, when it receives new values, and when it is removed from the page.

Hooks do away with both of those things in favor of something the React team claims is more re-usable, and more of a natural fit with the Javascript language. I agree on both fronts. I've never felt comfortable writing classes in Javascript. The language does not follow a classical inheritance model, and attempting to force it to do so causes all kinds of awkwardness. The handling of the this keyword is the classic example (pardon the pun). Component lifecycle methods are easier for beginners to understand. However, in many cases related business logic crosses the boundaries of those methods. Thus, they present an overt barrier to sharing said logic between components. The hooks approach changes both of these things, and I find that refreshing.

Emotion and react-spring

CSS-in-JS (or...CSS-in-TS)

I am a fan of CSS-in-JS. We are already writing Typescript, which transpiles to Javascript. Well...we're Typescript with JSX, which transpiles to Javascript with JSX, which transpiles down to more Javascript, which emits DOM. We live in a crazy world, so we might as well write Javascript that emits CSS too, because, well, who the hell cares at this point anyway? The thing I like about CSS-in-JS is that is can also be CSS-in-TS, which can be statically checked at compile time. See my rant on Typescript above.

Throughout this project's source I use Emotion's support for writing CSS styles as Javascript objects (as opposed to string interpolations). This allows me to statically check my styles. I can leverage the CSSType project to ensure that I'm using the right values for the right properties, and that is great for someone like me, who is far from a CSS expert.

There are some serious downsides with this approach. Writing CSS using Javascript syntax is...awkward. Even for someone without years of experience in the CSS ecosystem, there is just something strange about writing a selector as a Javascript key. '> div': { ... } just looks odd to me, and I'm sure it looks even weirder to a designer. In a team of any size with good designers and experienced front end developers, I would still use CSS-in-JS, but with the string interpolation style. It might not be as "strongly typed", but it's much easier for those with CSS experience to read the CSS that lives within those backticks. Furthermore, it would be less of a leap to take those strings and turn them into raw CSS in the case one wanted to depart from CSS-in-JS.

In any case, using CSS "objects" was an educational experiment for this project.

Animation

For animations, I'm using react-spring. I am no animation expert. What I've done in the past has always been minimal...just enough to give the app some polish. I find that styling an animation in a component frequently requires more lines of code than the rest of that component's styles combined. Using react-spring makes writing animations feel more natural, while also keeping the animation concern somewhat separate from the plain styling concern. I like that.

I shouldn't say too much more in this blog post, however. If you want to hear more of my opinions on the topic of styling web apps, you can check out my talk from Philly ETE 2020, with the guy who taught me everything I know about the subject.

Gatsby

Frankly, I don't have much to say about Gatsby at this point. The community support seems great, it seems quite mature, and things are working well so far. I'll just hearken back to my previous point. I know I'm not alone in my suspicions of the fact that in 2020 we are writing SPA's in Javascript frameworks just to turn around and generate static sites out of them. Call me crazy.

This is in no way critical of the creators and maintainers of the Gatsby project. From what I can tell it's a great project and a great community. The documentation is fantastic. There is a well-maintained plugin for nearly every adjacent requirement I can think of (such as deploying to AWS S3 and Cloudfront). And there is a long list of well-known companies that are running it in production. Those are the tell-tale signs of a battle-tested technology.

so are they sandals, sneakers, or ski boots?

In the end, as engineers, we build to learn. That's what this site is about. Hopefully the stack I've chosen will stand the test of time. I am fully prepared for it not to. That is not an indictment against the technologies, but an admission of the world we live in as web developers. It would have been an interesting exercise to use nothing but pure HTML, CSS, and Javascript because, frankly, I've never built anything that way either. In any case, it's been fun, and I'm looking forward to using this as a vehicle to write about the things I'm interested thatdon'tinvolve web pages. If you've gotten this far, thanks for reading! Whether you agree or disagree with any of the above, I'd love to hear from you, so please go ahead and reach out.