Software Development is Expensive

This is a bit of a rant, so I apologize ahead of time.

Software development is a crazy blend of art, science and luck. I’ve compared it to painting in the past and I still think that’s one of the better comparisons out there. It is difficult to build a software application that solves a problem, addresses technical challenges, and is intuitive and simple to use.

It shouldn’t be a surprise that software development is expensive. And the higher the skill level of the developer, the more well-known the developer, or the more specialized the skill set, the more expensive it will be. Art follows a similar cost pattern. A Picasso is going to cost more than something by a local art student. Fair or not, that’s the world we live in.

Booked is free and open source and will continue to be. I choose to release it free of charge because I enjoy giving back to a community that has given me so much. I also do a fair amount of custom software development for Booked. This development is not free, but I make every attempt to charge a reasonable fee for my expertise and time.

In some ways open source has spoiled us. It can give the perception that software development is easy and cheap. Most software developers – open source or not – are highly skilled experts in their field.

If you have a custom table built by and expert carpenter it will cost more than the particle board table that you pull off the shelf at the local Ikea. If you reach out a developer for custom software development be prepared for it to be costly. After all, you’re getting a solution expertly crafted to solve your problem. I know I’ll pay a premium for that.

Are You Mentoring or Lecturing?

Great team leaders raise the skill level of people around them. There are so many ways to do this – team presentations, sharing articles, demonstrations, etc. Mentoring is one of the most personal and powerful ways of developing individuals on your teams. Unfortunately, this term gets tossed around freely without really understanding it.

To the Wikipedia!

Here’s what Wikipedia says:

Mentoring is a process for the informal transmission of knowledge, social capital, and the psychosocial support perceived by the recipient as relevant to work, career, or professional development; mentoring entails informal communication, usually face-to-face and during a sustained period of time, between a person who is perceived to have greater relevant knowledge, wisdom, or experience (the mentor) and a person who is perceived to have less (the protégé)”

Knowledge. Social Capital. Psychosocial Support. Mentoring is not just teaching. It’s not lecturing or demonstrating.

Let’s just be frank

You are not mentoring if you’re: criticizing, doing, judging, scolding, arguing. The goal is not to claim your throne as supreme master of knowledge and make others feel bad. The goal is not to make others do things “your way.”

As a mentor you should be asking questions and guiding others to answers. You’re building skills as well as the inherent desire to apply those skills. You should want this person to become a mentor themselves – to grow others on your team.

Ask yourself this

Are the individuals that you are mentoring only doing what you want because they are scared of you or want to avoid confrontation? If you left today, would the process or behavior cease? If you answered yes to either of these then you’re not mentoring.

Empower others

People want to be great. If you’re in a leadership position – and let’s be honest, we’re all leaders – make the time and emotional investments to help others be great. I guarantee you’ll also grow as part of the experience.

There’s a place for mentoring and there’s a place for lecturing or instructing. Be aware of which role you’re playing.

Does your manager know how to code?

Who cares? Can you manage people?

I used to think that a good manager could come from any background. Hell, I’ve had some incredible managers that have never written a single line of code.

But as a full time manager of software developers I’m starting to think that a background in development does matter. I can honestly empathize with the highs and lows of being a software developer.

I understand my team’s frustration when they hit roadblocks. I share in their excitement when the business loves a new feature that they just spent a ton of time on. I feel the energy when they’re absolutely killing it during a sprint. I’ve been there. I’ve written a lot of software and have experienced the full range of emotions that come along with it.

Wait. Emotion and software development in the same sentence? Are we taking crazy pills? Software development is just a form of engineering, right? Feelings don’t produce a more accurate design or get us to production faster, you know? Obviously, I disagree, but that’s a topic for another post. Let’s just leave it at ‘software developers are humans, too’.

Why does it matter?

Not all developers are cut out to be managers. You know who I’m talking about. We’ve all had that team member who is too brilliant for their own good. The one who can solve problems before you even realize they exist. But they’d rather talk tech than talk about about you as a person. You may get some interesting insights into a new framework from these folks, but you’re not getting a deeper discussion on your career objectives. Teams need to be mentored – they don’t need to be lectured.

It’s incredibly unfortunate that some organizations only provide career advancement through the managerial path. There are a ton of talented people out there who may not fit a ‘management’ profile but can contribute from a leadership perspective. And honestly, I want a team of leaders.

OK, so here’s the big drawback.

