Django, Backbone, Handlebars

My whole programming career, I’ve defined myself as a back-end programmer. I know some javascript, but I feared CSS and the seemingly nit-pickyness of front-end coding.

Presently, I’m  building my own site for PinTheParty, and I *really* don’t want to bring another developer into the mix. I need to figure out how to do this on my own. I also need to redefine myself as a full-stack developer.

I’ve decided to use Python/Django with Backbone.js and Handlebars. There are many blog posts about bringing these and other frameworks together. But nothing exactly the way I wanted to do it. So I’m documenting my setup here.

      • First: Build the HTML page, including a template to use with Handlebars
        The venue_list div is where we will inject our rendered html from a Handlebars template. I’m also showing the js includes at the bottom. I’m using a library called ‘require’ to help organize all the js dependencies. This way, I don’t need to include all the js in the html, I can refer to it in each html’s supporting js file.
      • <div class="col-md-7">
             <div class="row search-results">
                 <div class="entry-searching-header">Searching "bake cupcakes"</div>
                 <div class="entry-header">25 results</div>
                 <div id="venue_list">
        
                 </div>
             </div>
         </div>
        ....
        <script data-main="/static/scripts/main" src="/static/scripts/require.js"></script>
        <script src="/static/scripts/venues.js"></script>
      • Second: Build the template contents using Handlebars tags in mark injection points.
        {{#each venues}}
        <div class="entry">
          <div class="row">
            <div class="col-md-6">
              <div class="entry-title"><a href="/venue/{{slug}}">{{name}}</a></div>
              </div>
            <div class="col-md-3 entry-cost">{{cost}}</div>
            <div class="col-md-3">
              <img alt="" src="/static/imgs/gograph_blue_ribbon.jpg" width="12px" />
            </div>
            <div class="row">
              <div class="col-md-12">
              <div class="entry-category">{{categories}}</div>
              <div class="entry-quote">{{quote}}</div>
            </div>
        </div>
        {{/each}}
      • Third: Build the supporting Backbone Model, Collections and View.
        I used one file to contain the Model, Collections and View to keep things simple. Notice, this is also where I use the require library at the top to help include required js dependencies, such as Backbone!  There are a couple choices I made.

        • I’m using an api to deliver the json
        • I fetch the data for the collection when it is first initialized. Because this is an asynchronous call, I need to make sure the template is injected when the data arrives. This is accomplished by setting “reset : true” in the call to collection.fetch and binding the render function call to the reset event. (By default the fetch will call “add” for each item in the json array)
        • When a collection receives json data and populates the associated models it expects an array of items. This is what I’m returning from the /api/vi/venues call. However the Handlebars syntax I’m using, {{#each venues}}, expects a parent element. So I add “venues:” when I pass the json to the template
        • There are two require blocks at the beginning of the file. The inner, nested require block is to include all the dependencies for this js file. The outer, require block is to load min.’s — the configuration file for require.js . Require.js recommends you use ONE main.js file to set the baseUrl as well as include js libraries that are used across the application. I don’t know if this is the best solution (nested require statements) but due to the way main.js is loaded (asynchronously using the data-main script attribute), I needed to make sure main.js is loaded before referring to its elements (i.e. backbone, underscore..)
require(['main'], function() {
	require(['jquery',
	        'underscore',
	        'backbone',
	        'handlebars',
	        'libs/text!../templates/parts/venue_list.html'],function($,_,Backbone,Handlebars,ListTemplate){

	    var Venue = Backbone.Model.extend({
	        defaults: {
	            name: 'My Favorite Place',
	            slug: 'my-favorite-place',
	            cost: '$$$',
	            quote:'Good for all ages with extremely helpful and competent staff!'
	        }
	    });

	    var VenueList = Backbone.Collection.extend({
	        model: Venue,
	        url: '/api/v1/venues',

	        initialize: function(){
	            this.fetch({reset:true,
		              success: function(collection, response) {
			          }
			    });
	         }
	    });

	   var venues = new VenueList;

	    var VenueListView = Backbone.View.extend({
	        el: '#venue_list',
	        // The collection will be kept here
			collection: null,

	        initialize: function(options) {
		        this.collection = options.collection;
			    // Ensure our methods keep the `this` reference to the view itself
			    _.bindAll(this, 'render');
			   this.collection.bind('reset', this.render);
			  },

	        render: function() {
		       var template = Handlebars.compile(ListTemplate);
		       var html = template({venues:this.collection.toJSON()});
		       this.$el.html(html);
	           return this;
	        }

	    });
	   	var myList = new VenueListView({
		      collection: venues
		});
	});
});

Table view on top of horizontal scroll view

I created an app with a UITableView main screen. There are about 12 rows in my table each used to describe a particular characteristic of an item for sale, including the ability to upload photos of the item. Simply stated, the user can tap each row to be brought to a detail screen. After entering their selections the user returns to the main table view.

Image

To add photos to an item, you click on the row labeled “More Photos” and are brought to a photo screen like this:

Image

After initial development was complete we decided it would improve usability if the photo details were pulled out from their detail screen to the top level main screen. I need to split the screen into two views: the main table view which scrolls top to bottom, and a persistent horizontal scroll area at the bottom. The main table view will scroll “under” the image scroll view at the bottom. I tried a couple ways to do this which didn’t work:

  • Place a UIScrollView on top of the UITableView so it will cover the bottom part of the screen. Not only did my scroll view not even show up in the simulator (probably hidden beneath the table), I’m certain the bottom of the table would never get a chance to scroll above the horizontal scroll view.
  • Change the height of the UITableViewController tableView in the viewDidLoad event. This did nothing for me. Not sure if the table was already drawn, so perhaps I could not affect the height.
  • Create a ViewController in the Storyboard, place two ContainerView objects on it which automatically create segues to two related view controllers. This did not run in my iPhone 5 Simulator because it complains these types of segues are not available in 5.1 and before. (arg)

SO, lets create my own in the code!

After reading this fantastic tutorial on Containing ViewControllers, I decided to create a Container ViewController which would have two child view controllers (not just child views). I call the containing VC “MyContainerViewController”. In my header file I have two attributes for the child VCs. One for the tableview, “ListItemViewController” and one for adding photos, “MorePhotosViewController”.


@interface MyContainerViewController : UIViewController{
//NSArray *_subViewControllers;
ListItemViewController *listItemViewController;
MorePhotosViewController *morePhotosViewController;
}

@property (nonatomic, strong) ListItemViewController *listItemViewController;
@property (nonatomic, strong) MorePhotosViewController *morePhotosViewController;

Then in viewDidLoad of my containing view controller, I instantiate and add my two ViewControllers as children. Also, I add each view of the viewControllers as subviews to the ContainingViewController. When I instantiate the tableview, I change the height to allow for the new horizontal scroll view which will set below it.



listItemViewController = [[ListItemViewController alloc] init];

//Grab the dimensions of the container view.
CGRect myframe = [self.view frame];

//Set the tableview to be 190 pixels shorter than the full view. 
//Also Leave a little room at top for the nav bar
[listItemViewController.tableView setFrame:CGRectMake(myframe.origin.x,
 myframe.origin.y-20,
 myframe.size.width,
 myframe.size.height - 190 )];

//ScrollView is created and sized within the child VC's viewDidLoad method
morePhotosViewController = [[MorePhotosViewController alloc] init];

// add as child VC
[self addChildViewController:listItemViewController];

// add it to container view
[self.view addSubview:listItemViewController.view];

// add as child VC
[self addChildViewController:morePhotosViewController];

// add it to container view
[self.view addSubview:morePhotosViewController.view];

In the viewDidLoad method of my horizontal scroll view, MorePhotosViewContoller, I create a scrollview, size it and add it as a subview



CGRect myframe = [self.view frame];
    UIScrollView *imageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(myframe.origin.x,
                                                                                   myframe.size.height - 190,
                                                                                   myframe.size.width,
                                                                                   190 )];

    imageScrollView.contentSize = CGSizeMake(myframe.size.width*2, 190);
    imageScrollView.showsHorizontalScrollIndicator = YES;
    //  imageScrollView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:imageScrollView];

I also add a bunch of image placeholders for the user to click on to “add a photo”.

The last step is to replace my original tableview in the navigation hierarchy with my containing VC. So I go to the storyboard and do just that. I make MyContainerViewController the rootViewController for my NavigationController. And here is the result!

horizontalScroll

Looks great, but there is one problem. All of the table cells that fall below the photo bar at the bottom do not respond to taps once they scroll into view! The way I solved this is to grab all the tap events for the table view through a gesture recognizer, determine which row the user tapped and trigger the selection event myself. A little hacky? Not too bad, I think.


- (void)tapped:(UIGestureRecognizer *)gestureRecognizer
{
    CGPoint point = [gestureRecognizer locationInView:self.tableView];

    CGFloat theRowHeight = [self.tableView rowHeight];

    CGRect btnCurrentFrame = CGRectMake(self.btnSave.frame.origin.x, (self.btnSave.frame.origin.y + self.tableView.contentOffset.y),self.btnSave.frame.size.width,self.btnSave.frame.size.height);

    CGFloat theRowNum = point.y / theRowHeight;
    float roundedRowNum = ceilf(theRowNum);
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(roundedRowNum-1) inSection:0];

    [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    [self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}

Becoming the Teacher

I have been given a great opportunity to help create the curriculum for an iOS programming course at Noble Desktop.  It will be a three day course focusing on using Xcode and the Interface Builder to create a couple of iOS apps, plus some programming fundamentals thrown in.

The process I am using to create the curriculum is to record a teaching session on my computer which will later get transcribed into the class workbook. I finished recording my first exercise (Hello World!) this week and gave the guys at Noble Desktop 20 minutes worth of video to review. In the video I explain the following:

  • small intro to Xcode
  • how to place a button and label on an iOS view
  • change the text of the label to “Hello World”, when the button is clicked
  • run the app in the iPhone simulator

Screen Shot 2013-01-06 at 2.23.24 PM

I really enjoyed making the video and it forced me to rethink the way I use Xcode. I am  self-taught when it comes to Objective-C and Xcode. I was a Java programmer for YEARS when I decided to pick up a book and program a kids’ game for the iPhone 3 years ago. Therefore, I did a little reading and refreshing before making my first video. I made sure I knew the exact names of all the inspectors and editors. Also, I looked into some of the most convenient ways to use Xcode. I’ve always been lazy about using IDEs– once something works for me, I don’t bother finding out if there is an even easier way. But for this recording, I forced myself to learn the trick to open the file editor and the storyboard editor in a split pane editor. Its called the “Assistant Editor” and its accessed by clicking on the little icon that looks like a tuxedo. I may never go back to the regular editor.  To that point, I think creating this curriculum will make me a better developer. Or at least a better IDE user! Not to mention what I’ll learn when I actually get to teach it to a room full of question-asking newbies. I’m pretty excited.

Front end coding for a back end girl

For some reason I’ve always steered clear of front end coding. I’ve had moments in my career where I’ve been a javascript guru, but then the standards and versions change and I’m just a know-nothing again. At the same time, I find great gratification from producing elegant GUIs. The instant gratification of changing a color, or triggering an action, can be so much fun.

I was finally persuaded to take a course on HTML5/CSS3 at Noble Desktop with a friend of mine who was attending. First off, let me tell you, this is a GREAT school. The instructor really knew her stuff. She taught the material clearly and at a nice pace and she was also able to answer any odd question you threw her way. She also had personal anecdotes about browser compatibility and nuances of working in a company that prohibits upgrading to latest browser versions. I was so happy to know she had been in the trenches and was not just an academic.

It was a two day course focusing on building a webpage using HTML5 elements such as video, and audio as well as new CSS3 modules such as transitions, multiple backgrounds, borders, shadows, etc. All this was really fun and fulfilled my “immediate gratification” quotient. But what I found most enjoyable and impressive is how much they focused on cross browser compatibility and gradual degradation. I guess this comes with the trade..to be a really good CSS coder, you have to know cross browser compatibility WELL.  And thus, that was the part of front-end coding that I was not looking forward to. However, HTML5/CSS3 and many open source libraries make it sooooo easy. Have you heard of Modernizr? It is a feature detection library for CSS3. So instead of asking the client browser what VERSION it is, the code can simply ask the client browser which FEATURES it supports. Then you can write logic to implement the ‘x’ feature if supported and provide a work-around, or perhaps even nothing, if its not supported. CSS and its community has come a long way since the last time I took a look at it. This class made me want to go build my own website soup to nuts….front end to back end. So fun not to be a know-nothing for the time being.

What do *I* believe in?

I’ve been consulting at a startup for about 4 weeks now. Lets call it client 1. (Wait, wait, maybe I should call it client zero…..to reference 0 based counters and the fact that it is the origin of my consulting practice (as in patient zero)).

I’m helping them look for a CTO/VP Engineering as well as hire more developers and advise on how to improve the current development process. Its made me feel a bit like a glorified recruiter, but so far I cost less than the percentage they’d have to pay a recruiter, so it is a justified role.

In my search for a CTO I find myself asking a question that I think could be a real teller, if the candidate opens up and answers honestly….”What do you believe in? Which software development practices do you really fight for when push comes to shove?” In other words, if the CEO came over to your desk demanding that certain features be delivered in x days and you knew it would entail sacrifice, what would you be willing to sacrifice and what would you not!

Some options to toss out the window

  • Unit Tests
  • Documentation
  • QA / Regression Testing
  • Configuration (global vars!)
  • Reusability (hard code it!)
  • Flexible code/ Design for easy iterating and change
  • Scalability (put it all in one class/method!)
  • Security (do I really have to encrypt the users’ passwords?)
  • Monitoring/Instrumentation (What? My MongoDB ran out of memory and has collapsed?)
  • Metrics (analytics of user behavior)
  • Logging

Its a tough question I think. I believe that in a startup, you have to work with the business side of things to create a quality product in a timely matter. That means sometimes compromising your ideals for a delivery date while maintaining a high level of quality. The definition of quality is subjective given the list above. Some engineers would say that you cannot sacrifice any in that list (well, except for documentation, who really wants to write or read documentation?)

When I think about what may or may not be sacrificed, I think about site stability first. And I think about my past experiences.  In my last position as CTO, I was using MongoDB for the first time. MongoDB loads your “working set” of data into memory to provide quick reads and writes. But once the size of your working set exceeds the amount of allocated memory, the performance can degrade quickly and without warning because of expensive disk I/Os. This is what happened to me. The size of the data did not increase suddenly or significantly, it simply crossed an important line in the sand one day. That line was the amount of allocated memory.  Looking back through the Mongo logs, we were able to determine that the amount of wait time per query had been increasing steadily as the amount of data increased (and the size of the indexes increased). If we had the correct instrumentation in place, we would have been alerted soon enough to increase our DB memory.

You can bet, the next time I use MongoDB in a production environment, I will have the right instrumentation and alerts in place such as this. Something to dig in my heels and fight for.

The start of lowetechgirl

I’m happy to say I’ve taken the leap from full-time work (programming or managing programmers)….to part-time freelance programming, to full on consulting. What I mean by this, “consulting”,  is I’ve jumped into a lifestyle that has no guarantee of a paycheck or a job, past today. In return I get the flexibility I need to spend time with my kids and perhaps equally important, spend time with myself on my own terms.

I left a full-time job one month ago and found my first paying gig 2 weeks ago. I’d say it took me 4 weeks of emailing, calling, lunching and meeting to secure this job. I don’t think that was a particularly long time to look for work, and I am happy with my ability to drum up this business. But it was a bit nerve wrecking, not knowing when something would come through, and I learned a little bit through the process.

  • Your rate is a non-starter. If you have a minimum $/hour you need to secure, inform your potential client of this as early as possible. There is no reason to meet in person if they are unwilling or unable to pay your rate.
  • Timing is a bit more flexible. Even if you are booked solid right now and a potential client needs you to start ASAP, you can suggest a later start date. Let them know when you would be able to give them more hours…perhaps they are flexible.
  • Some clients may choose not to pay you, or drop out of the engagement without any warning. Be smart about who you engage with (do they have funding…do they have other employees or contractors?). But ultimately, this is a risk you have to expect.
  • Always be looking for the next contract. Consulting engagements come and go and may take a month’s lead time to secure. You need to always be looking for the next job.