So it's 2015. You have a stellar back-end system: things are distributed, you're employing micro-services working in isolation maybe, everything seems to shine from your load-balanced heaven. This little beast will power your front-end experience and surprise surprise! - you wake up one day stunned by the criticism of people starting using it - "Why is it slow?" :) Yep, these users have absolutely no intention being confined to the boundaries of your app user flows. Driven by the smartphone boom you only have 6 seconds to keep your visitor until the moment you're idle again fishing in the market for the next 6-seconds visit. It's ridiculous and fun in the same time actually :) As a result it's an effort in itself finding non Bootstrap-alike websites. The word du jour seems to be performance on all levels - be succinct in ideas, be fast in load times, be responsive and obey the medium. Add to this the fact that you're running on a single UI thread and you have a story to tell.
Part one: Front-End.
More often than not it's this front-end part where the bulk of your user interactions will happen, event clicks intertwining with async requests and fast refreshes. In all this chaos you need to hold state. At any single point in time you need to know how your application looks like. Immutability is nice and solves lots of headaches but have a look at your memory. Yep, you're running in a browser, crammed in a tab. Hi!
Another systemic, deeply entrenched problem: mutating data. In doing so you ensure endless nights of debugging: properties out of sync with each other and interface out of tune. You cannot tell your variables apart, need to re-sync pretty much all the time and this quickly escalates to a one way ticket to the cuckoo land. Neither the best performing back-end in the world or the best binding library would save the day once your user starts panicking - and with each event passed the system as a whole feels less and less snappy.
For interface issues solutions like Angular exist. Bind my variable to that DOM control. I remember loving having this privilege with all the $digests that it involved. Angular is nice but has a lot of abstractions. Wait, what's the difference between providers and services? There's a StackOverflow for that sure or Angular source and documentation, it's even fun but it won't really fix the underlying issue. You don't need to sync DOM controls anymore, you need to sync scope variables now. Also, how many watchers are in there again?
Beginner JS devs are generally good with implementing spinners - everything loads all the time. Then ad-hoc jsons, ajax calls, console logs and if things really turn south end up refreshing the page.
Advanced JS devs fare better: are backed by backbone models which when changed trigger promises that perform callbacks which control things within the interface. Sometimes callbacks fight in which case a page refresh is due.
All of this is happening while senior devs cannot be called in to help assessing such issues, they're too high-level and expensive for this. Code reviews (when they happen) tend to happen across similar skill-sets, either jQuery-jQuery or Java-Java, never cross-systems.
Far from being the only approach (we're blessed with an abundance of architectures and libraries here) this describes a typical scenario employed by many of us today.
Jump into the band-wagon
We love React.js. It doesn't change the basic concepts and it's subtle. You have your same unassuming DOM element with a few new abilities (has its own state, you can initialise and caress it as much as you want). It can pass its properties to its children. The guy doesn't control anything, it just gets refreshed - two way binding is a rockier road. Problem stays the same but this time a predictable application state will always control the interface, not the other way around.
A few good gains already:
- You're faster. Components get rendered in memory not inside the DOM, DOM only updates when/where needed.
- It's accessible. Devs will initially freak out while realising what JSX is but in a few days' time they'd be happily churning out beautiful controls - productive and entertained at the same time.
- You can decide where rendering happens - server or client?
- You can finally do mobile the nice way via React Native
- Together with the whole JS crowd you can do multi-platform desktop apps too.
- Most of these steps can be achieved via configuration/minimum efforts
"..but it almost looks alive, Jim"
Fear not, there are clean alternatives.
One is Redux, enforcing immutability. All your data stores are immutable and you produce output by filtering these stores, cherry picking the properties you need. Beautiful & clean-cut, we have a reducer - another good sign. This guy's output gets mapped to our component's state (the glorified DOM element that is) and we're really in a much better position. Actions will trigger reduce functions that filter data. Interface is in sync all over the board. All this data being immutable our properties end up not stepping over each other and we're pretty happy with the outcome - our DOM is docile now. Change everything by triggering an action. Simple to code, easy to debug, concise. How well does it perform though? This is what needs assessment - immutability usually has costs in memory usage and we live in user browser land not inside a sandboxed, distributed environment. Each use-case has different requirements and you may be grand but yeah, this is definitely an area you want to assess.
Say hello to another project to love, Baobab.js. This guy is a tree holding your data. It provides access to branches in the data tree and it's damn serious about its job - it's really really efficient. You can have it mutable, you can have it immutable. You get various dynamically computed combinations of your data via Monkeys (lazily executed facets - reducers pretty much again, yeah). With a difference though: they are stored in the tree as well. How is this cool? They combine data from different branches together and you can tweak them at will at run time should you really need to while still preserving a single source of truth. THEY are the things that don't pollute your data, to come back to an earlier sentence - exporting your tree will not export its monkeys.
Good. Changing a property updates others and we end up with an interface that looks composed. Now, who's responsible for changing the damn property again?:) What if I'm actually using Angular and would like Baobab in charge there? Or how about changing the whole model library, replacing it with say Immutable.js?
Meet Cerebral - a state controller with its own debugger. This thing is your brain, the bulk of your front-end business logic goes here. It can trigger flows of actions (action 1 in sync, then actions 2&3 in parallel, when everything's done run action 4 - cleanup maybe). These flows are being referred to as signals in Cerebral slang. We're being given access to all our state history (you have a Chrome plugin helping you replay these actions, you'll love this) and it glues really well the data in your tree with the state of your components. Need a different data tree? Change the model library. Love Angular? Change your view layer. Debug? Check, there's your whole model in the console. You're ending up happily triggering signals and that feels like a lot more natural way of expressing intent - "my desired objective is this, actions are just steps taken towards reaching this objective". This is actually a major pain point while working with different Flux implementations - Reflux for instance. It's so easy to pick it up that you'll be firing Reflux actions for everything all the time. How do you construct your data tree? Sync actions :) With all this said we love this little dude, it's a really nice way of getting into Flux. For a newcomer this would be a really good candidate to play with.
We're still talking performance.
Module bundlers (Browserify, Webpack, System.js, etc) are really well described - not my purpose to get into details. They help you bundle your modular code together, add tremendous dev-value and take care of lazy loading of extra chunks of functionality only when you need it. But besides the obvious you also get ready for another incredible feature in the making (via ES6 exports): you get the ability to strip out incredible amounts of dead code when you transpile to js. Rollup.js is a pretty interesting project - it's another module bundler figuring out what you require() from your code and only preserving that. Zero efforts payload slimming, how cute is that?
Many thanks for reading and keep following us for a Star-Wars saga kind of feel:
Part two - Adventures in Back-End: How we stopped worrying and still don't understand Mesos
Ireland is ranked the best country in the world in terms of empathy and people doing good for others. Feel free to connect with the tech community in here, you'll meet incredible people. If lacking ideas on how to engage you can start here: http://irishtechcommunity.com/