Programming is addictive. You get into it and it’s really hard to stop. So when my team is facing a technical challenge – or when they’re exploring some new design or technology – it’s really hard to stay out of it. My instinct is to jump in. To solve problems. But that’s not the role of a manager.

Good managers help teams solve problems. They build their teams skill set. Managers don’t grow great teams by solving problems. They build the problem solving skills within the team. “Teach a man to fish”, right?

The jury’s out.

This isn’t to say that the folks who don’t have a background in software development are bad development managers. These people bring an entirely different – and generally very positive – dynamic to the team.

I know that I still have a lot to learn, but if I was back into full time development and you asked me, I’d tell you that I want a manager that has been ‘in the trenches’. I’d want someone who loves technology. I’d want someone who gets technology. Someone who knows the challenges, the highs, and the lows. Someone who knows that even the seemingly simplest problem may turn out to be an event that turns your hair gray. And by that line of reasoning, I’m becoming more qualified by the day :)

Update: November 13, 2014

JD Meier has a great post about building digital skills. He talks about how “hybrid leaders” – those who are skilled in technical and leadership aspects – are the leaders of tomorrow.

Give me a topic for a post!

I have a wide variety of topics that I would love to write about, but I want to hear what you’re looking for.

Do you want articles about using or administering Booked? Do you want to hear about my journey launching Twinkle Toes Software? How about being part of an agile team, or the broader agile software development process? General software development or architecture more your speed?

Leave a comment and let me know what you’d like to see more of on this blog!

Checking out Entreprogrammers

When I decided to start my own company last year I wasn’t really sure what to expect. Turns out, it’s a lot of work. :) Aside from being a developer, I also need to play the role of marketer, accountant, salesman, recruiter and so on. It’s pulled me out of my comfort zone. Way out in some cases, and I don’t always have a clear path forward.

I recently stumbled on the Entreprogrammers podcast. Unlike a lot of other podcasts out there, this one isn’t chock full of tips or advice. It’s not “how to be an entrepreneur”. It’s just three developers, who I happen to respect, having a discussion about their respective entrepreneurship journeys. And while there aren’t any predetermined topics or specific areas of advice, I have found a lot of the content to be useful. I’ve picked up a lot just by listening to what these guys are doing.

They talk about their ups and downs, marketing strategies, approaches to product development and other topics that are relevant to a developer who is also trying to sell a product or service. It’s also relieving to hear that other people, in this case people who are much more well-known and much smarter than me, face similar successes and struggles.

If you’re a developer who is trying to build a product, sell a service, or build a brand, this is definitely worth checking out.

Software Development is Like…

Software development is complex and difficult and unlike most other professions that I know of. This makes it tough to explain to colleagues in other parts of the organization, clients, and (all too often) management. We’ll typically try to find something well understood to use as a basis for comparison. Something to help explain the idiosyncrasies that come along with building software and being a software developer.

Software development is just like manufacturing, right?

I’ve heard dozens of comparisons of software development to other professions or activities. My least favorite – although seemingly most popular – is manufacturing. Sure. In both cases we’re building something based on specifications. That’s pretty much where the similarities begin and end. Manufacturing succeeds when you repetitively build the same thing with as little variation as possible. As a software team, if we build the same thing repeatedly then we’re doing something wrong. Software development is about solving a unique problem.

A different metaphor

Metaphors, by definition, are not perfect. Even so, I’d like to try a different one on for size. Lately I’ve been thinking that software development is not unlike drawing. Hang with me for a second… I’ll explain. Now, I’m not a drawer or a painter or a police sketch artist. But imagine having to draw or paint a scene from the real world. But in this case you have to recreate the scene from someone’s description. This is pretty much what we do every day in software. We bring people’s ideas to life, only we’re doing it on a computer screen rather than a canvas.

Keep playing along – this gets fun

Let’s extend this metaphor a bit to other challenges that we face in the software development world. How many times in your career has a requirement been misunderstood or missed altogether? Gee, I bet that would happen if I were trying to draw your words. Little details, even big details, can easily get lost in translation. “Yes, I said there was a bridge there, but it was iron – not brick.”

Or how about the situation where the user doesn’t exactly know what they want? “Can you paint a yellow-ish, blue-ish but definitely not green-ish house? Oh, now that I see it maybe green is right.” But sometimes your artistic influence leads them in another direction. “I had pictured this as a midday scene, but I love the way you have amber the sunset reflecting off the water. Let’s go with that.”

