Skip to content

A Useful, Tested Git Work Flow

knot photo
Photo by fdecomite

I’m working on a project with a number of developers (about 9 checking in code) that is moving rather fast and we’re using git and github. It’s actually really interesting to me, because most of my experience has been with smaller teams (and centralized VCS) where having everything on HEAD is perfectly fine. I was even able to branch using CVS because the chance of merge conflicts with no one else doing development was small.

I remember having lunch with a friend who worked at Rally and we talked about git. He said that they were heavy users, and “once you use it, dude, you’ll never go back”. At the time I thought–how great can git be? I’d been using it for a small project I was coding by myself, and it seemed nice enough, but not revolutionary.

But, now that I’m using it in a fast moving team with a large number of developers touching lots of parts of the system, the branching and merging capabilities of git are starting to shine. The project lead, who has used git before, recommended the Driessen git flow (from 2010), which is more complex than the github flow.

We’ve been using this for a few weeks and I’ve found it be clear, fairly easy to understand and still flexible enough to let development move forward at a breakneck pace. The supporting branches, along with master (always what is in production) and develop (always works, what is coming down the pike in terms of features), seem to be a nice compromise between the strictures of traditional, centralized VCS and the free-for-all that is possible with git.

Open Source, Consulting and Building SaaS Products

construction photo
Photo by JD Hancock

I was browsing Hacker News the other day, and ran across this article, lamenting how difficult it was to support a company with an open source project and that insomuch as one could, consulting generated far more revenue than selling SaaS services like hosting.  For the record, I’ve never touched LocomotiveCMS.  From a brief glance, it looks nice.

While I feel for them, I think that they have alternatives:

  • Sell premium support.  Right now, it appears the only way to get premium support is to host with them, and it seems that many clients are more interested in self hosted solutions.  Makes sense–if you are a rails developer (the target market for this CMS) you already have a hosting solution.  But if premium support was offered separately, they could hire someone (possibly part time) less skilled than Didier, the primary developer, and have them take care of tier 1 support.  And still offer a warm fuzzy feeling for harder problems, which would escalate to Didier.  Companies like to pay for that kind of service, even if they don’t always use it.  This strategy would also decrease the amount of revenue needed to hire someone to help Didier (customer server folks are less expensive than developers).
  • Sell an ebook (or a couple).  These are far easier to create and sell than a SaaS product.  (I use leanpub!)  It could be an ‘authoritative guide to LocomotiveCMS’ or just focus on one part.  Since Didier knows which questions he often answers for people who have paid him money, he’s probably got a very good idea of where the pain points are.
  • Someone suggested this in the comments, but a marketplace for plugins to LocomotiveCMS seems like a natural way to go.  Again, i don’t know that community, and marketplaces for CMSes can be hard to kick start, but this is worth evaluating.
  • I’m sure there are others.  Here’s an exhaustive list of business models, courtesy of the AVC community, so if I were them, I’d review and see what was a fit.

In my comment on the HN post, I talk about how products often face a “round peg in an elliptical hole” problem. I meant that products often solve 80% of the problem for 80% of the users.  They also require users to change their processes (more crystallization).  Typically there’s just enough offset that people feel cognitive drag.  (Of course, the same thing usually happens with custom solutions, you just don’t know that until you are done.  Doh!)

Especially in crowded markets, like CMSes, it is far far easier to sell enough hours to make a living customizing a solution than it is to sell enough products to make a living.  Brennan Dunn covers this ground well.  Every consulting company I’ve ever seen or been a part of, and every consultant I’ve ever known (except the ones who were contracting for one client and really were employees with more flexibility), dreams of transitioning from non scalable consulting by the hour to scalable product sales.  One friend even had a name for it–the “von MacIntyre machine”, which would make money while he slept.

But it’s hard.

Settle the Routine, Focus on the Important

IMG_20141016_165308295
My Bike Lock

This is a picture of my bike lock.

There are many bike locks, but this one is mine.

I always put my bike lock on as seen.  My helmet with the lock running through the styrofoam (because, on the off chance someone wants to steal a bike helmet, they’d have to destroy mine to get it).  The lock running through both the front wheel and the frame, so that the wheel can’t be stolen–nothing sadder than a locked bike with a missing front wheel–quick release works well.  The actual lock (where I put my key) sheltered from the elements, both because the helmet protects it and because it is facing down.

After commuting on my bicycle hundreds of times and leaving it overnight a handful of times, I’ve determined this is the optimal lock procedure.  Not that I’m not open to new ideas–a few years ago I took my helmet with me, but then I saw someone lock their helmet like this and thought “what a wonderful idea!”.  But once I arrived at what seemed an optimal solution, I just put it on autopilot.  This frees up my mind to pursue other things.  It also means I have not analyzed the way I lock my bike in a deep way until I started to write this blog post, and once this is done, I won’t think about it for the foreseeable future.  The bike lock setup is settled.  I’m always looking for other aspects of my life to settle, while still being open to possible improvements (if you lock your bike differently, let me know!).

