Ryan Tablada

Christian, UX Tycoon, Instructor at The Iron Yard

Checkout my screencasts at EmberGrep

Checkout my newest book on Leanpub

Local state vs strict reactive centralized state

Oct/23/2016

NOTE This article started as a reply to a Slack message but morphed into something larger. It is not a complete discussion, but just some thoughts I had around the topic of state management. View discretion is advised.

With local state it is easy to modify things you shouldn't or take actions that should be responded to somewhere else.

With Centralized state you now have to detangle data from small areas of your app meaning you will likely have identifiers or lists where you may not have had lists before. This causes you to have your persisted data model interlaced with local only visual state information. This also causes a large amount of information to have to "pass through" or be ignored by large areas of your application. Without proper guidance, tooling, or caution: centralized state can allow items to accidentally modify data they may not even have access to at all!

Example:

Let's say we have a file tree which is persisted in the following JSON data:

json { "name": "src", "folder": true, "children": [ { "name": "app.js", "folder": false }, { "name": "index.html", "folder": false }, { "name": "imgs", "folder": true, "children": [ { "name": "face.jpg", "folder": false }, ] } ] }

Now we want to make a toggleable file tree.

For this example, we'll create a basic standard MVC application:

```js // Controller class FileTreeController { createNewFile() {

}

createNewFolder() {

}

attach() { this.model.children.forEach((file) => { const v = new FileTreeView(file, this); v.render();

  v.attach(parentElement);
})

} }

// View class FileTreeView { constructor(model, controller) { this.model = model; this.controller = controller; }

render() { // Make changes to UI }

toggle() { // To be implemented } } ```

If we use local state to manage our folder open/closed status, we can do something like this:

```js class FileTreeView { constructor(model, controller) { this.model = model; this.controller = controller; this.showChildren = false; }

render() { // Make changes to UI }

toggle() { this.showChildren = true; this.render(); } } ```

One thing to note is that our original model is pure, we don't need to modify anything. This means persisting the core file structure is clean. But, it comes at a heavier cost since we don't have a good way to persist folder toggle state. If you don't need this persisted: well that's it use local state to toggle the children showing or hiding.

If you need the toggle state to persist, you will need to instead rewrite the View to be a bit more like this:

```js class FileTreeView { constructor(model, controller) { this.model = model; this.controller = controller; this.showChildren = false; }

render() { // Make changes to UI }

toggle() { this.controller.toggle(this.model); } } ```

Then the controller will update to be something more like this:

```js class FileTreeController { // ... methods from before

toggle(file) { // traverse entire model state and set toggle state for specified file // make decisions to persist state tree // what has changed? // do we need separate storage persistence for toggle vs actual files? } } ```

Sorry for the puesdo code, but I've been really wanting to finally show an example of this out in the wild.

A note about reactive central state management tools

If this title confuses you, it's "Flux" architecture that I'm talking about. In the reactive controller example I say something like "traverse entire model state and set toggle state for specified file". This is a pretty scary thought and should be really considered! While Redux and other reactive toolsets minimize the surface area of this process, by encouraging small reducer functions: it should not be overlooked that the entire state tree is traversed for ever decision.

Like-wise, middleware and other practices help with the question "make decisions to persist state tree". I think it may come off that this decision is something simple, but it's not. There is a lot of time and work going into making these decisions, but it's hard!

Personally, I'm not quite sure what I would do for persisting state for toggled items. Part of me dreads the idea of pulling apart properties and figuring out which properties should be persisted to two different persistence stores. The other side of me thinks of this as an RDBMS system and thinks that the file tree is parsable with relatively unique keys (the full file path), so if I can key on that data then I can have my application controller or a singleton service manage persistence of that data. This means that when I want to work with this information, I would call out and ask "hey is app/img open or closed"

A Story about PS4 Pro

Sep/15/2016

I come home, throw the week's mail on the counter grab a glass of water and start to head towards my gaming options. On the table is my PS Vita charging for my weekend trip and in front of me is my 3 year old mid-tier gaming PC. I ignore both of these, grab my Dual Shock 4 and instinctively hit the PS button.