And now for one of my all time favorite lines of though. This being that we can add more people to the team and deliver software faster. Any software developer knows this is true to a point. But once that point is crossed, adding people will actually slow the team down. Also, the smaller the project and the closer to being “done” the harder it is to have more hands on the code. I’d image this is true when painting, as well. It may very well be possible to have three artists working on the same painting at the same time. The larger the painting, the more individual components, the more ways to split up the work. Can you imagine thirty artists working on the same piece at the same time? I expect this wouldn’t work so well.

But software, like drawing, is soft!

Across the industry there are folks who seem to forget that software is supposed to be “soft”. We’re not welding a steel frame together. We’re typing words into an editor and almost magically creating something that the user can interact with on the screen. Changing direction, even late in a project, is supposed to be easy. When we make it difficult all we’re doing is reinforcing that notion that software development is similar to manufacturing. Do yourself a favor and be nimble in your process and your architecture. There’s no need to redraw the whole city just to change the brick bridge to an iron bridge.

Love Your Code

Me and Code, we had something special. Like all new relationships, this one started out with the best of intentions. Although, I suppose we both knew it couldn’t last forever.

Looking back I realize that I didn’t support Code the way I should have. The kind of support that could only be fulfilled by unit tests. I got so busy and felt like there just wasn’t enough time. It didn’t take long for things got messy, as things with source code tend to do. Code would be telling me one thing, but doing another. Randomly, Code would throw a NullReferenceException and I’d have no idea why. The API was fragmented, making it difficult to communicate.

I had a feeling this it was my fault. Red, Green, Refactor – I knew the rules but by the end I only saw red. I wanted to help change Code but I couldn’t. A change here caused a problem there. Each fix just made Code angrier with me. Eventually we broke up and I started over. What else could we do?

Now I give my source code all the tests that it can handle. This relationship I’m in now was test-driven, so it’s exactly what we both need. There’s an occasional spat, but the core is strong and it’s easy to get things back on track. It’s been three years since I started up with Code 2 was and things are still going strong.

Happy Valentine’s Day, everyone! Be sure to give your code some love.

We’re Officially Booked!

A New Name


It’s been many months since the last phpScheduleIt release and a lot has happened since then. The biggest change is that I decided to rename the project to Booked. I’ve never been completely happy with the previous name and received a lot of feedback about it. I landed on Booked because it succinctly gives you and idea of what the product is and it’s easy to remember.

A New Company


The next big change is the formation of Twinkle Toes Software. Words typed here on this blog cannot express how excited I am to finally make this announcement. I’m an entrepreneur at heart and have wanted to start my own business for a while. Booked gives me an incredible opportunity to bring that dream to life. We’ll be offering professional services such as support, custom development, and hosting. We’re here to stand behind Booked and help it grow. I also have to thank my good friend Mandy for helping me with the website design and logo.

There is plenty more to come including the launch of booked website, the announcement of our hosting partner and some great new features and enhancements to the Booked community.

New Features

Oh, and I forgot to mention that there are a ton of great new features with this release! Here’s what you’re going to get with Booked 2.5. You can download it here

  • Application renamed from phpScheduleIt to Booked Scheduler (why?)
  • Added ability to reserve resource groups
  • Added ability to filter schedule resources
  • Added ability to specify resource type
  • Added enhanced resource status management
  • Added ability to specify buffer time between reservations (per resource)
  • Custom attributes now appear on all reservation emails and balloons
  • Added ability set custom attributes for an individual resource, user or resource type
  • Added ability manage config files for all plugins through the UI
  • Added ability to set reservation colors per user
  • Added ability to subscribe to reservation Atom feeds
  • Added ability update blackouts
  • Added ability attach multiple items to a reservation
  • Added Shibboleth authentication plugin (thank you to the folks at UCSF)
  • Added ability to email admin for all new account creations
  • Updates and cleanup on the API
  • Removed password regex setting in favor of password complexity settings
  • Changed schedule drop downs to exclude schedules if the user does not have permission to any of the resources belonging to it
  • Added wide and condensed booking page views
  • Added option to allow all users access to reports
  • Added setting for default ‘from’ email address
  • Changed the reservation page to default to the minimum resource reservation time
  • Changed reservation update to grant permissions to all users if auto-assign permissions is being turned on
  • Fixed showing ‘Private’ when the current user is the reservation owner
  • Fixed bug where recurring reservations across daylight savings time boundaries were not being updated to the correct time
  • Fixed bug where schedule would freeze on certain daylight savings boundaries
  • Fixed pagination bug on manage reservations page
  • Fixed bug allowing invitees to join a reservation that was already at capacity
  • Fixed bug not enforcing resource cross day reservation constraint
  • Fixed bug where quota rules were being enforced cumulatively for resources on a schedule
  • Fixed bug where reminders were being sent for deleted reservations
  • Updated all mysql_* calls to mysqli_*
  • Numerous other minor fixes and updates

