Quantcast
Channel: Hasen Judy
Viewing all articles
Browse latest Browse all 50

Tools for Front End development

$
0
0

Front end development on the web can seem like a big mess. So many different libraries and frameworks.

This is my preferred toolset:

  • RequireJS: module system
  • LoDash: functional programming helpers
  • RSVP.JS: Mature Promise API
  • KnockoutJS: UI state management and reactive programming
  • DurandalJS: url routing and composable/reusable Knockout components (plus a dialog system and a pub/sub (events) system)

These libraries form the basis for almost any project I work on nowadays.

There are other libraries I use as well, but they are not as fundamental.

Craftsmanship

Software development is a craft. A craft is first and foremost about creating things that will serve some purpose.

Sometimes, you can find something that almost does what you want, and you just tweak it a little bit to suit your particular need.

Most of the time however, you have to create it almost from scratch. This applies to front-end development as much as it applies to back-end development.

If you think web development is mostly about gluing things together - things that other people have created - without you having to understand much of what’s going on and how things work, then this post is really not for you, and in all honesty, I think you will have a hard time trying to advance in the software development field.

As a craftsman, it’s your job to figure out how to create things even when there isn’t already a library/framework that does what you want. This doesn’t mean that you always work from absolute zero, but you should be comfortable going “down and dirty”; implementing the underpinnings (the low level details) yourself.

As such, what the craftman needs is not necessarily a framework, nor does he need a set of components (although that would be nice to have).

What the craftsman ultimately needs is tools that can help him build his own components (and his own “frameworks”, if necessary).

Good tools are the ones that help you by solving the common problems you face in your daily work. They should give you just what you need, and then get out of your way so you can focus on your work.

A bad tool can often get in your way, making your job more difficult than it needs to be. Worse, sometimes a bad tool will set an upper limit on the sorts of things you can do.

Most of the time, a few good tools will give you far more power and control than any framework ever could.

Good frameworks tend to be the “minimalist” types. Ones that are built on top of other components which you can use outside of the framework. (Example: Flask, being built on top of Werkzeug and Jinja).

Popularity and Trends

Do not assess tools by how much buzz they generate on the web. A lot of it can be due to pop-culture.

AngularJS for example is, in my opinion, one of the worst choices out there. It seems to me that its architecture is rather poorly thought out.

I do recognize its popularity, but I susepect it’s mostly because:

  • It has the Google name behind it.
  • It makes simple things look too easy.

Beginners like to jump on it. It’s the new VisualBasic.

I suspect that a contributing factor to its “popularity” is simply people not knowing how to use it; both because most of them are generally beginners, and because it’s overly (and unnecessarily) complicated. This means a lot of activity on stackoverflow.

At any rate: be careful about assessing a tool merely by its popularity. In general you should question popular trends. This also applies to things like “bower” and “yeoman” as well.

Always ask yourself: does it solve a real problem you always face? What pain point does it alleviate? What pain points does it introduce? What are the trade offs?

Ease of use - Complexity

For a tool to be good, it doesn’t necessarily have to be easy to use. What actually matters in this area is that it should not introduce unnecessary complexity.

Good tools can still have parts that seem “confusing” or “difficult to grasp” at first. That’s completely ok, as long as the tool doesn’t get in your way once you understand how it works.

Sometimes the solution to a problem requires introducing new concepts that you must get acquainted with. This means it might take you some time to absorb these new concepts and learn how to utilize them.

A tool can still be great even if most people won’t be able to be productive with it “from day one”.

In fact, I’ve found that many people have endless complaints about the good tools; they want something that works magically without them having to put any thought into it. (This is ok to think for an end user, but not ok to think for a craftsman).

Git is an example of a great tool that many people find difficult to use at first. This is because these people don’t want to put the effort to learn it.

Git’s genius is that it’s built on simple concepts which can be understood easily - a couple of hours of reading and thinking.

See: Git from the Bottom Up | Original PDF | Mirror PDF

When you understand how it works, it becomes unfathomable to you why people complain about git’s UI.

Git doesn’t set upper limits on what you can do. If you want to make a partial commit, it’s possible (thanks to the staging area). If you want to re-write history, it’s possible (thanks to the commit object model).

