AngularJS-large

AngularJS – Weekly Tech Learning

This post is part of my weekly tech learning series, where I take a few hours each week to try out a piece of technology that I’d like to learn.

After last week’s experience with riot.js I decided to experiment with another JavaScript library/framework I’ve been hearing a lot about, AngularJS.

Angular bills itself as a way to extend HTML for dynamic views in web applications. This sounded a bit strange but after seeing how Angular works and embeds itself into HTML, it makes sense.

Documentation

The first place I start with anything new is the documentation. I’m the kind of person who reads the manual for a new camera before using it.

Angular’s documentation really shines. The homepage has videos, several example apps, and there are a ton of resources deeper into the site.

What was really surprising is that Angular exceptions have a link on the JavaScript console that point to the angular website with details about what happened. This made debugging much easier because I could take my specific exception and find out what it meant in the more general sense.

Todo list application with AngularJS

Like my other applications, I built a todo list application with Angular. I’ve done enough of them that I know the scope so I can focus learning how Angular works.

Surprising, one of the demo applications on Angular’s homepage was a simple todo application. If you compare it to mine, you’ll notice I used much of the same code. But I still built my by hand so I can see how it works step-by-step.

Features

Being a todo list, I kept the feature-set short.

  1. Single page app without refreshes
  2. List all open todo items
  3. Add a new todo item
  4. Complete a todo item
  5. Delete a todo item

Since the demo application did most of this, I had extra time to add a basic localStorage persistence feature.

HTML

The first thing I noticed with Angular is that much of its view is put into the HTML. You decorate various elements and sections with ng values to connect them to Angular. This was a bit shocking to me, since years ago there were movements to get JavaScript out of the HTML (unobtrusive JavaScript, progressive enhancement). To see non-standard HTML used by Angular felt odd, like a step backwards.

But if you go back to what Angular’s goals, it makes sense. It wants to extend HTML, which means it will be changing what I’d consider HTML.

The first hiccup I had was getting my controller to connect. I had my ng-app and ng-controller declared, Angular was loading, and everything looked right. But my controller kept appearing as undefined. After some debugging, I found I needed to use ng-app differently than the demo code. I needed to fully declare my app (ng-app vs ng-app='tech-learning').

Once that was in place, things started working like they were supposed to.

Data binding

Like knockout.js, AngularJS puts some control flow and loops directly into the HTML. In my case I needed that for listing each todo item with a standard template (ng-repeat). In that loop, {{todo}} was used to reference the current todo item, just like most templates.

Completing a todo

The interesting thing with the demo application is that they used only the data binding to mark a todo as complete or not. The checkbox has a ng-model="todo.done" which toggles the done value of a todo object. This happens automatically and it also changes the css class for the todo text. With some css, that means it automatically gets a strike-through when it’s completed, right from the checkbox.

This did cause a problem with my localStorage though. Because the view was accessing the model directly, I couldn’t call the function to persist the data. I’m sure if I had more time I could hook up the persistence a bit more transparently so ng-model would automatically save.

Controller (and Model, kinda)

With the HTML page acting as the View, a JavaScript file functions as the Controller. What was odd, coming from a Rails background, is that the Controller also embedded the Model. The Model wasn’t explicitly declared but you could see it.

Maybe this was because a todo list application is simple so it doesn’t need a separate Model. But it still seemed like keeping them together would be a bit of a pain to test and maintain over time.

Much of Angular’s View-Controller connection is done through the scope, or $scope in the code. This seems to be a shared object that the view can access as well as the controller where it’s passed in as a parameter.

Data and behavior defined on this scope object let the View call it. In fact, I guess this ease of callability is what helps Angular be easy to develop with.

load()

The load() function was an addition that I added to support localStorage. Basically it checks localStorage to see if there are any todo items there and returns them.

This works in conjunction with the todos variable which is where the controller tracks the list of todo items (and which the View uses to build its list).

add()

This function has three behaviors:

  1. Add a new todo item based on the form submission
  2. Clear the todo field name
  3. Persist the data to localStorage

