React, AngularJS, Backbone and Ember The Bad Parts
I often get asked why I am not a fan of React, Angular, Backbone, Ember or other fast food frameworks. The full answer is probably long and drawn out, but I will try to simplify it.
When I started doing large single page web applications these frameworks were not yet invented. I also approach client application development with a user first approach. That means performance, touch and mobility are the primary considerations. Developer ergonomics a distant second.
Don't get me wrong I think the development experience is critical, I mean how else are you going to build these systems with any integrity. But fast food frameworks do not solve these problems, they just abstract them to another layer. In doing so they add some layers of fat we must carry and never use.
Since these frameworks were not around and I needed to create modern higher performance single page web applications I needed to create my own techniques and libraries to solve problems. As these large frameworks appeared and started gaining traction I had to decide, can they meet my needs? The answer is a consistent no.
Mobile matters more than developers realize. It is well over half the traffic to a web site or app. Mobile devices are weaker than desktops and often transfer data over bandwidth challenged GPRS. This is not a good environment for fast food frameworks.
I have worked on projects with Backbone, React and Angular. The #1 thing that irritates me is trying to make performance happen. These libraries are so large you have inherent delays. Many developers point to they should be cached via a CDN, etc. That is not a sure thing, especially over mobile.
Fragmentation and other factors come into play that cause developers to have blind faith in something they cannot control. Always assume your script is being fully loaded by the client no matter what and measure from there. You should always include testing on a real mobile device over GPRS before you finish your coding.
Even if the script is locally cached the browser still needs to evaluate the library. Fast desktop processors like I have on my Surface Pro 3 can evaluate these scripts rather fast. Mobile processors are another animal. This blocks your application from hydrating so the end user can start interacting.
I often read and hear one of the great selling points of Angular is modularity. I love modular architectures, but Angular 1.0 is NOT modular. The framework is all or nothing. You can extend it, but I cannot exclude parts I do not need, which is most of it. Just glancing around various web sites built with Angular I can tell 80-90% of the framework is not used. Angular (v1.4) is over 140kb minimized, that is huge! Let me put that in perspective, even my largest applications are less than 130kb total, most are under 70kb.
I have spent many hours routing through the Angular source code and I see so many parts that simply are not needed. For example did you know the validation layer just wraps the native validation functions and offers no real value?
Backbone and Ember also present tightly coupled scenarios as they depend on other large libraries, like jQuery. A rule I try to follow, after many development projects, is a library should be able to stand on its own as much as possible. A good library should be 3rd party library agnostic. Instead I tend to write against 'interfaces' and build providers or shims to help make my code more modular.
Abstracting Dependency Injection
The thing I probably hate the most in Angular is its dependency injection system. To me it is full of code smells. They start with the need to pass the name of the dependency as a string so it will not get changed by the minifier. That is a big fat brown M&M.
I often get push back here from folks saying you need this for large scale applications. Hogwash! I have build several SPAs with over 100 views and numerous components. The need for complicated DI never reared its head.
<script id="product" class="spa-view" spa-transition="slide" spa-view-id=".spa-view-product" spa-layout="fast-furniture-layout" **spa-route="product/:Name"** type="spa-view"><section class="spa-view-product "> <div class="y-scroller-wrapper full-text"> <section class="product-details"></section> <section class="product-details-related-products"></section> </div></section></script>
That is why I created SPAjs to not only manage view transitions but routes as well. SPAjs creates the callback to the hashchange event and responds accordingly. But more importantly when SPAjs is instantiated it parses each view and creates an object representing the view by evaluating various data- attributes. As it processes these attributes it builds an internal route table.
Two-Way Data Binding or Specifically Dirty Checking
There are many developers that have fallen in love with two-way data binding. I get it, it makes the developer feel a little empowered. But the reality is you write more code to deal with the models. Angular, Knockout, etc still have not gotten the update process right. It is a CPU intensive process that drains your battery.
Sometimes I think about data binding and their love as I would one of your buddies that has fallen head over heals in love with the hot chick with crazy eyes. You know the one you can see is going to wreck your friend's life but he wont listen to you.
Observables and data binding are really sexy, in presentations, but that is about it. Ask yourself how often you need to echo the value of a textbox as the user types a value? In my 20+ years of web development it has been very, very rare.
Sure I occasionally need to hide and show markup based on a user action, like checking a checkbox or clicking a button. But there are very easy ways to handle those situations, the onChange event allows you to define a callback.
This is what two-way data binding libraries are doing for you, the problem is they do it for every control in a page. Often they roll up the actual event binding to a parent element, like the BODY tag. This means they have to parse the event object, etc and they do it for every single keystroke, even if you have nothing defined in response to the change.
The single source of truth concept is seductive, especially when you are practicing test driven development. Here is where I am going to stick my neck out, the client is not about test driven development. Instead it is about user driven development. TDD is an inside out approach. This has to change. Write your user interfaces to make your users successful as quickly as possible.
Instead of a single source of truth created through data binding write a function to automate forms for your tests, Apply naming convention governance to INPUT names. This is not as hard as you think. Deserilizing form data is actually pretty simple.
Which leads me to my next point. Many developers have told me data binding makes collecting form data simpler. Again a simple function can solve this problem for you.
The reality I continually see as I consult with enterprise after enterprise is how data binding is complicating the development process and causing missed deliverable dates. It causes problems because it necessitates more code, which takes longer to write, test and refactor. It also causes confusion. To many developers they wind up focusing more on the data binding syntax than they do their data.
Instead use a templating mechanism to merge your data with markup and a reusable function to serialize form data. Use the onChange event to drive experience where needed as the value of a specific element changes.
This is a post I wrote the original draft just over a year ago. React was not even on the radar then, which of course is another problem, these frameworks are here today and gone tomorrow. I made a few modifications today because the content is still true. I hope it gives you some more insight into why I think fast food frameworks are problematic.
There are many things to complain about with fast food frameworks. These are just a few things I find easy to point out. I could dig into deeper more technical things, but there is only so much time in a day. Sure these problems could be fixed, but they wont be. This is why a modular, library and archicture approach is superior. It is easy to fix issues without affecting the entire application. Plus you have more options to avoid bad parts.
Please think about what you are trying to accomplish before you go through your local fast food framework drive through. Ask yourself is this 'value meal' you are about to order good for your customers or are you just being lazy?