My Journey in a UI Project (aka front-end is the new back-end)

In this blog post, I share my recent experience in a UI project, as a developer with limited past experience in UI development. I published this internally on REA Group's wiki a while back to foster interest in UI projects from a broader set of developers - highlighting that solid engineering is a big part of contemporary UI development.

This is not specific to REA, hence I was keen to share this journey externally on our blog.

A little bit about my background

Before joining REA Group (realestate.com.au), I had worked as a back-end developer on a number of large monolithic Java applications at different companies. At REA, except for more recently, I've been mainly involved in building Scala micro-services. My experience with front-end development in the past has been limited. Like most other back-end developers though, I’ve worked on projects which have had a mixture of back-end and front-end components; so I’ve occasionally used front-end technologies such as JSPs (a very long time ago), YUI, JSF, jQuery and AngularJS.

But for the most part, I had considered myself a back-end developer. When asked for example by recruiters in the past if I’m interested in front-end or back-end roles, I had always expressed interest in doing back-end.

Joining the realestate.com.au UI re-platforming project

A while back, I was asked by Alison Rosewarne (who was tech lead at the time in our team) to join a UI project as a lead developer. The project was to re-platform the realestate.com.au listing experience UI to a universal ReactJS application. I was initially very hesitant to join that team for various reasons:

I didn’t think I would be able to contribute much

Given my lack of front-end skills, I didn’t think I'd be able to contribute much in a UI-heavy project. My experience with CSS in the past, had mostly been something like this:

It usually takes me hours to make something on a web page look good, only to realise at the end that I’ve broken something else on the page.

To be honest, I didn’t think I would enjoy it

This kinda relates to my previous point. If you don’t think you're good at something, most likely you won’t enjoy it; unless you challenge yourself to learn it. I already felt challenged enough though with things I was learning in back-end projects at that point of time (elasticsearch, functional programming, etc.), so wasn't highly motivated to pick up something else.

I had a lot to learn

I felt overwhelmed by the number of things I had to learn to become productive in UI land.

NodeJS NPM Webpack Grunt
Jasmine Karma SASS Responsive UI
ES6 Babel ReactJS Redux

This list is changing all the time. New technologies replace the old ones much more quickly in front-end compared to back-end.

Despite all these, Alison suggested that there will be need for developers with experience in software design and testing in the team; there would also be a lot of Ops tasks that I can get involved in and enjoy doing. So we agreed for me to give it a try for a few months and re-evaluate.

And here I am, still in the same team after more than a year. And the interesting fact, which came as a surprise to myself, is that I’ve actually been really enjoying it. So I decided to share my experience here for those who might be in a similar situation, or those who haven’t considered joining a UI project.

In an ideal world, you would build features from back-end all the way to front-end as one team, and that’s the model we have tried here at REA in a number of projects with a team of individuals with mixed skills working closely together on both front-end and back-end tasks. Sometimes though, due to different reasons such as the size of the project, issues with team scale, or simply because the API hasn’t been built yet; you have to form a team only responsible for front-end, as we did for this project. Regardless of if it’s a front-end-only project, or a mixture of front-end and back-end, I think teams will benefit from back-end and front-end developers working more closely together.

What have I been enjoying doing in this project?

TL;DR

Never doubt your tech lead.

Many things about front-end development felt very different to my perception of it, which was based on my previous experiences in front-end projects. I'll cover some specific differences, which made this project very enjoyable for me in detail here:

JavaScript - ES6

JavaScript as a language itself has evolved a lot. Code written in ECMAScript 6 (the new version of JavaScript) looks very different to the JavaScript code I had written or seen before. You can read about ES6 features here, but some of my favourite ones are:

You've probably heard about the "JavaScript: The Good Parts" book and how people compare the number of good parts to the number of "not so good" parts.

JavaScript: The good parts

I think if someone was to write an "ES6: The Good Parts" book, it would look like this in comparison:

ES6: The good parts

Digitally modified image by Milly Rowett

ReactJS