There’s a similar tension in software development.  On the one hand, I want to be open to new ideas, frameworks, concepts and solutions.  On the other hand, it can be easy to go after the newest ‘shiny thing’ every time, spin my wheels, and not accomplish what I need to accomplish.  One way to the latter issue is to make some decisions in my work life.  This can range from the trivial–I have used the same aliases file for over a decade–to foundational–I only work on the unix stack.

Sometimes settling constraints are imposed by the project–it’s a RoR app that needs to be upgraded, or there are already extensive java libraries that this application will use (and that can mean that you won’t get the gig or the job).  Time also can be a limiting factor–deadlines have a wonderful way of focusing you to work on the problem at hand, rather than running off to explore that new library.  It’s also important to realize that you can settle the trivial–what shell you work in, what OS you use, how you lock your bike–which lets you focus on the important–the app you are writing, the restaurant you biked to.

(Of course, what is trivial for some projects may be foundational for others.)

When you are working on a side project, sometimes settling on a technology can be hard–it is more exciting to explore that new XYZ rather than grind away at a bug or a new feature in an app that I’ve already written.  But, in the end, extending and shipping an existing app almost always is more rewarding.

We software developers live on a knife edge–on one side is irrelevance, though it may be profitable (COBOL), on the other side is flitting from new technology to new technology (whether it is Erlang, Haskell, NodeJS or something new) but never mastering them.

Fun stuff I’ve done

amusement park photo
Photo by Loozrboy

One of the companies I’ve met with wanted a bit more context around work I’ve done, so I wrote up some of the ‘greatest hits’ of tech work I’ve done in the past couple of years. It was so much fun, I thought I’d post it here so I’ll remember it in a few years.  This is just some of the tech highlights, and doesn’t include other things I’ve learned (managing folks, softer development skills, etc).

  • Colorado CSAs.info is a directory of Colorado CSAs. This site received 28k visits in 2013, and 26k visits so far in 2014. You can view the source. The source has some quick and dirty aspects, since this is a side project.
  • Home valuation processing software output. This was a fairly simple algorithm (linear regression among geographic datasets) but involved some interesting processing because of the number of records involved (1M+) and data sources. The graph shown here was generated by code I wrote. The content is human generated, however. I worked directly with the CEO on requirements for this v1 project.
  • I wrote an ebook about an aspect of mobile app development last year:
  • I built large chunks of COhomefinder (which has not been touched in 2 years, because the business has decided to move forward with an outsourced home search solution). The last code I touched was replacing google maps with mapquest. I also built a widget for featured home listings that could be dropped into other websites. You can see both on the search results page.
  • I wrote a hybrid mobile app that displays news and info about neighborhoods in the front range. This never really got much traction, unfortunately.

It’s fun to look back.

Python Minesweeper Programming Problem

At an interview, I was asked to build a python program, using TDD, which would output the results of a minesweeper game.  Not a fully functional game, just a small program that would take an array of bomb locations and print out a map of the board with all values exposed.

So, if you have a 3×3 board, and there is a bomb in each corner, it would print out something like this:

x 2 x
2 4 2
x 2 x

Or if you have a 3×3 board and there is only a bomb in the upper left corner, it would print out something like this:

x 1 0
1 1 0
0 0 0

I did not complete the task in the allotted time, but it was a fun programming exercise and I hope illuminating to the interviewers. I actually took it home and finished it up. Here’s the full text of the program:

class Board:
        def __init__(self, size = 1, bomblocations = []):
		self._size = size
		self._bomblocations = bomblocations
    	
	def size(self):
		return self._size
    	
	def _bombLocation(self,location):
                for onebomblocation in self._bomblocations:
                	if onebomblocation == location:
				return 'x'

	def _isOnBoard(self,location):
		if location[0] =self._size:
		    	return False
		if location[1] >=self._size:
		    	return False
		return True

	def whatsAt(self,location):
		if self._bombLocation(location) == 'x':
			return 'x'
		if not self._isOnBoard(location):
			return None
		return self._numberOfBombsAdjacent(location)

	def _numberOfBombsAdjacent(self,location):
		bombcount = 0
		# change x, then y
		currx = location[0] 
		curry = location[1] 
		for xincrement in [-1,0,1]:
			xtotest = currx + xincrement
			for yincrement in [-1,0,1]:
				ytotest = curry + yincrement
				#print 'testing: '+ str(xtotest) + ', '+str(ytotest)+ ', '+str(bombcount)
				if not self._isOnBoard([xtotest,ytotest]):
					continue	
				if self._bombLocation([xtotest,ytotest]) == 'x':
					bombcount += 1
		return bombcount

	def printBoard(self):
		x = 0
		while x < self._size:
			y = 0
			while y < self._size:
				print self.whatsAt([x,y]),
				y += 1
			x += 1
			print
				