Avoiding the Temptation of Record and Playback Acceptance Tests

I’m sold hook, line and sinker on the value of automated testing. Unit tests, integration tests, acceptance tests – I love em all. I joined a new company a few months back (more on that in a later post) and I’ve had the opportunity to get back into some acceptance testing using Selenium/WebDriver.

The allure of record and playback

Selenium makes it trivial to create web tests using the open source IDE. Hit record, click around, then play it back to verify that your web application works as expected. It’s so easy, in fact, that you barely have to think about what you’re actually testing. To be fair, if you’re doing this then you’re doing more automated testing than a lot of teams have. And it may be enough for simple smoke tests. There are a number of reasons why I avoid this, though.

The problems with record and playback

Ok, I admit that it’s incredibly fast to get a test up and running with record and playback. Unfortunately, writing tests is only half the battle. Your tests evolve along with your codebase. Take a look at the selectors that the IDE uses to locate elements to click and interact with. If you were to come back to this test in a month would you understand it’s intent? If you add a new element – or worse a whole new feature – to your application can you easily find a seam in your tests to inject the new verification? It is unexpectedly difficult to maintain tests that were set up through a UI recorder.

An alternative approach

I don’t always test through the UI, but when I do, I prefer Selenium WebDriver. WebDriver is an open source API for writing browser based tests. In my current role I’m using the Python driver (along with some some awesome other tools that I’ll get into soon), but there is support for a handful of other languages. Using the driver API, we can write tests with all of the power of your programming language of choice. We can perform intelligent element extractions and assertions. Tests become readable and maintainable.

We now have to think about what we’re testing, which is just as valuable as all of the technical benefits. If we have well written stories and specifications we can turn those specifications into acceptance test scenarios.

Imagine a story in the e-commerce space where the customer receives an automatic discount if they put at least $200 of products into their cart. This would be nearly impossible to understand as a record and playback test. But we can easily make this scenario crystal clear when writing the tests. Not only that, but we can clearly illustrate the edge case expectations, such as when the cart contains exactly $200 of products. Heck, we can use a variable and have a single place to make a change when the product owner decides that they want to bump the amount to $250.

Well layered tests will set you free

Using the WebDriver API is a huge leap forward over record and playback. But if we just have a long list of element selections, invocations and assertions, we’re not that much better off than we were. Your tests should be treated with the same respect as your production code. That means putting proper abstractions in place, naming things clearly, staying DRY and SOLID.

One of the most useful abstractions when testing your web application is the Page Object. The idea is to keep a clean separation of tests and HTML/page structure. This ends up making tests even more readable and maintainable by providing an API for your pages. No more hunting through test files when you make changes to your page’s DOM – everything is in a single place.

A well stocked tool belt

You can using WebDriver from your normal unit testing framework and it will work brilliantly. But there are many incredible supporting tools for acceptance testing and behavior driven development for all major languages. In Python, I’m using Behave and loving it – .NET teams can use SpecFlow or StoryQ, in Java there’s JBehave.

Behave uses the Gherkin natural language format. This allows us to describe the desired behavior of the application in a format that is easy to read and write by both business and technical folks. We then provide implementations for each of the steps in each scenario, using the API provided by our page objects to drive the tests and get values used in our assertions. Running the tests produces output that reads just like our stories which we can use to show our stakeholders exactly how the application behaves.

Try doing that with record and playback!

Extending phpScheduleIt : Getting started with the API

One of the big features we introduced in 2.4 was a RESTful API for integrating with phpScheduleIt. This is disabled by default but can be flipped on just by changing the config setting $conf['settings']['api']['enabled'] to 'true'. Once you do that, navigate to the auto-generated documentation page at http://your_phpscheduleit_root/Web/Services/index.php (if you’ve got mod_rewrite set up with Apache, you won’t need ‘index.php’) and take a look at everything that’s available.