The View is hooked up to this through the ng-submit="add()" declaration on the form. This works like a binding that takes the submit events and sends it to the add() function. The name field is also given a ng-model declaration so the controller can access it (e.g. getting the value, clearing).

deleteTodo()

I also wanted to be able to delete a todo item. The deleteTodo() function does this by searching for the todo item and removing it from the todos array.

The interesting thing was that I hooked it up using the ng-click and was able to pass in the current todo from the View. This meant I didn’t have to bother with ids or some unique key to search on.

persist()

The persist() function is just a simple little wrapper for saving the current todos into localStorage.

localStorage compatibility

Based on my experience with localStorage in the past, I’ve created a simple compatibility object for browsers who don’t support localStorage. All it does it mockup the API I need with no-op functions.

(In a larger application, this isn’t the best approach. Feature detection will notice this object and think that a browser actually does support localStorage. So watch out if you try this.)

Final thoughts

That’s it. All together, my AngularJS todo application is around 30 lines of JavaScript with a dozen or so of HTML. It’s one of the smaller ones I’ve built, which isn’t surprising since Angular is supposed to be a higher-level library than others.

Overall though, I wasn’t happy with a few things in AngularJS.

Code in HTML

I strongly dislike putting that much “code” into my HTML. I’ve seen too many teams start with a little bit of code and then they end up with a mess that is impossible to work in. (knockout.js also suffers from this.

With a good team, the right practices, and an eye for problems this could be worked around. But it’s easy to fall off.

(Granted the alternatives aren’t much better: building HTML strings in JavaScript is horrible and JavaScript templates can become a pain too. It’s not an easy problem.)

One plus with AngularJS from what I understand is that you can scope it to a specific part of the HTML document. So instead of one ball of mess, you might have several smaller Angular controllers.

(I also seems like SEO can be a bit of an issue with angular. Some people say angular content is invisible because it’s JavaScript, others say that Google will run angular code and see the content. All I know is that you’ll have to do your own tests if you have a public angular site.)

Large API

AngularJS’s API is large. Even if you’re just looking at the core, there’s a lot there. It seems like it also has its own API for events, which could be interesting if you use jQuery also.

As part of my advancing age, I’m starting to prefer libraries and frameworks with a smaller footprint. Not just in size but also in how many methods/functions they expose. Having less of an API to remember means more of my application can fit in my head.

It was good to see Angular has separated some components out of the core, which reduces both its size and API footprint.

Summary

angularjs-quote

I can see using AngularJS with some applications. I’m not putting it into my general purpose toolkit quite yet, but I’d feel comfortable working with it in an existing codebase.

I also hear the 2.0 version is going to have some significant changes which improve some of the problem areas.

If you’d like to use a demo version of the application, you can find a copy running at http://angular-tech-learning.apps.littlestreamsoftware.com/ with the unminified version of the JavaScript and localStorage.

Need custom JavaScript development?

Code

Basic HTML page with the skeleton structure, ng declarations, and the todo list.

<!-- www/index.html -->
<!DOCTYPE html>
<!--[if lt IE 7]>      <html ng-app='tech-learning'  class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html ng-app='tech-learning'  class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html ng-app='tech-learning'  class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html ng-app='tech-learning' class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width">
 
        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
 
        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/main.css">
        <link rel="stylesheet" href="css/app.css">
    </head>
    <body ng-controller="TodoController">
 
      <h1>Todos</h1>
 
      <ol id="todos">
        <!-- http://mutablethought.com/2013/04/25/angular-js-ng-repeat-no-longer-allowing-duplicates/ -->
        <li ng-repeat="todo in todos track by $id($index)">
          <input type="checkbox" ng-model="todo.done">
          <span class="done-{{todo.done}}">{{todo.text}}</span> 
          <a class="todo-delete" ng-click="deleteTodo(todo)" href="#">(X)</a>
        </li>
      </ol>
 
      <form id="addNewTodo" ng-submit="add()">
        <p>
          <input id="todoName" name="name" ng-model="todoText" />
          <button type="submit">Add</button>
        </p>
      </form>
 
        <!-- JS -->
        <script type='text/javascript' src='js/jquery-2.1.0.min.js'></script>
        <script type='text/javascript' src='js/angular.min.js'></script>
        <script type='text/javascript' src='js/tech-learning-angular.js'></script>
    </body>
</html>

The full angularJS application, including the simple localStorage wrapper.

// www/js/tech-learning-angular.js
// Test if localStorage is present and supported in the browser
if (typeof(localStorage) == 'undefined') {
  localStorage = new Object();
  localStorage.getItem = function(key) { }
  localStorage.setItem = function(key, value) { }
  localStorage.clear = function() { }
}
 
 
var todoApp = angular.module('tech-learning', [])
  .controller('TodoController', ['$scope', function($scope) {
    $scope.load = function() {
      var todosJSON = localStorage.getItem("todos-angular");
      if (todosJSON) {
        return JSON.parse(todosJSON);
      } else {
        return [];
      }
    }
 
    $scope.todos = $scope.load();
 
    $scope.add = function() {
      $scope.todos.push({text: $scope.todoText, done: false});
      $scope.todoText = '';
      $scope.persist();
    };
 
    $scope.deleteTodo = function(todo) {
      var index = $.inArray(todo, $scope.todos);
      if (index > -1) {
        $scope.todos.splice(index, 1);
      }
      $scope.persist();
    };
 
    $scope.persist = function() {
      localStorage.setItem("todos-angular", JSON.stringify($scope.todos));
    };
  }]);
ideal-clients

Ideal Clients

A bit of truth for you: Working with great clients is 100x better than bad clients.

But how do you actually find these great clients?

By focusing on your ideal clients.

An ideal client is a person who is a perfect fit for you and your services. It’s a standard you can measure potential clients against.

But there are two things you must do before you can work with your ideal clients.

First, you need to describe who they are, and what they do. Only once you’ve clearly defined them, then you can start looking for great clients.

(And actually be confident that you’ve found one)

Second, you need to regularly review your ideal client definition. You can make plans and guess all you want, but until you get feedback on your definition you won’t know for sure if you’re right. Regular review helps you process that feedback and adapt to it.

Do this and create a process around it, and your client quality will improve. You’ll work on better projects, with better people, and be happier with your work.

Eric Davis

Want weekly freelancer training?

Redmine Consulting Services Open

My company, Little Stream Software has re-opened its Redmine and ChiliProject consulting services.

If your Redmine or ChiliProject installation needs help, I’m here for you.

  • Maybe your team needs to change the workflows.
  • Maybe you need some expert training on customizations and plugin development.
  • Or maybe you want to extend it to better fit your business processes.

Whatever the reason, if you’re interested you can learn more about how I can help you:

Learn more about my Redmine services

riot.js, minimal MVP – Weekly Tech Learning

This post is part of my weekly tech learning series, where I take one hour each week to try out a piece of technology that I’d like to learn.

Last week I started my tech learning series back up. I’ve been feeling a bit behind with client-side JavaScript libraries so I’m planning a few around them.

To start off, I decided to try out riot.js. Billed as a minimal MVP library that is under 1kb, it felt like a good introduction before getting into the larger Angular or Ember.

Also with my pleasant experiences with knockout.js in the past, I wanted to see if riot.js would be easy add in for an existing server-side application.

Documentation

The approach riot.js takes is to add a small layer on top of regular JavaScript. The benefit here is that if you know JavaScript, its API is so small that you will barely notice it.

One thing that tripped me up was how the documentation and demo applications were built modularity. Once I understood how they plugged together it made sense, but most of my experience has been in monolithic applications.

(I’ve tried to steer client projects to a more modular structure but I’ve never been able to build one from scratch. It’s one thing to refactor towards modularity, another to start with it in mind.)

Todo list application with riot.js

Like my previous articles, the base application I’m building is the vulnerable todo list. It’s a project I’ve done many times and know the scope by heart, so I can explore how the technology side works.

This time I spent a bunch of time to really finalize my Grunt configuration. I’ve been experimenting with it over the past few months and I decided to codify those experiments into a configuration the suited me. While it was great, it did burn up a lot of my time.

Features

Being a todo list, I kept the feature-set short.

  1. Single page app without refreshes
  2. List all open todo items
  3. Add a new todo item
  4. Complete a todo item
  5. Delete a todo item

Nothing crazy.

I also didn’t want to deal with the data storage at this time. For something client-side using localStorage is probably enough but I’ve already built something using it so I didn’t need to explore how it works.

(Also riot.js is supposed to make this quite easy due to its modularity. Design your models with a simple backend API and you can swap them in or out as needed.)

The Single Page App

Since this was a single page app, I needed a base skeleton to hold the app. There’s a list (ol), a form for adding new todos, and a embedded JavaScript template for each todo item.

The final piece was to initialize and start riot.js. Initialize was easily done by calling my application’s function (todo()) with its initial configuration. As you’ll see later, this created a singleton instance of my TodoList object (a model).

One area that threw me for a few nested loops was the SPA module I copied from a demo program. This module did several things:

  • it created a singleton instance for the app
  • it would return than instance when the function was called (todo())
  • when passed a function, it would layer that function on the instance. Thereby making this new function act as a presenter layer.
  • it would initialize my TodoList model to hold the TodoItems
  • finally it would trigger the “ready” event, which presenters could listen for

All this is about 16 lines of code. Three different ways to call it (todo(), todo({..}), todo(function())). As you can imagine, this took a bit of time to understand and figure out.

Mixed with the fact that I forgot to trigger the ‘ready’ action myself, meant that I was doing some deep debugging before I understand what was happening. Once I added that, it worked exactly how I was described. Basically when the DOM is ready (from jQuery), my application is told that, and it runs any functions that were waiting on the DOM (e.g. rendering the list).

Models

Once I got everything hooked up, development started going really well. The model development in particular was easy. Models in riot.js are just basic objects that have the ability to trigger and listen for events (Observers, using riot.observable).

In this case my models didn’t use any events, they were just data stores operating on a single data structure, the todo items. Adding meant adding the TodoItem to the end of the list, completing wrapped the name in <strike>, and deleting removed the item from the list.

The real magic happened in the presenter.

Presenter

As explained above, the presenter function is layer on top of my application’s API which was just a model in this simple case.

The presenter does five different things (originally, it was actually five different presenters layered on top but it made sense to combine them into one. This is where the modularly can be handy, if you need to split up or combine presenters you can and they’d end up working the same)

  1. Listen for the form submission for adding a new todo item
  2. Listen for any clicks to complete a todo item
  3. Listen for any clicks to delete a todo item
  4. Listen for any events to redraw the list
  5. Initialize the first loaded view

If you look at the code below for the presenter’s Add, Complete, and Delete areas they are basic JavaScript/jQuery event logic. Bind on an event, run a function. Complete and Delete are ultra simple, just call the app’s function for each and then trigger a ‘list’ event to redraw the list. (app.trigger('name') is how riot.js creates new events that objects are listening for).

Add is a bit more complex because it’s working with the form. Instead of just calling the add() function, it has to pull the value out of the field, check that it’s not empty, and then clear the field when done. Nothing really out-of-the-ordinary with jQuery but it’s worth pointing out that all of this UI logic is contained in the presenter (unlike many other applications I’ve been brought in to help with).

Now the fun parts. Instead of using jQuery bindings, list is using riot’s on() function to setup a callback function when the “list” event is triggered. When this happens, the list is cleared and each item in the todo items from the model is added to the todo list. I used riot’s template rendering using the render() function and passing in each todo item. This meant my todo template (in the HTML) could access every property and riot would substitute the values before returning the final string.

The final part of the presenter is listening for the “ready” event. When this happens, the presenter knows the DOM is done and renders the first version of the page. In this case, the only dynamic thing needed is the list. Instead of duplicating how the list is rendered, the ‘list’ event is triggered which uses the list code.

Entire flow

It can be hard to see how this all goes together so here is the basic application flow from start to finish.

  1. Page loads.
  2. When the JavaScript is parsed, the presenter is added. This happens because the presenter is using todo(function()) which executes immediately. This hits the 2nd section of the todo function (labeled as SPA) which listens for the “ready” event.
  3. todo({..}) is called with a few initial, hard-coded todo items (which would be where I’d get them from the backend if I used one)
  4. That hit the 3rd section of the todo function in SPA
  5. A new TodoList was created with the todo items, which due to TodoList’s extend populated the items with the initial data
  6. Then back in todo() the instance of TodoList starts listening for the “ready” event.
  7. Sometime later the DOM finishes loading so the jQuery ready block in the HTML runs and triggers the ‘ready’ event
  8. The instance gets this ready event (3rd part of SPA) and triggers its own ready event passing in the instance as a parameter (the TodoList aka the application).
  9. This executes the presenter which sets up its own event observers (riot and jQuery) as described above.
  10. Finally the application is fully booted.

Adding a new todo item would flow like this:

  1. You enter the item into the field and click submit
  2. The presenter receives the submit event in Add, blocks it, and calls TodoList.add()
  3. add() create a random-ish id and appends the new TodoItem to the list of items
  4. Flow falls back to the presenter which resets the field, clearing it
  5. A ‘list’ event is triggered
  6. The presenter’s List observer receives the event, empties the list, and re-renders it based on the current list of items.

(As you might have noticed, I’ve had to refer to each section of the presenter by the section name given in the comments. This makes a good case for having multiple presenters which you can name separately. Even if it causes a bit more code, communication would be much easier which is a net win for any team)

Summary

All said and done, experimenting with riot.js was fun and productive. This entire process took a few of hours, some of which included reading documentation and demo code (and configuring grunt). There was more code here than in my knockout.js version but I didn’t have to embed logic into the template like I did in knockout.js (my main complaint with knockout). Instead, riot.js used custom events to handle behavior which has always been something I found useful for structuring JavaScript applications (and something I’ve done manually).

One thing I didn’t get to do was to really tease apart the model and application layers more. Right now my model and application are pretty much the same thing, which happens with such a simple concept. I’d imagine a larger application with more models would have a clearer separation between each layer.

All in all, I’m going to add riot.js to my regular toolbox. I feel it’s useful when you need a lightweight MVP library but don’t want a lot of overhead with it. Also since it’s mostly vanilla JavaScript, it should be easy to adapt to a heavier library later on should the need arise.

If you’d like to use a demo version of the application, you can find a copy running at http://riot-js.apps.littlestreamsoftware.com/ with the unminified version of the JavaScript.

Would you like to hire me?

Code

Basic HTML page with the skeleton structure and the todo item template.

<!-- www/index.html -->
<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width">
 
        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
 
        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/main.css">
        <link rel="stylesheet" href="css/app.css">
    </head>
    <body>
      <h1>Todos</h1>
 
      <ol id="todos">
      </ol>
 
      <form id="addNewTodo">
        <p>
          <input id="todoName" name="name" />
          <button type="submit">Add</button>
        </p>
      </form>
 
 
        <!-- JS -->
        <script type="text/tmpl" id="todo-item-tmpl">
          <li data-key="{item.id}">
            <a class="todo-complete" href="#">[ ]</a>
            <span>{item.name}</span> 
            <a class="todo-delete" href="#">(X)</a>
          </li>
        </script>
 
        <script type='text/javascript' src='js/jquery-2.1.0.min.js'></script>
        <script type='text/javascript' src='js/riot.min.js'></script>
        <script type='text/javascript' src='js/tech-learning-riot-js.js'></script>
        <script>
          // Initialize
          todo({items: [
            {name: "This is a test", id: 1},
            {name: "Need to do this too", id: 2},
            {name: "<strike>Done</strike>", id: 3}
          ] });
          // DOM ready so start the app
          $(function() { todo().trigger('ready'); });
        </script>
    </body>
</html>

The riot.js application. Normally you’d put each model in its own file in a directory and separate the presenters from the application API. But since this was a small app, they are combined into one file with comments to separate them.

// www/js/tech-learning-riot-js.js
function TodoList(configuration) {
  var self = riot.observable(this);
 
  // Requires an array of TodoItems
  $.extend(self, configuration);
 
  self.add = function(name) {
    var id = Math.random() * 1000000;
    var data = {name: name, id: id};
    var todo = new TodoItem(self, data);
    self.items.push(todo);
  }
 
  self.complete = function(id) {
    var itemAsArray = $.grep(self.items, function(item) { return item.id == id});
    if (itemAsArray.length > 0) {
      var item = itemAsArray[0]; // Assume only one
 
      if (item.name.match(/<strike>/)) { return false; }
      var index = $.inArray(item, self.items);
      item.name = "<strike>" + item.name + "</strike>"
      self.items[index] = item;
    }
  }
 
  self.delete = function(id) {
    self.items = $.grep(self.items, function(item) { return item.id != id});
  }
}
 
function TodoItem(app, data) {
  var self = riot.observable(this);
 
  $.extend(self, data);
}
 
// SPA
var instance;
 
window.todo = riot.observable(function(arg) {
  // todo()
  if (!arg) return instance;
 
  // todo(fn) to add a new module
  if ($.isFunction(arg)) {
      console.log('spa2'); 
    window.todo.on("ready", arg);
  } else {
    // todo(conf) to initialize the application
    instance = new TodoList(arg);
      console.log('spa3'); 
 
    instance.on("ready", function() {
      console.log('spa3-ready'); 
      window.todo.trigger("ready", instance);
    });
  }
});
 
// Presenters
todo(function(app) {
      console.log('pres-parse'); 
 
  var root = $("#todos");
  var template = $("#todo-item-tmpl").html();
 
  // Ready
  app.on("ready", function(view) {
      console.log('pres-ready'); 
    app.trigger('list');
  });
 
  /// Add
  $("#addNewTodo").submit(function(e) {
 
    e.preventDefault();
    var name = $("#todoName").val();
    if (name) {
      app.add(name);
    }
 
    this.reset();
 
    app.trigger('list');
  });
 
  /// List
  app.on("list", function(view) {
    root.empty();
 
    $.each(app.items, function(i, item) {
      root.append(
        riot.render(template, { item: item }));
    });
  });
 
  /// Complete
  $('body').on('click', '.todo-complete', function(e) {
    e.preventDefault();
 
    app.complete($(this).parent().data('key'));
 
    app.trigger('list');
  });
 
  /// Delete
  $('body').on('click', '.todo-delete', function(e) {
    e.preventDefault();
 
    app.delete($(this).parent().data('key'));
 
    app.trigger('list');
  });
});
tEREUy1vSfuSu8LzTop3_IMG_2538

Should you bill by the hour, week, day, or month?

The topic of changing your billing frequency comes up often.

Most freelancers I know bill by the partial hour, with a few billing in units larger than that (and some freelancers bill by the minute using stopwatch timers). I can understand the feeling that you too need to bill by the same units as everyone else in the industry but that doesn’t mean you have to copy everyone’s billing method.

Value trumps how you bill

Once you’ve gained the trust of a client and started building a relationship with them, your rates don’t matter as much as we freelancers tend to think. As long as the client is getting above a specific amount of value for what they are paying for and we aren’t charging them more than they expect, most don’t worry about our rates.

If a client has a budget of $5,000 allocated for you, it doesn’t matter much if you charge $4,500 or $4,415, or even $4,000. The larger the organization, the more you can see this indifference to the per-unit cost.

Fit the billing to the project

So the question of which per-unit price to use comes back to what makes sense for the project and what you’re comfortable using.

For a monthly retainer contract, a per-month price would be best because the client isn’t getting X hours of your time, they are getting access to you for the “month of June”.

For more of a contracting project, where you’re expected to be around and working for a set number of hours, an hourly rate makes sense. A daily rate could also work if you limit the total time worked (e.g. overtime).

On an on/off contract schedule, it’s best to pick a unit that matches your schedule. If the client is scheduled for a week at a time, per-week billing is best. If it’s three days at a time, per-day billing is best.

Tracking your time (optional)

Now even if you aren’t billing a client by the hour or minute, tracking that data still could be valuable for your business. I’ve been tracking my billable and non-billable time since I started freelancing in 2007 so I can run reports to see where I’m spending my time.

In the past I noticed that I was spending up to two hours in email everyday, so I used those metrics to make a decision to cut way back on email. Now it’s more like an hour or two per week.

Setting your new unit rate

Setting your rate is a pretty huge topic, with entire books written on how to calculate or figure out what rate you should charge.

If you’re a new freelancer, I cover setting your rates in 30 Days to Become a Freelancer. You can also use an online calculator but those have their own set of problems. Primarily, they are too cost-focused.

If you’re an experienced freelancer who already has a set rate, taking a first guess at what your different per-unit rates is easy. Remember, you have clients who are paying your existing rate already. Some clients might already be getting your time in large chunks like full days or weeks so you’re already charging per-unit rates now but you haven’t formalized it yet.

Since most freelancers I know state their rate in terms of per-hour, I’m going to start with that as the base.

per-hour rate

The rate you charge now.

per-day rate

Based on a busy but not an excessively long day, how many hours did you work? Times this by the hourly rate to get your per-day rate.

When I focus get around 6 hours of productive work each day for a client. Anymore than 6 and it affects my productivity the next day. So my daily rate is around 6x my hourly rate.

per-week rate

If you go on the assumption that you are working a full 5 day workweek, just multiply your per-day rate by 5. If you have a shorter week, lets say you take a three day weekend every week or maybe you have an administration day each week, adjust as needed.

I work 5 days a week so my per-week rate is 30x my hourly rate.

per-month rate

Finally we get to your per-month rate. I found multiplying your per-week rate by 4 is a good estimate, you can get closer but you’ll have to adjust for holidays and other oddities. As you’ll see in a minute, we are just looking for ballpark numbers right now.

So my per-month rate would be 120x my hourly rate.

I know 120x is a good estimate for me because I used to plan out every month to figure out the number of billable days and calculate to the hour how much availability I could sell. More often than not, each month came out to 20 billable days, which based on 6 hours of working per day would be 120x my hourly rate.

NOTE: You’ll notice I didn’t put calculations in for per-quarter or per-year rates. I think these are so rare that you don’t need to calculate them upfront. You can always use the per-month rate if you needed to.

Review for confusion

The next step is to look at each of your per-unit rates and see how they feel to you. You’ll want to round some of them, or maybe adjust them so they feel more comfortable to you. Just don’t adjust them down to make them too comfortable, you don’t want to give a discount just because your per-month rate is large. You would be billing that much if you had a month-long project at your hourly rate.

Let’s put these calculations through a few examples. With the base hourly rate of $85/hour and a 6 billable hour day, the per unit rates would look like this:

  • per-hour: $85
  • per-day: $510
  • per-week: $2,550
  • per-month: $10,200

Now these numbers look a bit odd so let’s round them up a bit. Remember that the per-day rate is based on an estimated amount of time you can bill in a day, so if we are rounding up a lot we can counter that by working a bit longer as needed (e.g. 6.5 hours, 7 hours).

  • per-hour: $85
  • per-day: $550
  • per-week: $2,750
  • per-month: $11,000

Now lets look at what a $150/hour rate looks like:

  • per-hour: $150
  • per-day: $900
  • per-week: $4,500
  • per-month: $18,000

Part-time freelancers

This process can be done by part-time freelancers too. Just adjust the number of hours per day and the days per week to fit your schedule.

Hopefully this gives you some ideas to break away from the per-hour and per-minute billing rut. Not only will you feel less pressure but your billing will become clearer to your clients.

Want weekly freelancer training like this?

Helping new entrepreneurs build a successful software business.

Need more freelance clients?