def main():
	board = Board(15,[[0,1],[1,2],[2,4],[2,5],[3,5],[5,5]])
	board.printBoard()

if __name__ == "__main__": 
	main()

And the tests:

import unittest
import app

class TestApp(unittest.TestCase):

    def setUp(self):
    	pass

    def test_board_creation(self):

        newboard = app.Board()
        self.assertIsNotNone(newboard)

    def test_default_board_size(self):
     	newboard = app.Board()
        self.assertEqual(1, newboard.size())	

    def test_constructor_board_size(self):
     	newboard = app.Board(3)
        self.assertEqual(3, newboard.size())	

    def test_board_with_bomb(self):
     	newboard = app.Board(3,[[0,0]])
        self.assertEqual('x', newboard.whatsAt([0,0]))	

    def test_board_with_n_bombs(self):
     	newboard = app.Board(4,[[0,0],[3,3]])
        self.assertEqual('x', newboard.whatsAt([0,0]))	
        self.assertEqual('x', newboard.whatsAt([3,3]))	

    def test_board_with_bomb_check_other_spaces_separated_bombs(self):
     	newboard = app.Board(4,[[0,0],[3,3]])
        self.assertEqual(1, newboard.whatsAt([0,1]))	
        self.assertEqual(1, newboard.whatsAt([1,0]))	
        self.assertEqual(1, newboard.whatsAt([1,1]))	
        self.assertEqual(0, newboard.whatsAt([1,2]))	
        self.assertEqual(0, newboard.whatsAt([2,1]))	
        self.assertEqual(1, newboard.whatsAt([3,2]))	
        self.assertEqual(1, newboard.whatsAt([2,3]))	
        self.assertEqual(1, newboard.whatsAt([2,2]))	

    def test_check_other_spaces_contiguous_bombs(self):
     	newboard = app.Board(4,[[0,1],[0,0]])
        self.assertEqual(1, newboard.whatsAt([0,2]))	
        self.assertEqual(2, newboard.whatsAt([1,0]))	
        self.assertEqual(0, newboard.whatsAt([2,1]))	

    def test_off_the_board(self):
     	newboard = app.Board(3,[[0,0],[1,2]])
        self.assertEqual(None, newboard.whatsAt([3,3]))	

This was written in python 2.7, and reminded me of the pleasure of small, from the ground up software (as opposed to gluing together libraries to achieve business objectives, which is what I do a lot of nowadays).

Using JSONP For Angular Requests

screen photo
Photo by Neil T

I was writing an angular app (source) that was accessing the Best Buy API, just to play around and get more familiar with Angular.  All of my previous apps had been to APIs that I controlled, and could thus use CORS to set headers.  Obviously, not so with the Best Buy API.

Whoops.

Luckily Angular makes accessing data via JSONP almost exactly the same as accessing data via XMLHttpRequest/CORS.  Rather than use $http.get, you use $http.jsonp. You have the same promise returned, and can handle the results in the same way. I didn’t dive into error handling (but if Angular follows jQuery’s lead, it looks like there’s none), and obviously JSONP can only be used to read information, but the guts of injecting a script, etc, are all handled for you.

 

RSS Pick: Dion Almaer

dion almaer photo
Photo by marcosfernandez

I think that the RSS reader is such a fantastic invention. It lets me monitor many bloggers and news sites, and see new content.  This lets you have an eye on lots of writers, including some that haven’t written for a long time.  I’m going to be highlighting blogs that I follow, one per month.

The first is Dion Almaer’s, who, unfortunately, has moved most of his writing to Medium.  But Dion is a great technologist.  He currently is employed at WalmartLabs Mobile.  He’s written such gems as:

Your coding voice:

When people ask me about Java and why I don’t often write applications in it, my answer is not that I think “Java sucks”. I think the JVM is amazing technology, and there are a ton of fantastic APIs. Using Java is a great answer for many situations. However, the least amount of fun that I have had programming has been when using the Java language. It isn’t just that it feels frustratingly verbose, although that is part of it.

and Browsers are Finally Catching Up (in 2009):

But, the browsers are finally changing. The new crop come with technologies that show that the browser vendors are thinking about building a platform for desktop quality applications. The Chrome comic book was full of this.

Remember the Chrome Comic Book?

Dion, thanks for sharing your knowledge, please resurrect your blog!  (Dion, I know this is an old photo–feel free to send me a new one and I’ll update this post.)