Each service description contains some important information. You’ll see if the method is invoked via GET, POST or DELETE. You’ll also see:

Name  – This is the name of the service endpoint and the URL segment to use.
Description – A brief description of what the service does and any optional parameters.
Route – The full route and variables needed to invoke this endpoint. Any portion that begins with a : denotes a variable that must be provided. Pay attention to any trailing slashes – those are required when specified.
Response – An example JSON response (if applicable).
Request – An example JSON request (if applicable).

You’ll notice that all requests/responses are in JSON. In this post we’ll use jQuery to authenticate, list our reservations, and update a reservation. It’s important to remember that you cannot POST JSON data cross domain with JavaScript. So if you want to use this method you’ll need to run it from the same domain as your phpScheduleIt instance.


Just like the web front end, most of the services that the API exposes require an authenticated session. The documentation will note whether or not a service is secure or not. So step one will be to get a session token to use for subsequent calls.

Here’s our authentication fragment. It’s pretty simple, really. We POST the username and password to the Authentication/Authenticate service, then store the sessionToken and userId that we get back. We’ll just pop up and alert if the authenticate call fails.

	type: "POST",
	url: self.baseUrl + "Authentication/Authenticate",
	data: JSON.stringify({username: self.username(), password: self.password()}),
	dataType: "json"
.done(function (data)
	if (data.isAuthenticated)
		self.headers = {"X-phpScheduleIt-SessionToken": data.sessionToken, "X-phpScheduleIt-UserId": data.userId}

Finding Our Reservations

Now that we have a session established we have all the rights and privileges of that user. We’ll start off by getting a list of our reservations. By default, this will get all of the reservations for the authenticated user in the next two weeks. This is a simple GET request to Reservations/. The important part is that we attach the headers to this request.

	type: "GET",
	url: parent.baseUrl + "Reservations/",
	headers: parent.headers,
	dataType: "json"
.done(function (data)

	$.each(data.reservations, function (idx, val)
		self.reservations.push(new ReservationItemViewModel(val, parent));

Updating A Reservation

Alright, that was almost too easy so far – let’s get into the nitty gritty. Create and update calls require a full object to be posted. To do that, we’ll first need to load the reservation and map it into a request object. This one is a little more involved, so I’ll walk you through it.

First, we make a GET request to Reservations/:referenceNumber with the reference number of the reservation that we want to update. Next, we walk through the response object and convert it into a request object. Most of this is straightforward. You may be asking why we’re calling $.map for the array objects. This is because the request object needs a different object structure than what what we currently have. So we’re just looping through each one and converting the item into the format needed for the request.

	type: "GET",
	url: parent.baseUrl + "Reservations/" + reservationItem.referenceNumber(),
	headers: parent.headers,
	dataType: "json"
.done(function (data)
	existingReservation = data;
.then(function ()
	var request = {		
		accessories: $.map(existingReservation.accessories, function (n)
			return {accessoryId:, quantityRequested: n.quantityReserved };
		customAttributes: $.map(existingReservation.customAttributes, function (n)
			return {attributeId:, attributeValue: n.value};
		endDateTime: existingReservation.endDateTime,
		invitees: $.map(existingReservation.invitees, function (n)
			return n.userId;
		participants: $.map(existingReservation.participants, function (n)
			return n.userId;
		recurrenceRule: existingReservation.recurrenceRule,
		resourceId: existingReservation.resourceId,
		resources: $.map(existingReservation.resources, function (n)

		startDateTime: existingReservation.startDateTime,
		title: existingReservation.title,
		userId: existingReservation.userId,
		startReminder: existingReservation.startReminder,
		endReminder: existingReservation.endReminder
	self.UpdateReservation(request, reservationItem);

We then make any changes we want (in this case, just updating the description) and issue the update. If we get an error during the update call we’ll display it. The error messages will be the same ones we get when we have a problem saving a reservation from the web. Expect to see messages like missing required fields, invalid dates, or conflicting reservations.

request.description = reservationItem.description();
	type: "POST",
	url: parent.baseUrl + "Reservations/" + reservationItem.referenceNumber(),
	headers: parent.headers,
	dataType: "json",
	data: JSON.stringify(request)
.done(function (data)
	console.log("Update response message: " + data.message);


}).fail(function (data)

Putting It Together

Here’s the full example. Full Example Code – You’ll need to View Source and save this file locally.