olibarnesdevstuff-blog
olibarnesdevstuff-blog
Dev stuff
11 posts
Don't wanna be here? Send us removal request.
olibarnesdevstuff-blog · 10 years ago
Link
With the latest release of Ember Simple Auth, using the library with ember-cli has become much simpler. As ember-cli in general is still pretty new to many people though, this post describes how to setup a project using Ember Simple Auth with ember-cli.
Setting up the basic project
First...
6 notes · View notes
olibarnesdevstuff-blog · 11 years ago
Link
The long-standing issue of how to know what the user has typed in the url has been resolved by our remote miracle-worker Piotr Sarnacki. I had read just about every search result pulled up by Google and I have become intimately close with the Discourse source code in countless attempts to find out...
4 notes · View notes
olibarnesdevstuff-blog · 11 years ago
Text
Ember Controllers as Presenters
Confused about routes vs controllers in Ember? Reading this Ember forum thread might help. Here are the parts I keep going back to:
michaelrkn asks where to put a save action, something not readily clear since Ember lets you define an action on either a route or a controller. He sums up his frustration:
Two things make me dislike the ability to define actions in multiple places: when I come to a new Ember project and I see an action in a template, I need to check two places to figure out where it’s defined; and if I ever change an action from staying on the same route to moving to a new route, I need to move it from my controller to my route. Both of these feel like unnecessary work and confusion.
Work and confusion that will get worse as your routing table and number of controllers and templates grow.
Alex Speller explains his own approach to organizing things:
I’d generally recommend putting actions on routes in preference to controllers, especially if you’re going to do things like transition, which is a routing concern and not a controller concern. Controllers are there to store your in-memory application state, wrap your models to present them to your templates, and connect your models together using dependency injection. Routes should be where the bulk of your logic and actions live. In my experience you will find your application easier to maintain if you keep your controllers as skinny as possible.
Complementing with:
The exception would be UI only actions on controllers. An example would be an action that shows or hides a part of the UI by setting an isVisible property on the controller or something - in that case a tight coupling of controller and template makes sense.
opsb points out:
if all actions are moved to the routes, are we not just using controllers as presenters and routes as controllers?
Speller:
Yes, this is the point and is intended. They are misnamed IMO. Or more accurately, they are not supposed to be viewed the same way as controllers in rails would be. Routes in ember are much more like controllers in rails.
After that, the intro to controllers on Ember guides made a lot more sense to me:
In Ember.js, controllers allow you to decorate your models with display logic. In general, your models will have properties that are saved to the server, while controllers will have properties that your app does not need to save to the server.
Replace ‘controllers’ with ‘presenters’ there and everything falls into place.
This presentation by Matthew Beale, also mentioned on the thread, goes more in-depth into how actions work and the process of architecting an ember app. The video is well worth a watch too.
Written with StackEdit.
0 notes
olibarnesdevstuff-blog · 11 years ago
Text
Getting setup with Ember CLI, Emblem, EasyForm, Mocha and Chai
This is how we managed to get this stack going for Participate for now. It should be a lot easier soon, when ember cli addons come out for mocha and ember-form.
Installing Ember CLI
Just install the npm package for it. You’ll also need PhantomJS:
npm install -g ember-cli npm install -g phantomjs
Then generate an ember-cli app:
ember new yourapp
Installing Emblem
Cd into your generated app’s directory and then install the broccoli-emblem-compiler package locally with --save-dev:
cd yourapp npm install --save-dev broccoli-emblem-compiler
Installing Easy Form
No addon available yet, but It’s easy enough to install it by following these two steps I got from this github issue thread :
1) Add an easy-form build to bower.json
{ "dependencies": { "ember-easyForm": "http://builds.dockyard.com.s3.amazonaws.com/ember-easyForm/canary/ember-easyForm.min.js", } }
Here’s a list of builds
Don’t forget to run bower install.
2) Add this initializer under app/initializers/EasyForm.js
import Ember from 'ember'; import 'vendor/ember-easyForm/index'; export default { name: 'configure-ember-easy-forms', initialize: function( container, app ) { var options = {}; Ember.EasyForm.Config.registerWrapper('default', options); Ember.EasyForm.Submit.reopen({ disabled: function() { return this.get('formForModel.disableSubmit'); }.property('formForModel.disableSubmit') }); } };
Not bad, right?
Now comes the painful part:
Installing the adapter for Mocha
These steps laid down on another github issue worked for us, after some tweaking and help from the guys on that thread:
Add test dependencies to index.html
Add the new test dependencies to the app tree Brocfile.js
Turn off hinting because the generated tests are QUnit and will explode.
Manually run the tests in test-helper.js. Not a big fan of this approach honestly.
Changed qunit to mocha in testem.json
Here are my relevant files, for reference:
Brocfile.js bower.json tests/index.html tests/test-helper.js testem.json
I’d list the changes made or provide the specific diffs if I could, but the process was a little too convoluted to keep track of.
Here’s a test using this setup. You’ll notice it doesn’t use describe() blocks - it’s not supported by this provisional setup yet, but should be soon.
Feel free to reach out if you run into trouble.
Written with StackEdit.
0 notes
olibarnesdevstuff-blog · 11 years ago
Text
Learning Behavior-Driven Development with Ember CLI - part I
This tutorial walks through BDD‘ing a feature with Ember CLI, Mocha and Chai.
I’m writing it as I learn Emberjs, its way of doing things and its toolset, and try to adapt my usual workflow coming from Ruby. It’s meant as an initial guide for the RGSoC team working on Participate. Hopefully this post will be helpful to others learning Ember as well, and even better, invite people to show how they’re doing things themselves in the comments.
The feature I’ll build here in baby-steps will be Posting a New Initiative. In Participate, a user can post proposals for civic initiatives, to which other users can then suggest changes, and then vote on.
This first installment will involve nothing but filling out a simple form with a title and a description, and submitting it. The next installment will add validation checking both fields are filled-in.
As the feature gets incremented - an initiative must have an author and belong to an issue, for instance - new installments will come describing the process of adding them in. At some point I’ll talk about integrating with the separate API backend app.
Setup
Besides Ember CLI, Mocha and Chai, we’ll also use Emblem and EasyForm.
I go through installing all of them on another blog post.
Once you you got them and have generated your app (we’ll assume it’s called ‘post-initiative’ here in the tute), create a new file app/adapters/application.js and add this line to it:
export default DS.FixtureAdapter.extend();
This defines we’ll be using fixtures, so we don’t need to worry about the backend for now.
Starting with an acceptance test
Let’s start with a test that drives the interface, describing user interactions and expectations first, then implement these by letting test errors be the guide as much as possible.
Create a file named posting-an-initiative-test.js under tests/acceptance.
import startApp from 'post-initiative/tests/helpers/start-app'; import Resolver from 'post-initiative/tests/helpers/resolver'; var App; suite('Posting an initiative', { setup: function(){ App = startApp(); }, teardown: function() { Ember.run(App, 'destroy'); } });
Let’s add a test for a link to create a new initiative:
test('Successfully', function(){ visit('/').then(function() { click( $("a:contains('Start a new initiative')") ).then(function() { expect(currentPath()).to.equal('/initiatives/new'); }); }); });
And, from the command line, run ember test:
➜ post-initiative git:(simple-new-initiative) ✗ ember test version: 0.0.37 Built project successfully. Stored in "/Users/work/Projects/post-initiative/tmp/class-tests_dist-Bv3r6aYr.tmp". not ok 1 PhantomJS 1.9 - Posting an initiative Successfully --- message: > Error: Element [object Object] not found.
The key here is the message output. The opaque error means Jquery hasn’t found the link.
And understandably so, since it doesn’t exist yet.
Link to new initiative
Let’s implement it by adding it to application.emblem, under app/templates.
h2 Participate App #menu = link-to 'initiatives.new' | Start a new initiative =outlet
Run ember test again and you’ll get a new message:
message: > Assertion Failed: The attempt to link-to route 'initiatives.new' failed. The router did not find 'initiatives.new' in its possible routes: 'loading', 'error', 'index', 'application'
Route
In the router (app/router.js), let’s add a route to a new initiative resource:
Router.map(function() { this.resource('initiatives', function() { this.route('new'); }); });
Tests should pass now.
1..1 # tests 1 # pass 1 # fail 0 # ok
This is the basic flow. Let’s add another expectation:
Adding the template and form for the new initiative
After clicking the link, the user should be able to fill in a title for the initiative. Add this line to the test
fillIn('div.title input', 'Public health clinic');
So it now looks like this:
test('Successfully', function(){ visit('/').then(function() { click( $("a:contains('Start a new initiative')") ).then(function() { expect(currentURL()).to.equal('/initiatives/new'); fillIn('div.initiative div.title input', 'Public health clinic') }); }); });
Run the test again:
message: > Error: Element div.initiative div.title input not found.
To satisfy this, let’s create a template, and in it our form:
Create a directory initiatives under app/templates, and then add a file called new.emblem.
Paste the following in it:
form-for model = input title
Run the tests again, and they should pass.
Let’s add the remainder of the form-filling steps in our test:
visit('/').then(function() { click( $("a:contains('Start a new initiative')") ).then(function() { expect(currentURL()).to.equal('/initiatives/new'); fillIn('div.title input', 'Public health clinic'); fillIn('div.description textarea', 'Allocate compensation money to create a local public health clinic'); click('form input[type=submit]'); });
Running the tests again will give us:
message: > Error: Element div.description textarea not found.
Add the next input field and the save button to the form:
form-for controller = input title = input description as="text" = submit
The tests should now pass again.
Of course, submitting the form doesn’t do anything yet :)
Submitting the form
So what would a user expect to see after submitting the form. Likely she’ll:
Expect to see the url change
Expect to see the new initiative’s content so she can be sure it went through correctly.
She would also expect a confirmation message, but testing that is a little more involved from what I could find so far. So I’m leaving it for a later installment.
Let’s add these expectations within a then() function chained to click():
click('form input[type=submit]').then(function() { expect(currentPath()).to.equal('initiatives.show'); expect(find('.title').text()).to.equal('Public health clinic'); expect(find('.description').text()).to.equal('Allocate compensation money to create a local public health clinic'); });
then() returns a “promise”, and writing the expectations in a callback passed to it means they’ll get run once click() is done and the resulting rendering is finished. Promises can be a confusing concept at first (I’m still grokking them), but powerful - they let us not worry about all the issues coming from async events.
Run the tests:
message: > AssertionError: expected 'initiatives.new' to equal 'initiatives.show'
To satisfy this and get to the next error, we’ll need to take a few steps, inherent to how Ember wires routes and data being passed around. The errors I got when going through each of the steps weren’t very informative, and I got things working by trial & error & lot of googling and asking things on #emberjs. So I’m pragmatically breaking tdd here and just wiring enough to get to a useful error.
(For more info on what these steps are about, read the Ember guides on routing and controllers, and this thread on Discuss, which clarified things a lot for me. Ember’s architecture is still a moving target.)
First, let’s add this route handler for app/routes/initiatives/new.js:
import Ember from 'ember'; var InitiativesNewRoute = Ember.Route.extend({ model: function() { return this.store.createRecord('initiative'); }, actions: { submit: function() { this.transitionTo('initiatives.show'); } } }); export default InitiativesNewRoute;
And this model definition (app/models/initiative.js) to go with it:
var Initiative = DS.Model.extend({ title: DS.attr('string'), description: DS.attr('string') }); export default Initiative;
Next, update the router (app/router.js) to include a path to /initiatives/show:
Router.map(function() { this.resource('initiatives', function() { this.route('new'); this.route('show'); }); });
And add the corresponding template (app/templates/initiatives/show.emblem). It can be empty for now.
Run the tests and we’ll get
AssertionError: expected '' to equal 'Public health clinic'
Which means that we got the route transition to work, and are now looking at this test:
expect(find('.title').text()).to.equal('Public health clinic');
We made some progress. So far the user can:
navigate to our app’s homepage
click on the link for a new initiative
fill in a form with the title and description for it
submit it
get redirected to the created initiative page.
But there’s no initiative created yet. Let’s tackle this next:
Handling the form submission
Here I’m also going to wire a few things up to get to the next test error.
Let’s update InitiativesNewRoute to handle the submitted params, and then transition to /initiatives/show/:initiative_id
var InitiativesNewRoute = Ember.Route.extend({ model: function(params) { return this.store.createRecord('initiative', params); }, actions: { submit: function() { var _this = this; var initiative = this.get('controller.model'); initiative.save().then(function(model) { _this.transitionTo('initiatives.show', model.get('id')); }); } } });
Update the router to accept the :initiative_id segment:
this.resource('initiatives', function() { this.route('new'); this.route('show', {path: '/:initiative_id'}); });
Create a InitiativesShowRoute (app/routes/initiatives/show.js) to fetch the initiative model:
import Ember from 'ember'; var InitiativesShowRoute = Ember.Route.extend({ model: function(params) { return this.store.find('initiative', params.initiative_id); } }); export default InitiativesShowRoute;
And, finally, a new template for showing the initiative (app/templates/initiatives/show.emblem)
.title h2 model.title .description p model.description
Run the tests and they should pass.
Start up ember-cli’s server by running ember serve, and point your browser to http://localhost:4200/, for a good sanity check. If everything went well, this tiny feature should just work :)
Coming soon: Adding validations
Written with StackEdit.
4 notes · View notes
olibarnesdevstuff-blog · 11 years ago
Text
Why teach kids how to code?
Answer to a question on Quora, with great answers already, but thought I'd add my 2 cents:
Software is changing the world on a scale compared by many to the first industrial revolution. It expresses the opinion of its creators. Facebook implements Mark Zuckerberg's ideas about what a networked society should be, how people should act in it, about privacy, among other things. Free software of different kinds put in practice ideas about freedom of information, about tools being free to be shared and modified, about collaborative production of value, among many others.  Software is opinion, and the different kinds of software are dialoguing, clashing, competing. It's growing a new culture, a new economy, a new society. People who have no base knowledge of programming (and software, and the internet, more broadly) have very little input in this debate. They don't understand how it works on its most fundamental level, and so it's very hard to propose alternatives, or even discuss them at all. Mostly they can only consume passively what's given to them, act as customers (and assets, as data sources). Even major intellectuals trying to make sense of these changes struggle because they don't have this foundation. It's a major literacy problem. And it's not just about 'functioning in society', or taking advantage of the job opportunities, but most importantly, it's about being an agent in this process. It's about enabling participation, as a citizen. The same narrow comment could be made about reading, kids don't want to spend all day shackled to books. Reading and coding can be fun, and one doesn't need to do them all day to learn them either.  Being shackled to anything sucks. Learning to code is liberating, that's the whole point.
0 notes
olibarnesdevstuff-blog · 11 years ago
Link
I’ll introduce a new pattern for testing, against external APIs (like HTTP.get()) with ruby 2.1 refinements instead of Dependency Injection.
"Interceptor Injection pattern" is a word coined by me. Better idea for this pattern is always welcome.
code
Our application or libraries call many…
2 notes · View notes
olibarnesdevstuff-blog · 12 years ago
Text
Testing flow recipe
Pick a user story, a feature narrated from the point of view of a user, with clear, concise scenarios and some wireframes. If you don't have these, create them with whatever stakeholder close to that feature. No need to be exhaustive. Create either a Rspec integration test or a Cucumber feature based on this, using capybara to drive the steps.   Run it, follow the errors and implement accordingly. Write unit tests to drive the design of models and libs, and to controllers in case of special behavior. When done, pick the next scenario and do the same. When done with all scenarios, show it to the stakeholder, get feedback. Tweak, and perhaps add newly discovered scenarios. Sometimes toss the feature altogether and start-over. Deploy, moment of truth, gather user feedback, review stories and scenarios in light of them, tweak, update.  Repeat
(In answer to How do you typically test your Ruby on Rails application? on Quora) 
0 notes
olibarnesdevstuff-blog · 12 years ago
Link
When making requests to an external service’s API, some requests will frequently occur with the same parameters and return the same result. If we cache our request or response, we can reduce HTTP requests, which can improve performance and avoid hitting rate limits.
15 notes · View notes
olibarnesdevstuff-blog · 12 years ago
Link
Ruby comes with many fantastic Enumerable methods, but the two most useful ones come through Smalltalk via LISP: #map and #inject. What follows are some lengthy method definitions followed by rewrites that are not only more concise but also more clear in their intentions.
10 notes · View notes
olibarnesdevstuff-blog · 12 years ago
Text
Well-written code and constant refactoring == fast sustainable development
Originally posted as an answer to this question on Quora
The "just get it working" and "cut corners" practice is a slippery slope that quickly leads to a quagmire. And by quickly I don't mean months, but weeks from initial development. The messy, untested code becomes brittle and exponentially harder to work with and extend. And progressively harder to refactor and to add a proper test suite on after the fact.  The initial illusion of speed is quickly replaced by crawling slow delivery, and a LOT of time spent debugging.  Many man-hours start being spent just figuring out what a chunk of code was supposed to do and how it's affecting the rest. The kudos the dev teams gets initially for getting that prototype out the door gets forgotten, replaced by growing pressure from management for more of the same, perceived initial "speed". No matter how much the CTO or lead developer reminds the other managers of the trade-off that was made initially (which gets renewed as time goes by, since that "stop everything to refactor and add tests" time never comes), with the blessing and sometimes the imposition of the latter, the blame for the perceived slower speed is increasingly put on the dev team. After all, that's where the bottleneck is, right? That can, and often does, lead to political conflict that festers quickly. More overhead. And general unhappiness... And disgruntled devs, who on top of the bad code they have to deal with, have a whole company looking at them as if they are slackers, often after many late nights and weekends put in, all for sub-market pay. Disgruntled devs start leaving for greener pastures. And then you have a revolving door problem. Finding new devs, and then getting them up to speed on... a black-box of a code-base, brittle, untested, running live on production. Oh, and that ninja dev who wrote the code so "quickly" isn't there to explain how he got to that point. And no docs around, since that's... just a corner to cut, right? Go back to the top and start again. It's an endless loop that usually ends in a crash, or at least a lot of stress for all involved.
And a lousy product.
1 note · View note