4. Traditional Web Development
Stakeholders, architects and developers define the
“real” application.
The application is built model first (from the DB up).
Web assets are created last to glue together things.
5. Traditional Web Development
Most of the application is just CRUD.
The design of the UI/UX happens in Photoshop... if it
happens at all.
The design is focused on making the CRUD pretty, not
usable
6. We have a widgets
table
We need a
widgets
screen!
7. Traditional Web Development
JavaScripts are something someone download from
hotscripts.com.
Most user interactions result in lots of POSTS back
to the server.
“Advanced” web developers write lots of unorganized
bits of jQuery.
8. We have a widgets
table
We need a
widgets
screen!
Make sure you
add a date picker
And a lighbox!
9. JavaScript: Not a “Real” Language
Not thought through like server-side code.
Built as a glue to bind pieces together, not as a core
component of the application.
Patternless design.
10. Not Real? Why?
JS used to be a tool for doing image rollovers.
Libraries like jQuery make it really easy to pile on lots of
little events.
A lot of development tools traditionally hid the JS behind
configurable controls.
11. Is That A Problem?
For form-based apps that was mostly fine.
In a workflow-based application it falls apart.
Customized, reusable controls and a modular
application design needs something more.
43. Some Reasons
• JavaScript isn’t real code
• We don’t treat client side things as real features
• We can’t easily test it
• We don’t like writing it
• It behaves differently in different browsers*
* Or at least it used to
44. This really all boils down to one thing.
We developers suck.
46. Decouple Everything
Start thinking about UI pieces as individual JS objects.
Remove dependencies between objects.
Apply your OO best practices here too.
47. Small Chunks Of Code
Separate DOM dependent stuff into a single layer.
Put the rest of the stuff in classes that you can test.
Even if you don’t test everything, learning how to
write testable code means learning
how to write better code
48. Push Events, Not State
Know about the Law of Demeter.
Let controls worry about their own state.
Inform other controls that “X happened to Y”,
not “Y is in X state”
49. Writing Better JavaScript
Leverage language features whether JS has them or not.
Use the design patterns you already know.
Find the tools that make your life easier.
50. Language Features
JavaScript loves its objects. Create them to represent
page elements.
Objects have state and behavior.
Keep state inside of the objects and expose methods.
58. Mediator Pattern
"The essence of the Mediator Pattern is to "Define an
object that encapsulates how a set of objects interact.
Mediator promotes loose coupling by keeping objects
from referring to each other explicitly, and it lets you
vary their interaction independently."
-Design Patterns: Elements of Reusable Object-Oriented Software
59. NavControlMediator
itemSelected()
unselectAll()
Events from some
other object
60. Observer Pattern
"Define a one-to-many dependency between objects so
that when one object changes state, all its dependents
are notified and updated automatically."
-Design Patterns: Elements of Reusable Object-Oriented Software
Think jQuery $(‘.something’).click()
61. NavControlMediator
itemSelected()
viewModel
unselectAll()
Events from some
other object
66. A KO Warning
It’s really easy to go overboard with KO events.
I prefer to use KO for the VM binding (observables and
computeds) but rely on jQuery for events.
jQuery’s .on() binding and a good understanding of ‘this’
makes for much cleaner events.
67. Backbone
While KO is Model < > View magic, Backbone is structure.
Routers help you organize page flow.
Views help you control the visual rendering.
Models help you keep track of state.
72. Service Bus
A service bus is another layer that sits outside controls.
Controls that want to communicate speak through it.
Your controls are then only coupled to a single thing.
74. Service Bus + Mediator
• Controls no longer need to know about others.
• We can remove/replace controls individually.
• We can add controls that listen to the same events
without modifying the publisher.
• We can re-use pieces more easily because they work
in a standard way.
79. Testing
Try to have layers of your application’s JS that don’t
touch any HTML elements.
Store data in models inside individual controls and test
that published messages change the state of those
models correctly.
Software developer for years. Worked in consulting, education, enterprise. Worked with java, .net, ruby. Almost always been web based with just a few services here and there. Now lead engineer at Facio, a startup aimed at helping people and organizations better understand themselves.
Also I’m the cofounder of CloudDevelop, a regional cloud computing conference in Columbus, OH. This will be our second year and we’re really happy at how successful we were last year.
*Real being the database, server side code, tech stack, etc *Domain driven design (at least some uses of it) enshrines this *Little thought is given to these web assets. They’re just glue. Not important
*If anyone is not familiar with CRUD it means Create, Read, Update, Delete. Just forms not workflows. *Photoshop design isn’t great at showing design patterns or interactions. *No thought is given to consistency or usability NEXT: A traditional dev feature conversation is like this
A traditional dev feature conversation. We build this screen and then we need a bit of JS to glue things together We’ll come back to this in a second
* JavaScript is something widgets use. Your control from Telerik or Google Toolkit or your UpdatePanel might use it. Most developers don’t know what happens if a control breaks. The JS is mysterious and unapproachable. (note) Thanks, searls, for the joke * * More JavaScript isn’t better JavaScript
Time to add the javascript
Why is this? *In traditional web development JS is an afterthought and not a first class citizen in our application * * Design patterns and practices used throughout the rest of our app are somehow forgotten
*Depending on how long you’ve been building websites you may have been around when JS was used for little silly things * Now it can be used for more but most people still only use it for a few click events * Or they use it without knowing about it because it’s bundled in things they buy/download. Complexity is hidden. Debugging is unknown.
* If all you really needed was a date picker or a validation message why not just use drop-in JS. In fact, a lot of companies (give examples) made a lot of good money helping you do this. * Companies are caring more and more about UX. Things need to be intuitive. The experience needs to be consistent and reinforce what is important to the user. * We want this to be easy to maintain and extend as well.
The designer comes up with a simple feature The designer tells the developer about the feature
The developer doesn’t ask enough questions, doesn’t really get the designer’s vision. The developer builds exactly what was asked for and nothing more
The developer totally botches the visual design (you all know this happens) The designer shakes his head in disappointment
The designer heads to the coffee shop to get a soy peppermint mocha so he can calm down and get over his frustration with the developer. The developer cleans up the visual stuff. Everybody is happy, until...
The designer comes up with another feature
Developer wishes this had been mentioned initially. He may have done things a bit different initially. Designer lets out an exaggerated sigh. Silly developers don’t understand the creative process (next) Developer grabs some caffeine and gets to work
The developer is mostly happy although this is a bit messy. Still, it’s only one little bit of JS. The designer is totally unaware of the developer’s slight unease.
Some time passes and then the designer comes up with another feature. It’s not totally incompatible but it’s not something that was part of the original design.
The developer wishes he had known about this last iteration. He didn’t build in any support for collapsing navigation. Maybe he used some global variables assuming only a single nav control.
So he tries to talk the designer out of it. Who here hasn’t been there? Anyone?
And the designer doesn’t buy it. He leaves the developer to start working on it. He needs another coffee break so he goes to get a double ristretto venti nonfat organic chocolate brownie frappuccino . Designers are divas.
The developer gets more mountain dew and gets to work bolting on more code
Messy slide is messy (3 clicks) It’s starting to get more and more messy. Selectors are flying everyone. But it’s pretty much ok because the nav controls the page but it’s all pretty 1:1. (next) Uh oh, what’s this. The developer realizes there’s another feature in the comp he didn’t know about that he has to add too.
Designer adds a new feature
Developer attempts vaporize designer with his angry stare
But the designer’s protective beret shields him from the laser eyes
3 clicks The developer pulls an all-nighter to get the features in the release. He swears a lot. Now pieces are interacting two ways with part of the page affecting the nav perhaps. He breaks some existing functionality. He swears some more.
If the developer was unit testing his JS (which he really wasn’t) he’d find regression bugs (click) He finds the last bit of old code that was breaking because of his changes. Wait no, there’s another. Swears some more.
Developer finally hacks together a solution
So the next morning arrives and the DESIGNER comes to work (not the dev)
The designer is at the office sipping his iced no-fat low-carb glucose-free vitamin-fortified chocomocha frappe expresso twist with skim milk and pondering his next feature. The developer stays home sick.
Designer has mostly recovered
Designer adds another new feature
The developer has a nervous breakdown and gets hauled away to the hospital The designer punches his ‘broken developer card’. One more ruined developer’s life and he gets a free coffee.
So this was a bit overly dramatic. I may have been embroidered a bit. The designer probably doesn’t actually own a beret. But who here has run into something like this on a project?
This may not happen over weeks. It may be over years. It may be totally different developers somewhere in a projects lifetime. It may have just been one developer. It may have been you. It may have been your crappy JS.
We’ll re-iterate a few things I mentioned earlier and add a few more in. Then we’ll look at solutions.
1. It’s glue we use to connect bits of real code. We don’t like writing it and we do it last. 2. We don’t put the same amount of thought into designing our JS as we would ‘real code’ for ‘real features’. We often have a PSD mockup without real workflow. 3. Because everything is so coupled to everything else testing is a nightmare. It’s hard to unit test. It’s hard to acceptance test because of the # of browsers.
We don’t craft our JS like we do ‘real’ languages. We don’t apply patterns we use elsewhere. We don’t build (or learn to use existing) tools to truly craft JS. So how do we break out of this and teach our arch-enemies (the designers) who’s boss?
1. Start writing classes (maybe using CoffeeScript) to represent UI controls Let JS objects exist outside of the context of the page they exist on 2. We’ll talk about this in a bit. 3. Whatever you would prefer to do when writing C#, Java, Ruby, etc try to do in JS
You can test DOM dependencies but until you are already testing your logic don’t bother. A lot of DOM issues are user acceptance type issues anyway and require hitting the pages with different browsers. Core logic usually won’t care about the browser.
If you don’t know the Law of Demeter you should probably google it later. It basically says “objects should know as little as possible about the stuff inside other objects”. You shouldn’t reach into other objects to get at their properties. If you need to tell another object to change something send it an event that it will care about and respond to.
We’ll talk in more depth about each of these. * JavaScript is a powerful language that doesn’t always do things the same way as other languages. Purists may argue with me, but I’m not averse to adding things in that it doesn’t support natively if it helps you build a better application. * If someone else has already solved a problem for you (with a pattern or a tool) leverage that
* Create object definitions for traditional code things but also create objects that represent visual elements so you can control their behaviors in a cleaner manner. * In this context ‘objects’ refer more to the conceptual bundle of data and markup that defines a control more than a JavaScript {} * In the lifecycle earlier I showed behaviors being thrown about everywhere and no central repository of state for “objects” on screen. We don’t write (or shouldn’t write) server side code like this.
Namespacing isn’t a native feature but you can at least get the code organizational benefits of namespacing by rolling your own.
We can stop cluttering up window!
JavaScript has prototypical inheritance which is a strange thing to wrap your head around. Using it, or using any one of the ways of getting “classes” in JavaScript will help you write cleaner code. You should be able to re-use/subclass in a real language.
You’ll definitely want to Google this. Think of it like inheritance. If you can’t find it in this object, but this object has a prototype look in that. If that object has one, look in that. Compare it to CoffeeScript
This is from the coffeescript.org. I can’t run native Coffee as easily in the Chrome console http://bit.ly/13cogQ8
Most web frameworks can take a model on the backend and JSONify it. Using any method of sending an async request to a server, you get back this JSON and treat it like a JavaScript object. You can load up the skeleton of a control and then add bits to it after the page loads, or in response to a user interaction. And it’s super easy.
The mediator pattern has you create one object, a mediator, that’s responsible for coordinating the actions of a bunch of related objects. The objects don’t reach into each other when things change, they inform the mediator.
-Each button can have events happen. They don’t have to know about the other buttons. The mediator is the only thing that tracks individual button states. -The mediator doesn’t track the state of other page elements, only its children. -Other page elements only interact with the children via the mediator. -When an event causes the mediator to change children we push state changes down. I use KO for this.
The observer pattern is just pub/sub (publish/subscribe). If you’ve ever done any event binding with jQuery or by hand you’ve done pub/sub. Mention click binding as an example
With KO.js we bind elements to a view model. We basically tell KO “Hey, let me know if my state (in the view model) changes so I can do something”. This is called View Model Binding
KO is simply a way to magic changes to a model into a UI, and magic events in the UI back into the model
KO template. data-bind is how you tell KO there are things here we care about. click tells it to call a method named ‘selectMe’ on a click event css tells it to add a class of ‘selected’ with the value in the property ‘selected’
An observable array is an array that KO adds some helper methods to You see one of the methods ‘selected(false)’ which stands in for ‘selected = false’ because it adds some callbacks
Example 5
Backbone isn’t simple enough to explain in one slide. It’s a set of tools to let you construct really well organized, decoupled applications. It’s also harder (IMO) to really wrap your head around. It’s really powerful for building re-useable pieces.
So this is a real set of controls I’ve built into Facio. They share some visual styles and behaviors (like they can both have page controls if necessary). I built a base Backbone view and then in each case used prototyping to add custom behaviors. Each question (left) or todo (right) is a child view that interacts with its parent.
Are you building a large JS app or a web page with lots of little JS parts? Do you want VM binding or application structure? I’ve found Knockout to be conceptually simpler for people getting started in writing JS apps. It doesn’t do as much and lets you get started building nice interactions.
You may be familiar with these from the server side of things. A pretty populare .NET one is MassTransit. There are others in the Java and Ruby spaces. They are frequently used to let network services communicate between themselves. We can use them on the client too.
Publishing with postal.js is as simple as picking a channel, a topic, and pushing in a javascript object. Subscribing is the same with a function to execute when data comes back. Strongly typed languages will often use the type of the message object to determine what to listen to. JS doesn’t lend itself to this so you specify the topic like “ItemSelected”, “ItemDeleted” etc to limit which messages you get for a single control. You could do this on your own by wrapping some method calls around lists of events or something like that but using a library for it does make things easier.
2. If you want your page to have totally separate nav controls for tablets but keep the same report control, you can switch them out as long as they publish the same messages.
The nav control doesn’t know anything about the report. It’s really easy to extend.
We can have other things listen to the bus
We can use the message bus to update other view models when the state of objects change. One control knows nothing of another. When we started building our management screen it was really handle to be able to build things in parts and just agree on a message API of sorts. Not every piece of the puzzle needs to use everything. We built a mediator of sorts to control the team but it doesn’t have a view model with pub/sub
We used another message topic to push items back to the main screen and updated a view model to update the page without a postback. We even use this edit team popup on other screens (in this case the team’s specific screen) and simply had to have that screen listen for events on the same message bus.
As time as gone on I’ve started testing my JS more and more. I almost never test that some DOM manipulation worked. Instead, I test that messages that needed to get passed got past, or that child methods got called. I eyeball test the page. You could use automated UX testing if you wanted.
Underscore is a
Underscore is a functional helper library. It gives you a lot of the features you already have in your existing languages that are missing from JS.
It’s even better with coffeescript. This is a chrome plugin called coffee console. I love underscore coffee one liners
You may be familiar with these from the server side of things. A pretty populare .NET one is MassTransit. There are others in the Java and Ruby spaces. They are frequently used to let network services communicate between themselves. We can use them on the client too.
Go through the first 4 and then next slide
The designer comes up with a simple feature The designer tells the developer about the feature
The developer’s been through this before. He ask the designer to walk him through his vision of the page. Developer has a good feeling that this page will be expanding in the future. He decides to decouple his controls. He builds a few simple controls (no mediator pattern yet) but uses a message bus to connect them.
The developer still botches the visual designs. We haven’t solved that one yet.
The designer stills heads to the coffee shop to get a soy peppermint mocha so he can calm down and get over his frustration with the developer. The developer cleans up the visual stuff. Everybody is happy.
The designer comes up with another feature
Developer replaces a simple control that had a few JS calls with a mediator. Other controls on the page still see the same messages through the message bus and don’t change at all.
The designer mentions another similar but not identical feature.
The developer subclasses the existing JS (using CoffeeScript for instance) and adds the new functionality for the piece that needs it. He also handles the collapsing/expanding nav with some code in his KO view model. The designer starts to worry about his unbroken record of developer breakdowns.
Designer adds a new feature
Developer adds a new control that listens for an existing bus message and does stuff.
Designer is getting really stressed.
Designer has a nervous breakdown, quits his job, and goes to live on top of a mountain somewhere to seek inner peace and reflect on his life. Developer goes on to be a developer who builds cool things that people use.
TODO Insert knockout.js tutorial url Insert media pattern tutorial Insert observer pattern tutorial