Vim is another great tool, but it probably takes about a week of practice before you can start noticing any gains. (So if you ever want to pick up Vim, I recommend starting with a “regular” editor that supports some kind of Vi(m) emulation, such as “Sublime Text”).

Practicality

Bad tools introduce unnecessary complexity, in the form of concepts that are born out of over-engineering or just out of not understanding the problem space very well.

A good example of this is Angular’s system of modules, services, controllers, directives, etc. You know these concepts are superfluous because they get in your way instead of helping you.

What you need from a module system is simply 1) a way to isolate your code into modules, and 2) a way for a module to declare and load its dependencies.

Angular’s over-engineered moduels system doesn’t do any of these two points well. Instead, it’s designed to cater to some particular ideology about how code should be organized into services and factories, etc.

A good tool should make simple things easy enough, and make advanced things possible (without adding unnecessary complexity).

In order to be able to evaluate whether a tool is good or bad, you must have a decent understanding of the problems at hand.

This means you must first try to do everything manually. Take the “down and dirty” approach, and manage to produce results despite all the problems.

Only through this kind of experience will you gain an appreciation of what the problems are, and only with such appreciation will you be able to make reasonable assessment of what sort of tools you will need.

Functional programming

Javascript might be a terrible language, but it has some good parts. One of the best parts of Javascript is functional programming. Embrace it. Learn how to leverage it. It’s an extremely important foundation for solid front end development.

It might be interesting to note that some of the greatest tools for web development leverage functional programming techniques.

Start with this excellent article by Joel Spolsky: Can Your Programming Language Do This?

If you don’t understand functional programming, you’re missing out. You won’t be as effective as you would be otherwise. I highly and strongly recommend you immerse yourself learning functional programming if you’re not familiar with it.

Functional programming lets you write very clean code, where you can:

  • Isolate complex behavior to small components.
  • Handle cross-cutting concerns without introducing coupling.

Justifying these claims is a little out-of-scope for this post, but as food for thought, look at the memoize function from lodash, and try to think of how it could be implemented without any use of functional programming techniques (for example, in Java, prior to version 8).

Modules

One of the biggest areas lacking in Javascript is a module system, and as a result, the default method of managing code is to split it into multiple files and include these files in the header or body of index.html in the correct order; which is ridiculous.

I recommend RequireJS:

  • Isolates your code into separate “scopes”. (make sure you use var everywhere you declare a variable so you don’t pollute the global scope).
  • Requires no special compilation step. Works directly in browsers and you can start using it today.

The fact that you can build a module system out of other language features is quite interesting, and speaks volumes about the power you can have if you know how to wield the good parts of Javascript.

What would your modules look like when you use requirejs?

Let’s say you configured requirejs to look for modules under “/app/”. The following is a contrived example with two modules, A and B, where B depends on A.

app/A.js:

define(function() {
    var A = {}; // this module;
    A.log = function(message) {
        console.log(message);
    }
    return A;
});

app/B.js

define(function() {
    var B = {}; // this module;
    var A = require("A");
    B.check = function(condition, error) {
        if(!condition) {
            A.log(error);
        }
    }  

    return B;
});

I don’t want to turns this into a requirejs tutorial, but just for completeness sake, this is what your index.html could look like:

<head>

    .....

    <script src="/libs/require.js"></script>
    <script src="/rconfig.js"></script>
</head>
<body>
    ....
    <script>
       // manually load the entry point
       require(["main.js"]);
    </script>
    .....
</body>

That’s at least the approach I’ve taken to structuring a requirejs based web application. The file rconfig.js is basically configuration for requirejs. Here’s some example content:

require.config({
    "baseurl": "/app/"
});

This is not the default approach you will find in tutorials but I’ve found that’s what works best.

Start here: Requirejs: Why AMD?

Normally, importing a module requires an asynchronous operation (fetching the module file), but if the module has already been loaded, then it can be imported synchronously.

The require function operates in two modes. If given a string, it will behave as a synchronous function and look for an already-loaded module (throwing an exception if the module hasn’t been already loaded). If given an array of strings, it will operate asynchronously, and execute a callback function when the loading is done.

One of the genius aspects of RequireJS is that its loader can figure out the dependency graph and load a module’s dependencies before executing its code, thus making them all available via the synchronous version of require, and allowing you to write modular code without worrying about the asynchronous aspect of module loading.

