5 min read

In this post, you will get a high-level overview of the theoretical part behind modern architecture of client-side Web applications, establish basic terminology, and define the main problem of Component-based software engineering.

You will be able to translate that knowledge on to real examples of component-based technologies, such as React and Angular, to see how they are different from Elm.

Components: the building blocks of modern Web UI

Component-based development is lingua franca of the modern frontend programming.

We have been using this term for years, but what is a component exactly?

The definition of Component

From Computer Science we know that Component is a software package or a module which encapsulates related functions or data.

Component, as a design pattern, originates from the traditional Object Oriented Programming. Component-based Web application consists of multiple components and some sort of infrastructure for component communication.

In a real world it is usually represented by a class, for example,  Angular 2 Component or React Component. Please, don’t be confused by Web Components.

Object Oriented Programming and Components

Traditional Object Oriented Programming, as a design pattern, focuses on building class hierarchy with a chain of inheritance. Despite the fact, that Component-based software engineering is still usingclasses, it prefers the composition over inheritance.

Modern Web applications usually implement an architecture that includes Components and an infrastructure for their communication.

The problem of distributed state

Components rely on classes, which contain mutable state as properties.

JavaScript is well known for the reputation of one of the mainstream asynchronous programming languages. Maintaining distributed state with many relations is hard when every piece of data is scattered around the components and it’s not getting easier when code is executed asynchronously.

Asynchronous state management is a hard task, which is getting only worse with the scale. Many of JavaScript libraries and ES2015 spec attempt to provide an experience of synchronous-looking code, while we’re actually writing asynchronous code, which often leads to a situation where we have a problem with promises.

Many design patterns are aiming on solving the problem of Component Communication with distributed state. Observer pattern is one of the traditional ways to establish Component communication in Component-based application.

From your frontend experience, you might be familiar with the three main types of Observer pattern:

  • Event Emitter
    EventEmitter from Node.js or Events mixin from Backbone.js library.
  • Pub Sub
    Not as widely used, because it requires you to follow certain architecture, such as  PubSubJS
  • Signal(often referred to as a Stream)
    See rxjs or xstream

Redux was a big game changer in state management with React, but any great power comes with responsibility. A lot of people have been struggling with Redux, which ledto a logical conclusion in the post by Dan Abramow You Might Not Need Redux.

The problem is that the functional patterns are harder to implement in a language that has a strong imperative side.

Elm Architecture

Elm application does not have components.

Primary building blocks are pure functions.

Minimal example of an application consists of three main parts:

  • Update function
    This is a function where you handle state changes; it accepts the current state and returns the next state.
  • View function
    Produces the output of your program; it accepts only one argument, which is the state of your application.
  • Initial state of the model
    This function simply returns the initial state of your application.

Technically, the whole Elm application is a component. It exposes a Signal or Reactive Stream API for interpretation with the outside world or other components.

State is a unified storage of all data in the application. Every stateful Elm application is built with a module called Html.App.

As of today, Elm’s main focus is on applications that produce a DOM tree as an output.

Stop thinking about components

Component communication is a term, which refers to an implementation of a certain infrastructure between two or more inter-operating classes with encapsulated state.

Elm Architecture composes update functions to form a pipeline for changing one unified immutable state, which is composed out of functions that produce the initial state.

Code splitting is not the same as componentization, you can have as many modules as you want.

You can check out an example of module composition in Elm on GitHub; it implements the so-called Fractal Architecture.

Practical advice on scaling Elm applications

Code organization should not be prioritized over business logic. Code splitting is rather harmful during the early stages of development.

Omit type signatures at the beginning. Without specific signatures you will have more freedom while experimenting.

Elm code is extremely easy to refactor, so you can focus on getting stuff done and clean-up later.

When refactoring, try to do one thing at a time; the compiler is extremely useful, but if you don’t define a limited scope for the refactoring process, you will get overwhelmed by compiler errors.

Elm is offering an alternative

Component-based development is lingua franca of the modern frontend programming.

Elm Architecture is a polished design pattern, which offers a lot of interesting ideas, and some of them are drastically different from what we are used to.

While component-based architectures, written in imperative languages, have their strong sides, Elm can provide a better way for implementing asynchronous flows. Function-based business logic is way more reliable and easier to test.

About the author

Eduard Kyvenko is Front-End Lead at Dinero. He has been working with Elm for over half a year and has built Tax return and financial statements App for Dinero. You can find him on Github at @halfzebra.

LEAVE A REPLY

Please enter your comment!
Please enter your name here