ReactJS has been a major contributor to front-end development feeling similar to back-end programming for me in this project. My limited previous experiences with front-end development had involved:

  • Writing HTML in a dynamic templating engine (e.g. velocity, mustache, etc.)
  • Including sub-templates within parent templates
  • Fetching data in a back-end language like Java
  • Passing the fetched data to the top-level template and seeing variables get implicitly passed through to child templates
  • Using plain JavaScript or jQuery selectors to attach event handlers to DOM elements to make the UI interactive. These usually sit in JavaScript files separate from the templates.

Some problems I've had with this approach are:

  • Debugging how a piece of data used in a nested template gets passed down is usually very hard.
  • Finding the linkage between DOM elements and event handlers is hard. They're in separate modules after all.
  • Business logic and DOM manipulation code are usually mixed together. For example, the same event handler which sends a request to bookmark a listing, also adds a CSS class to an element to mark it as bookmarked.

I found that ReactJS addresses some of these issues for me and does even more:

Modularity and composability

In React, you define Components as JavaScript modules which accept input (a.k.a. props) and generate virtual DOM as output. Components can be composed by calling other components from the render method of a parent component.

UI templates and event handlers co-located

You can attach event handlers to DOM elements in the same Component which renders the elements. This provides coherence and makes the impact of event handlers local, unlike event handlers applied using jQuery selectors.

Explicit passing of props

Props need to be passed down explicitly from each component to child components. Defining a variable in one template/component doesn't make it magically accessible to all child components (unlike Velocity for example).

One-directional data flow

In React, you declaratively define your UI and update the data passed to the UI in reaction to events. React then re-renders the UI for you. Going back to my "bookmark listings" example, in a traditional UI application, jQuery or plain JavaScript would have been used to assign a "bookmarked" CSS class to an element once the user bookmarks a listing. However, in a React app, a "bookmarked" boolean data attribute is passed as a prop to the component and used to decide if a "bookmarked" CSS class should be rendered. When the user bookmarks a listing, React’s setState API is used to update the value. React then traverses the component hierarchy to determine which DOM elements need to be updated. No manual DOM manipulation code. Read more about this approach here.

There are more benefits to using ReactJS, but I'll leave it at that to keep this post short.

BEM and CSS Modules (a.k.a. sane CSS)

If like me, you've struggled with keeping the impact of your CSS changes contained to one element, don't worry; there are techniques and approaches like BEM and CSS modules to help you.

I'm not the best person to introduce BEM (Blocks, Elements and Modifiers) to you, but my naive understanding is that it defines rules and a structure for naming CSS classes to avoid clashes.

We've been using this approach in our new UI application. I overheard one of my colleagues explaining BEM to someone else like this:

BEM effectively provides a way to stop your CSS (cascading style sheets) from "cascading".

And isn't cascading the root of all evil?

More recently we've also started using CSS modules in some of our other UI codebases. I won't pretend that I can explain what CSS modules are, but if it does what it says (making your CSS modular), isn't it awesome?

JavaScript as a first-class language - Good practices/patterns applied to front-end

With technologies such as NodeJS, ReactJS and Webpack, we have been building UI applications which render both on server-side and client-side (a.k.a. universal or isomorphic). This means that we have been treating JavaScript as a first-class language, which has enabled us to apply the good practices and patterns well known in back-end programming to front-end. Apart from some obvious ones such as single responsibility principle, cohesion and modularity, there are some which I like to explicitly call out:

Functions as first-class citizens

Let's face it - unlike Java 8 where functions were bolted on the language in a not so convincing way, functions have always been first-class citizens in JavaScript, perhaps even more than prototype-based Objects. JavaScript developers find it intuitive to pass functions around as values or return functions from functions (higher-order functions).

The recent introduction of arrow functions in ES6 has made it easier to define functions. This in turn makes application of functional programming techniques such as currying easier and more pleasant.

I hear you saying "but functions are useless without types". I've talked about types below.

Design patterns

We are all more or less familiar with different design patterns and have occasionally used them in back-end applications. Good news is that we've also been able to identify where it makes sense to use design patterns in our UI codebase and have successfully applied patterns such as decorators, adapters and strategies. We've also used higher-order components (a fancy name for a decorator) in a few places.