It's almost 11PM so as the home screen boots up, I have a choice to play a few competitive matches of Overwatch, explore some planets in No Man Sky, or start the second half of episode one of Life is Strange that I've been meaning to go back to. As I drop on to the couch and take a sip of water, I choose to work on some public matches and try a new hero in Overwatch. Right as I enter my first match and get killed with a Hanzo "headshot" that lands at my ankle, I get a message on Discord.

I don't even check the message because I know what it is going to ask "Hey do you want to play Overwatch with us on PC". In my mind I'm thinking of the great times I've had with some PC games: 52fps (yeah I have a European monitor) is a slight noticeable improvement over 30fps on my PS4 and the better draw distance and texture detail do look really nice. At the same time, I remember when PC gaming has been pretty bad for me: a random background process spins up and suddenly the game crashes, the framerate drops because the fans don't seem to be working super efficiently today, I seem to have to download new drivers and settings for every new AAA release. As I weigh the pros and cons, I yell at my public match team to get on the payload.

It gets me thinking, I think I'm exactly who the PS4 Pro was designed for. It's not for the traditional early adopters and it's not for the PC master race. Instead the PS4 Pro is aimed at the young professional market.

For me, I want a consistent easy to use and reliable platform to play on. I don't have a ton of time to fiddle with settings and when I get home I want to boot up my game and get started. Sure, the PS4 Pro is more expensive than the AMD 480 or Nvidia 1060. But for my PC those cards aren't the answer to the smooth gaming I actually want.

While my last update to my PC hardware was 2 years ago, alot of the bones are actually older than that. The CPU is starting to reach its limits for single thread output (I purchased the 6 core AMD originally for linux development). But, to upgrade this CPU I will actually need a new motherboard as well since the CPU was actually my third in this build and is near the max capable for my chipset. Now that I have a new motherboard, I'll likely have to upgrade my RAM to match speeds for the new motherboard. All of this and I still haven't ACTUALLY guaranteed a smooth running system.

Tonight I have about one hour to play a game, and this is the case most nights. I really can't be guessing if I'm going to get a silky smooth 60 FPS (because let's upgrade my monitor since we're throwing in a new build) or 15 chunks per second based on the weather and depending on if the label of my bourbon bottle is turned five degrees due north. This is why I'm probably going to get the PS4 Pro within the first few months.

On one side I'm looking at $400 even, being able to give my current PS4 to a friend or family member who does not have the money to buy their own (or I could sell it too), and getting an improved experience that still feels familiar and has all of my friends. On the other side, I have the bet that $250 of raw GPU power will solve all of my problems, but if the bet fails I'll be starting on a solid $400-600 more to get everything upgraded on my PC.

To be completely fair from the specs and stuff it looks like the PS4 Pro will just outperform my current PC build.

But...

If you want to come over and use a compass and rearrange my liquor cabinet, I'll be over here hitting the PS button.

Travel Loadout - The Gear

Jun/02/2016

I still don't travel as much as many developers I know: but, I have traveled a lot more this year than ever before. So, the night before I travel out to New York I think it would be good to cover my carry-on pack. This is going to be a series of posts, but for now, I'll start with the gear.

The Gear

All of my carry-on gear is shown in the picture above. Starting in the top left in columns:

Column 1

  1. Sony Vita Headphones - These earbuds are comfortable, have a toggleable microphone, and very importantly they work for voice chat on Vita and PS4 which have a different set of tollerances for the mic.
  2. Lightning Cable - This is the standard Lightning cable for my iPhone and iPad. I also travel with a longer amazon Lightning cable which is just off screen charging my phone
  3. Micro USB Cable - This cable is used for my non-Apple devices (mostly for my battery packs)
  4. Playstation Vita USB Cable - This cable can be plugged in to external batteries or my Mac to charge the PS Vita. Sadly the vita takes almost a full 2A to run while charging and the stock power pack is a bit bulky
  5. Anker 10,000mAh Battery - This backup battery can fully recharge my Vita and Phone with some room to spare. While that's really nice at a conference, this sees more use as a USB splitter that happens to act as a backup battery. Since this battery is fairly heavy, I don't usually cary it around cities.
  6. Jot 4.5 - This is actually the newest addition to my pack. The Jot is a small reverse e-paper eWriter. Clicking the button on top makes the whole screen black and then using the stylus (or your fingernail), draws white lines on screen. I've been impressed with the resolution so far. The small size also is great for a quick sketch or Pomodoro style notes. Since there's no storage, these notes here have to be single track and then moved to something more permanent or sent off to the ether.