Promises to handle Asynchronous flows

Asynchronous code can quickly turn into a spaghetti mess that’s very difficult to handle and reason about.

Learn how to use the Promise API.

Fortunately it’s now supported in all modern browsers, and we have a polyfill for old browsers (based on rsvp.js)

I recommend avoiding “Q” and other libraries built around the concept of a “deferred” object. Stick with the Promise/A+ API.

Start here: Domenic Denicola: You’re Missing the Point of Promises

(That post is written by the author of Q, but like I said I personally recommend avoiding Q and the whole “Deferred” concept as it seems rather superfluous to me).

Of course, Promises are still not the optimal solution. It will probably be a couple of years before it becomes feasible to use some async/await like feature in vanilla Javascript; until then, the Promise API is the best thing we’ve got.

Managing UI state

I already mentioned that my preferred tool for handling this is KnockoutJS.

It’s an extremely mature library with excellent documentation and interactive tutorial (quite possibly the best I’ve ever seen). It’s backwards compatible with itself and with old browsers (supports even IE6!). Very stable and reliable, with comprehensive test suites.

It doesn’t impose itself on you and does not set an upper limit on the things you can do. It does everything it can to empower you.

Knockout lets you define your UI declaratively, so you don’t have to manually manage the UI state to keep it in sync with your application state; it’s done automatically.

The declarative language lets you “bind” certain aspects of the UI with certain objects in your data model. It provides a decent set of “builtin bindings” for the most common use cases, such as binding the text value of an input field with a string, the checked status of a checkbox with a boolean, and the text inside an html element with a string. It also lets you define your own “bindings” that can handle other aspects of the UI. The custom bindings allow you to handle cross-cutting concerns effectively without introducing any unnecessary coupling.

The “automatic” aspect of the binding is thanks to the system of observables. An observable is an abstraction of a setter/getter that you can subscribe to so you can react to changes made to it. The most powerful aspect of Knockout’s observables system is probably the computed observables, which lets you react to when a function’s return value is changed!

After you’ve read the introduction page (linked above) jump right into the interactive tutorials.

Building applications

For an application all you really need in addition to KnockoutJS is a “routing” system so that different client-side urls go to different “views” so to speak.

The best system I know for doing this is DurandalJS, which is not only a routing engine, but comes with a few other goodies: a composition system and a mechanism to display modal dialogs.

(Side note: The DurandalJS website has some talk about the “next-gen” framework thing called “Aurelia”, I can’t actually say anything about it because I haven’t tried it, so I’m not endorsing it in this post; I’m actually somewhat suspicious of it)

The composition system allows you to “inject” a view into the page, or “compose” independent isolated views together. It’s implemented as a custom binding for KnockoutJS and it’s really powerful.

Even if you don’t need the router, I would still recommend you include DurandalJS in your application just to get the view composition system.

DurandalJS in general is a very minimalist framework, but it does include some areas which I think are best to be avoided (such as: widgets, see below). The documentation is not that well organized; you pretty much need to read the whole thing twice to get a good grip on it (but it’s not that bad).

In particular, when it comes to composition: I recommend you always provide an explicit viewUrl to go along with your viewmodel object.

I generally avoid the “widget” part of DurandalJS. Just use composition as a basis for reusable components.

I also do away with the silly convention of putting code into viewmodels/ and views into a views/ directory. I just let the js and html file reside in the same directory. It makes things much simpler: keep related things close to each other. If you must separate files to dierctories, consider instead of doing this:

viewmodels/
    component1.js
    component2.js
    component3.js
    component4.js
    component5.js
    component6.js
    component7.js
    component8.js
    component9.js
views/
    component1.html
    component2.html
    component3.html
    component4.html
    component5.html
    component6.html
    component7.html
    component8.html
    component9.html

Do this:

component1/
    component1.js
    component1.html 
component2/
    component2.js
    component2.html
component3/
    component3.js
    component3.html
…

Isn’t it so much cleaner?

It’s one of the things that make DurandalJS a good mini-framework: it doesn’t impose its defaults on you; you can always organize your code the way you see fit.


Viewing all articles
Browse latest Browse all 50

Trending Articles