Due to functions being first-class citizens, we've been able to implement known Object-Oriented design patterns in much simpler ways. Many of the patterns implemented in our codebase are just simple functions. Much nicer than the scary class diagrams you’ll see if you Google design patterns.

Immutability

ReactJS itself encourages immutability for better performance, and Facebook has open sourced a JavaScript library called ImmutableJS which introduces immutable data structures for use with or without React. Other libraries such as Redux, also encourage immutable data and pure functions for updating data. We use Redux in a few places in our codebase; and although we don't use ImmutableJS, we've embraced immutability mostly through use of ES6 classes with command/update methods which create new instances instead of mutating in place.

Types

Sure, JavaScript isn't a typed language, but there are a few ways you can benefit from some aspects of type systems in a JavaScript codebase:

  • ReactJS component can declare prop types. These are only checked at runtime in dev mode or while running the tests.
  • Flowtype (or TypeScript) can be used as static type checkers for JavaScript. We recently introduced Flowtype to our codebase and while it hasn't always type checked our code as expected, it's proven useful in at least documenting the interface of modules within our codebase.

Lots of things to learn

I mentioned earlier that one of my concerns before joining the team was that I felt overwhelmed by the number of things I had to learn to become an effective front-end developer. However, because of the excellent front-end developers in the team and across the company, I have been able to learn at my own pace. I can be confident that these knowledgeable people, who know how to "build UIs", are there to fill the gaps and help me to learn "how to UI".

If I go back to the list of UI things I thought I needed to learn, I can (shamelessly) say that I've only really managed to learn a few of them while I've been in this team:

NodeJS NPM Webpack Grunt
Jasmine Karma SASS Responsive UI
ES6 Babel ReactJS Redux

And that's fine. I tend to think that I've been able to contribute to the project and the team with my back-end knowledge and experience.

Lots more you might enjoy doing in UI space

Opportunity to contribute to open source projects

There are a lot of new tools/libraries in JavaScript and NodeJS ecosystem, some of which are still fairly immature. So there is a god chance you'll be able to find an open source project to contribute to if you're using any of these tools. We've had some examples of this in our team.

Writing tech blog posts

There is a very large community of UI developers out there and again, given some of the tools used in UI space are fairly new, there is a big opportunity for publishing technical blog posts around things that you would be using in your day-to-day job.

A number of blog posts have for example been authored and published by our team members on REA tech blog.

Solving problems unique to UI

Perhaps closely related to my point on learning opportunities, there are a lot of challenging problems which are unique to UI projects, which you wouldn't have experienced in back-end development. If you're after a new challenge, you'll enjoy getting involved in:

  • Web performance - Web performance is obviously a different kettle of fish compared to API performance. There is a lot to consider when it comes to performance of a web application, such as server-side vs. client-side rendering, size and number of asset files, lazy or eager loading of resources, code splitting (loading only what's needed for the current page), number of Ajax requests made, caching, third party code (we have a lot of them), etc.
  • SEO - A concern fairly unique to UI applications. There are many interesting things to learn in this space.
  • User experience
  • Accessibility
  • Complex technical problems to solve - Building large JavaScript-heavy applications is still fairly new at REA and possibly even outside REA. Unlike APIs you can't just break the code down into multiple micro-services, given the need to provide an integrated experience for the users. Therefore, there are complex technical problems to solve at scale in this space.

Final words

I still don’t consider myself a UI developer, I can’t do CSS for example or set-up a UI project from scratch; but I still found myself productive and have been able to contribute to our project. The point is you don’t necessarily need to know CSS or you don’t need to know a whole lot about HTML to make yourself useful in building a large UI application. There are always very good UI developers passionate about building UIs. You can pair with them and learn from them, while contributing your ideas from back-end. UI projects can definitely benefit from a close collaboration of developers with varied skill-sets.

And don't get me wrong. I don't mean to say that everything in front-end is shiny and perfect. Not at all. Having to deal with both null and undefined would still make you want to cry and NPM and shrinkwrap will most likely break your heart on your first date, until you break up with them for yarn.

Despite some shortcomings, it's been a pleasant ride for me and I hope it will be the same for you.