Column 2

  1. 13" Macbook Pro Retina - This is my office, work horse, and most everything. Fully packed and ready for fullstack development, under the hood is a 2.8GHz i7 and 16GB of RAM.
  2. Brikbook Case (on Macbook) - I get asked about my new Macbook case at conferences. Brikbook was originally kickstarted and is now available for sale. Right now I'm sporting one of the monthly designs.
  3. Playstation Vita - The Vita is an impressive set of hardware for a handheld. While I don't spend much time playing Vita day to day, this gets a lot of use on the plane. It's an awesome break and since the battery life is pretty solid and all games support system lock and resume, it is nice even on public transit. I'm currently playing Jak and Daxter, Hitman Go, and Little Big Planet. Also, note the trigger case on the Vita, this helps for longer play times for when I am at home or on the plane (but the case is removed if I need to pocket and go).
  4. Notebooks - For times when the Jot isn't enough room, or I need to save something for later, I have two notebooks with me. The larger is a gift from The Iron Yard and is helpful for things like specing out app or assignment ideas. The smaller one is a fields note sized Moleskin I got from Conde Nast and is great for carrying even when I don't have a bag.
  5. USB Wall Wart x2 - These are standard Apple 1A wall warts. I carry two with me on trips for a few reasons: first I have enough devices that I likely need to charge two things at once. But, more importantly, I have a backup if one goes bad (which has happened on the last two trips I've been on). If I loose one power brick I still have another and don't have to wait FOREVER for something like my Anker or Vita to charge via the USB on my Mac.
  6. Apple Earpods - Standard pack Earpods. While I like the Sony earbuds above, it's not uncommon for me to have podcasts and my vita going at the same time. But, also it's a good idea to have two different style earbuds since my ears start hurting after a while. Then I can swap and not have the fatigue from the foam or hard Earpods

Column 3

  1. Bobble Infuse Water Bottle - While day to day on campus I cary a 32oz Contigo Water Bottle, that becomes hard to carry around when traveling. This Bobble seems to be a nice trick. The infusion basket can be used to filter fruit infused water, or you can pack it with a carbon filter basket which can help reduce some odd tasting water when running around. The Bobble still holds ~22oz so I don't think I'll be running to refill it every 10 mins. Plus the softer sides make it easier to pack (but more on that in the next post).
  2. Dynex Backup Battery - Another new addition to the bag. This backup battery only has a single port, but has enough juice to keep the old iPhone going for a few more hours. Being alot smaller than the Anker, the Dynex is even pocketable for time around town.
  3. 60W Apple Mag Safe 2 Charger - The old work horse needs some juice. This is it! I keep my extension cable on this charger at all times: outlets are always two tables away in the coffeeshop.
  4. Quirky Powercurl Round - Cables are always getting cluttered. The powercurl keeps the Mag Safe charger neat and tidy. It even stows away quickly. There's also a little powercurl on one of the USB blocks, but no cord is in there.
  5. Bag - My bag is a hand me down from my dad. Turns out, it's the best bag I've found for traveling. More on that in the next post though...
  6. Wallet - I go with the standard billfold. I've had this wallet since university. Nothing really special. This was really just laying next to the rest of my pack...

Stay tuned for the next post where I talk about something even more important than the gear... THE PACK!

Building Todo MVC from Scratch Using Ember CLI

Jan/22/2016

Creating a new Project

Right now Ember-CLI is in a bit of a teenage stage. While the 1.13.x branch of Ember CLI is crazy stable, I would rather get the benefits of building apps using hot style reloading and alot of the performance upgrades available in the 2.x beta versions. This means, we'll need to install the beta version of CLI:

npm install -g ember-cli@2.3.0-beta.1

Now once we have this, we can create a new Ember project:

ember new todo-mvc

Now we have a lot of files, but we can get started.

Assets

The first task we have to tackle is getting the Todo MVC styles and such into our app. A quick bower search todo yields: bower todomvc-app-css#* not-cached git://github.com/tastejs/todomvc-app-css.git#*.

Score!

We don't have to do too much to get things into our app from there. Looking at the bower_components/todomvc-app-css folder, we have a base.css file. We'll have to get that into our build steps.

To pull in third-party JS or CSS, we can go to ember-cli-build.js in our project and import the CSS into our build pipeline. After the creation of app, let's import our the base.css file we found earlier:

``` var app = new EmberApp(defaults, { // Add options here });

app.import('bower_components/todomvc-app-css/index.css'); ```

Now when we build our app, the base.css from Todo MVC will be wrapped, minified, and imported directly into our final app.

That brings us to making our first build. While we can run ember build to make a one off build of our project, ember serve will be more helpful since it continuously builds our projects after changes and serves things up on http://localhost:4200.

Now if we look at our app in the browser, we can see maybe there's some background to our app and we have a heading that says "Welcome to Ember".

Creating the Base Markup

Now we need to add some HTML into our app to make it actually look like TodoMVC. If we go to the template HTML for TodoMVC, we can grab all of the contents of section and footer and copy them.

Ok. We have some HTML, but where can we put it?

In Ember, our app is built of nested sets of routed Handlebars templates (more on routes in a bit). At the top of this hierarchy of nesting is the template in app/templates/application.hbs. This template will wrap and be shown for everything within our app. If we open this file, we'll see the "Welcome to Ember" heading we saw in the browser. Let's paste the HTML we got from TodoMVC template so that our application template looks like this:

<section class="todoapp"> <header class="header"> <h1>todos</h1> <input class="new-todo" placeholder="What needs to be done?" autofocus> </header> <!-- This section should be hidden by default and shown when there are todos --> <section class="main"> <input class="toggle-all" type="checkbox"> <label for="toggle-all">Mark all as complete</label> <ul class="todo-list"> <!-- These are here just to show the structure of the list items --> <!-- List items should get the class `editing` when editing and `completed` when marked as completed --> <li class="completed"> <div class="view"> <input class="toggle" type="checkbox" checked> <label>Taste JavaScript</label> <button class="destroy"></button> </div> <input class="edit" value="Create a TodoMVC template"> </li> <li> <div class="view"> <input class="toggle" type="checkbox"> <label>Buy a unicorn</label> <button class="destroy"></button> </div> <input class="edit" value="Rule the web"> </li> </ul> </section> <!-- This footer should hidden by default and shown when there are todos --> <footer class="footer"> <!-- This should be `0 items left` by default --> <span class="todo-count"> <strong>0</strong> item left</span> <!-- Remove this if you don't implement routing --> <ul class="filters"> <li> <a class="selected" href="#/">All</a> </li> <li> <a href="#/active">Active</a> </li> <li> <a href="#/completed">Completed</a> </li> </ul> <!-- Hidden if no completed items are left ↓ --> <button class="clear-completed">Clear completed</button> </footer> </section> <footer class="info"> <p>Double-click to edit a todo</p> <!-- Remove the below line ↓ --> <p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p> <!-- Change this out with your name and url ↓ --> <p>Created by <a href="http://todomvc.com">you</a></p> <p>Part of <a href="http://todomvc.com">TodoMVC</a></p> </footer>

In our browser, we can see the standard TodoMVC app. It looks nice, but nothing is working... Let's start fixing that.

Submitting a New Todo

To get started we need to modify our markup a bit. For accessibility and submit capturing, let's wrap the new-todo input in a form tag:

<form> <input class="new-todo" placeholder="What needs to be done?" autofocus> </form>

Now we need to listen for our user to submit this input (with the "Enter" key most likely). We can add an onsubmit handler to the form HTML, but we need a way to let Ember know that something has been triggered from our template. To do this, we will use the action helper which allows us to capture user interaction and send it into Javascript where we can manipulate it. We'll call this new action createTodo:

<form onsubmit={{action "createTodo"}}> <input class="new-todo" placeholder="What needs to be done?" autofocus> </form>

If we try to load up our app in the browser, things will be broken and in our console we'll see a new error:

Uncaught Error: An action named 'createTodo' was not found in (generated application controller).

This error means that we don't have anything in our Javscript to handle createTodo. So, let's first create a controller which will allow us to handle this user interaction. To go along with our application template, we'll need an application controller. Similar to Rails, we can generate this from the command line:

ember g controller application

Now we will have a new file app/controllers/application.js:

```js import Ember from 'ember';

export default Ember.Controller.extend({ }); ```

But, our app is still not working. We need to create an "action handler" for the createTodo action within an actions object in our controller:

```js import Ember from 'ember';

export default Ember.Controller.extend({ actions: { createTodo() {

}

} }); ```

Now our app is loading, but if we hit enter, our page refreshes... Well, if we recall jQuery days, we need to prevent default. So, let's stick a debugger in the new createTodo method and see if we can figure out what we have to work with.

If we submit from the input and have our console open, we can inspect the values of arguments and see that Ember has passed along the DOM event from the form submitting. So, let's add another argument to our createTodo method and prevent default:

```js import Ember from 'ember';

export default Ember.Controller.extend({ actions: { createTodo(ev) { ev.preventDefault(); } } }); ```

Now we have a new way to capture user input, but we don't have a clean way to get WHAT the user has inputted.

Let's go back to our application template and work on this. Instead of using the native input element, we'll look at using Ember's input component.

Components in Ember are similar to standard HTML elements in that they have a name and arguments, but they also bring in some extra UI implementations. For instance the input component in Ember will allow us to listen for changes and update a property on our application controller. To use the input component, let's just replace the angle brackets with {{ and }}:

hbs {{input class="new-todo" placeholder="What needs to be done?" autofocus=true}}

NOTE since we want the input to autofocus, we modified that attribute to say autofocus=true

Now we can make our input live update a property on our controller named newTitle by setting a value attribute to newTitle:

hbs {{input value=newTitle class="new-todo" placeholder="What needs to be done?" autofocus=true}}

Note we are not using quotes here because we want to use JavaScript values not string literals

Ok... So we're changing a value called newTitle in our controller when the user inputs data. How do we grab that?

To the action helper after the action name, we can pass in a second parameter for data that we want to send along with the DOM event, in this case, our newTitle value:

hbs <form onsubmit={{action "createTodo" newTitle}}> {{input value=newTitle class="new-todo" placeholder="What needs to be done?" autofocus=true}} </form>

When we specify an argument for our action, it does come in as the first argument to our action handler. Let's grab that value as title and log it to the console.

```js import Ember from 'ember';

export default Ember.Controller.extend({ actions: { createTodo(title, ev) { ev.preventDefault(); console.log(title); } } }); ```

Woo! We've logged some input! Now to submit this to the server.

Submitting Todos to an API

For this tutorial, we'll be submitting to my API that is described in this article. I have hosted this API on Heroku at http://todo-mvc-api.herokuapp.com/api/todos.

We'll use the browser fetch to post to our API:

NOTE fetch is not implemented in all browsers, we'll fix this when we get to addons, but for now use latest Chrome or Firefox

```js import Ember from 'ember';

export default Ember.Controller.extend({ actions: { createTodo(title, ev) { ev.preventDefault(); window.fetch('http://todo-mvc-api.herokuapp.com/api/todos', { method: 'post', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({todo: {title}}) }); } } }); ```

If we look at our network tab, we'll see that we have made a OPTIONS request, but it doesn't look like our POST went through. But in the XHR tab, nothing is showing up... This is because the native fetch implementations will be listed under Other (at least for now). Let's turn our results into a JSON object and log it to the console to check that the server is responding.

```js import Ember from 'ember';

export default Ember.Controller.extend({ actions: { createTodo(title, ev) { ev.preventDefault(); window.fetch('http://todo-mvc-api.herokuapp.com/api/todos', { method: 'post', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({todo: {title}}) }) .then((response) => response.json()) .then((data) => console.log('request succeeded with JSON response', data)); } } }); ```

Clearing Out Our input

After we know that the user's todo has been saved, let's reset our input. We can do this by using Ember.set to set the value of our newTitle for our controller to an Empty string. We have to use the Ember.set method so that our template context is notified of the underlying changes. Here, we start by destructuring the set method from the Ember object, then calling set after our fetch has finished. Ember.set takes three arguments: the object to change values on, the name of the property to be changed, and the new value to be set.

```js import Ember from 'ember'; const {set} = Ember;

export default Ember.Controller.extend({ actions: { createTodo(title, ev) { ev.preventDefault(); window.fetch('http://todo-mvc-api.herokuapp.com/api/todos', { method: 'post', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({todo: {title}}) }) .then((response) => response.json()) .then((data) => { set(this, 'newTitle', ''); console.log('request succeeded with JSON response', data); }); } } }); ```

In the next article, we'll grab some data from our server so that our todo list starts filled out.

Creating a Simple TODO MVC API with API Kit

Jan/20/2016

For a long time, I've wanted a small JSON based API server that I could stand up in minutes with relationships. I decided that Node and Mongoose give me a lot of flexibility for small projects that I just want to try things out on.

I've been messing around with this stack and had a fairly large setup called express-shell that I use to make a more handrolled site using Express and Mongoose. But, express-shell focused on server rendering and there was a lot of things around sessions and mail that I didn't need for micro-services and smaller APIs.

So, I had a list of things that I wanted:

  • Quick start up
  • CLI Resource Generators
  • Support for One to One, Many to Many, and Has Many relationships (with foreign keys)
  • JSON output to match JSON API or namespaced JSON resources
  • OAuth 2 Bearer Grant Support
  • Easy (or auto) registration of public and protected resources

After a while of work, I've created api-kit and to go along with things generator-api-kit a Yeoman generator package to facilitate the creation of APIs.

Getting Started

To get started, install Yeoman and generator-api-kit:

npm install -g yo generator-api-kit

Then create a new API Kit project:

yo api-kit

This will create the boilerplate for our API project and install all the required Node modules.

Generating the Todo Resource for Todo MVC

One of the key points of API Kit was that it has to build quick JSON based APIs right from the command-line. So, to match Todo MVC, let's create a todos resource with two properties: an isComplete field which will be a boolean value and a title field which will be a string of what our user wants to do. We can now generate this using the api-kit:resource generator:

yo api-kit:resource todo isComplete:Boolean title:String

Here we are saying that we want to create a todo model with our different fields and data types.

This will create a few files for us:

  • app/models/todo.js - A Mongoose model describing our model schema
  • app/http/resources/public/todos.js - A set of Express.js routes for standard CRUD
  • app/transformers/todo.js - A Mystique transformer to map data in and out of our API

Using our API

Now, we can serve our API by running npm start.

If we use something like Postman, we can go to http://localhost:3000/api/todos and we'll see the following response back from our API:

{ "todos": [] }

Let's create a new Todo for our app by sending the following JSON to our API as a POST to http://localhost:3000/api/todos:

{ "todo": { "title": "Buy Milk", "isCompleted": false } }

And now the server responds with:

{ "todo": { "id": "56a01982f8630e7f4a771879", "title": "Buy Milk" } }

NOTE Your id will vary

And if we make another GET request to http://localhost:3000/api/todos:

{ "todos": [ { "id": "56a01982f8630e7f4a771879", "title": "Buy Milk" } ] }

What's Next

In the upcoming weeks I hope to document API Kit a bit more including:

  • Deploying to Heroku
  • Creating Related Records
  • User Authentication
  • Interacting with this data from a single page app (likely Ember.js)