rc3.org

Strong opinions, weakly held

Tag: software development (page 11 of 16)

Interviewing programmers on philosophy

Today I took a survey on Object Oriented Concepts. Two computer science researchers are trying to determine how divorced the theory they teach is from the day to day practices of professional programmers. Here’s the introduction:

You have done some programming for fun, or you are a professional that has been on one of those $2000 a day professional development courses, or read the latest book, or subscribed to the current in-RSS feed, so you know how you’re supposed to write good code. But do you actually write code the way you’ve been told is The Way, or do you ignore the theory and follow the tried and true practices learned the hard way in the School of Hard Knocks, the way that really works?

We’re researchers. We know what we teach and we know what all the research papers/books say, but you write the code – you know what really works and what’s just so much theory. Here’s your chance to tell us what you know.

If you’re a programmer, you may want to take the survey. I’m sure the researchers would appreciate it.

I’m so enamored with it that I think I’m going to post my answers to each of the groups of questions here, just because I wanted to add more detail and also because I think they’re interesting points of discussion.

What the survey really made me think, though, is that programmer interviews should center more on questions of philosophy. Obviously after an interview you should know whether the person you interviewed can program, but it’s also helpful to know whether you’d actually want to let that person touch your code. I think philosophical questions could extract more information that pertains to both. They also measures the thinking skills of the candidate, and their ability to communicate effectively.

Here’s one of the questions from the survey: “When working on a class, is its depth in the inheritance hierarchy important to you?”

That’s something that someone who thinks about programming could really chew on. If a candidate doesn’t even know where to start on the answer, that tells you something about them immediately. Or perhaps they answer in great detail, but their answer is the opposite of yours, and you don’t find their argument in favor of their side convincing. Do you really want to sit in meetings with this person for the next few years having this same discussion over and over? Do you want them refactoring your code because your way is different than theirs?

After responding to the survey, I want to ask other people these types of questions. They drive right at what’s important in finding good team members.

How simple features become complicated

This post is for all of my non-programmer readers who have to deal with programmers on a day to day basis. It’s a description of how things that may seem simple really aren’t. Maybe I’ll write another post later about how things that seem complicated can be very simple to fix.

I’m working on a Web page that is supposed to display some events from a Google calendar. When I started, it grabbed the JSON feed from the calendar and displayed the first two events in it. Generally speaking, these are the next two upcoming events on the calendar. The feed contains a lot more events, though — some from the past and a lot from the future.

Unfortunately displaying the first two events in the feed did not meet the exact requirement, which turned out to be: display the events from the first two upcoming dates on the calendar. If there are multiple events on one of those dates, show them all. If there are not two upcoming dates, show one or two dates from the most recent past (so that two dates are always displayed).

Outwardly, this seems simple. Reorder the calendar in ascending order and pick the right slice of events to show.

The old code just grabbed the first two events in the list and printed them. The new code had to do the following:

  1. Extract the dates from the feed and convert them into JavaScript Date objects.
  2. Sort the events from oldest to most recent.
  3. Split the events into two lists — events in the future and events in the past.
  4. Iterate over the future events, picking out the events from the next two dates, and adding them to a third “events to display” list.
  5. If there are not two dates with events in the future, sort the events from the past in the future in descending order then pick out enough dates to fill out the “events to display” list.
  6. Sort the “events to display list” in ascending order.
  7. Display the final list of events.

Making that list was easy, but figuring out all of the requirements and then coming up with the best way to implement the solution took plenty of time from the point when the designer said “sort the events in ascending rather than descending order” to the time it was deployed. And all this for one little module on a page that contains lots of other information.

This is why I generally forbid the use of the word “just” when people are making feature requests. When it comes to developers, the word I forbid is “should,” but that’s another story.

Ward Cunningham on technical debt

Rick DeNatale posted a link to a video of Ward Cunningham explaining the debt metaphor. The whole video is essential watching, but I wanted to quote this little explanation of refactoring that works as well as any I’ve seen:

It was important to me that we accumulate the learnings we did about the application over time by modifying the program to look as if we had known what we were doing all along and to look as if it had been easy to do in Smalltalk.

I think that states the goal of refactoring quite elegantly. I also love that throughout he refers to the application as “the program”. That’s old school.

The Ruby book market

Joe Gregorio prompted me to take a second look at O’Reilly’s “state of the market” report for books on programming languages. Of particular interest to me is what they report on Ruby:

We reported last year that Ruby had grown nicely, had passed Perl and Python, and was knocking on the door for Visual Basic’s spot. However, Ruby had the largest decrease in unit sales in 2008.

Let’s go to the numbers, 95,731 Ruby books were sold in 2007, and 61,171 Ruby books were sold in 2008. That’s a big drop. In terms of absolute size, in 2007, the Ruby book market was about 40% of the size of the Java and C# markets. In 2008, Ruby’s market was about 28% of the size of the Java market, and 22% of the size of the C# market. (Python has almost caught up with Ruby.)

Some thoughts on possible reasons why Ruby fell off so sharply:

  • Deployment problems. The Rails deployment picture did not improve quickly enough to enable people who were dabbling with Ruby to make the transition to deploy real applications. That could be lowering interest in Ruby. I think 2009 will be the year of Ruby deployment — Phusion Passenger changes everything.
  • Lack of new bestsellers. Speaking for myself, I bought several Ruby and Rails related books in 2007, and none in 2008. There just weren’t any titles that really caught my attention.
  • Fragmentation. It seems like 2008 was the year in which there was a lot of splintering in the Rails community, and for good or ill, Ruby and Rails are still tightly coupled. People were trying new test frameworks, alternative persistence frameworks, and alternative Web frameworks. This hurts the book business.
  • Declining interest in Ruby in general. There are any number of reasons why interest in Ruby (and more specifically, Ruby on Rails) may be declining. For one thing, no platform can be the “new hotness” forever. For another, there are plenty of things not to like about Rails, the rate of change not being least among them. My feeling is that it’s nearly impossible to keep up with what’s going on in Rails unless you make a full time job of it. Fatigue sets in.

There may be other reasons as well. I would also caution people a bit against assuming too tight a correlation between book sales and the overall health of a programming language. It’s a piece of the picture but not the whole picture.

The other thing I take away from this is that it’s hard to see beyond your cocoon. From where I sit, the large growth in C# book sales is surprising. I don’t really know anybody who uses it. I’m not surprised by the Python growth, and I am shocked by the decline in the market for JavaScript books. This is one of the reasons why I’m looking to expand the portfolio of software development blogs and news sources I’m following.

Paying off technical debt

David Gammel asked the following in the comments on my previous post on technical debt:

Do you think the technical debt has to be paid off with a balloon payment? It seems to me like you can’t really pay off this kind of debt on a 30-year fixed interest model, it all comes due at some point in the future and must be paid in full, at once, in order to move beyond it.

Or can you refactor code consistently and in essence pay it off with small payments over time?

I think it very much depends on the form of debt. As a matter of habit, whenever I work on code in an application that seems difficult to understand or badly written, I take the time to try to improve it where possible. I think that constant weeding and pruning are the key to maintaining a nice code base, and nobody seems to know or mind when what would have been a one hour fix turns into a two hour fix because you went ahead and made things a little better while you were in that code anyway.

On the other side, there are cases where technical debt has to be paid off all at once. For example, one application I work on is still running on Rails 1.1.6. Rails is now at version 2.3, and there have been a multitude of changes that would make this application easier to work on. Unfortunately, migrating up to the latest version of Rails is going to take a fairly substantial chunk of time, and it all has to be invested at once.

In both of these examples, good unit tests are the key to being able to pay off the debt at all. In the first case, making “improvements” to the code while you’re working on it can be risky if you don’t have the tests you need to insure that you haven’t broken the business logic in an effort to clean things up. In the second example, having a solid suite of automated tests makes it possible to rapidly locate and repair all of the problems you run into when making a large set of changes.

I suppose then that I’d argue that inadequate tests are one of the most painful types of technical debt that a project can accrue. On the upside, it can be paid off gradually.

Technical Debt

The other day I was reading an article by Martin Fowler in which he referred to the term technical debt. He credits Ward Cunningham for coining the term, which is defined thusly:

Technical Debt is a wonderful metaphor developed by Ward Cunningham to help us think about this problem. In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice. We can choose to continue paying the interest, or we can pay down the principal by refactoring the quick and dirty design into the better design. Although it costs to pay down the principal, we gain by reduced interest payments in the future.

This is a nice, business-y way to discuss a problem every developer is familiar with. You could publish a blog just on ways projects incur technical debt and how to address those problems. In fact, I’d argue that one of the primary jobs of a team leader or manager on a technical team is to spot places where technical debt is being incurred so that it can be addressed later on.

The burden falls on the person leading development, because nobody else involved in the project is going to take care of it. The product manager (or project manager) are properly focused on budget, schedule, and specifications. The quality assurance team is focused on making sure the application produces the right output given the right input. Only the developers themselves can be responsible for reducing or avoiding technical debt while addressing the other audiences.

I think that most of the worthwhile fights that developers have with other members of the team are over issues of technical debt, it’s just that few people refer to it that way.

Expect more posts on technical debt in the future.

Programmers should study a little economics

So the big news on Twitter among Ruby programmers is that the “hashrocket” operator has been deprecated. For those of you who aren’t Ruby programmers, here’s what that means. If you want to declare a hash literal in Ruby, right now you can do it like this:

my_hash = { :foo => "1", :bar => "2" }

Also, many methods accept hash literals as an argument, so you can do things like this:

url_for :controller => 'posts', :action => 'index'

At some point, that notation will be unsupported, and hash literals will have to declared in a different way.

When the version of Ruby is released that doesn’t support this notation, it will be incompatible with a massive amount of Ruby code. My advice to the Ruby developers would be not to do it. I don’t know what the rationale is for removing it, but the result is going to be lots and lots of servers that are simply never upgraded to that version of Ruby.

They should take a lesson from the PHP people. The migration from PHP 4 to PHP 5 has taken forever as a result of much smaller incompatibilities than this one.

Economics tells us that we have to be careful about the incentives that result from our actions. Removing the hashrocket operator creates a strong incentive to leave the Ruby upgrade path.

Update: Sometimes rumors on Twitter are just rumors on Twitter. I don’t see any mention of deprecating the => operator in the Ruby Subversion repository.

Bugs and hacks

I always wonder what goes on behind the scenes on the World of Warcraft team at Blizzard. Aside from being impressed by the scope and quality of the game, I wonder how difficult it must be to build this (very) fat client that has to be kept in sync on the OS X and Windows platforms, integrate new content, and keep all of the game’s internal systems in balance so that users enjoy themselves. Then there’s the challenge of maintaining the infrastructure needed to support over 10 million active accounts.

So I relish any little glimpse behind the curtain we can get. This weekend, players found a really interesting bug in the game. Death Knights, a new class in the game, have an ability called “Death Grip”. It allows the player to pull an enemy toward them through the air. (Here’s a short video.) So here’s the bug: if a Death Knight uses Death Grip while standing on a particular ship, the target is pulled through the world (the flight lasts about 8 minutes, apparently) to a hidden ship in the middle of empty space far away. There are several videos of this in the blog post I linked to above.

As long as MMOs have been around, there have been ships to take users from one place to another. You go to a dock, wait for a ship, climb aboard, and wind up somewhere that would otherwise take you forever to get to by running (or swimming). Here’s the thing — ships have been buggy in every game they’ve been implemented in. For some reason, the folks at Blizzard had to create this hidden ship somewhere to get around some bug they obviously couldn’t fix in any other way, and now this Death Grip bug has in some way exposed the inner workings of the game.

I doubt there’s any advantage to players in finding it nor will there be any way to get to it once this bug is fixed, but I would still love to hear the inside story of how that ship got there in the first place. It reminds me of some ships I’ve built in the past to get around what at first looked like relatively straightforward problems.

A database design question

I’m looking for people to give me some ammunition to win an argument with myself. I have a database table that stores denormalized data for presentation in reports. One of the columns will hold some messages that are taken from three different tables.

The three tables are parents, children, and child_messages, which contains custom messages associated with the keys stored in children. To include the children in a report that lists a number of parents, you have to do all sorts of stupid tricks. Denormalization is easier, especially because on this report there are a number of similar scenarios that all involve different tables, making things even more complex than I’ve already described. (I’m planning a blog post to describe this denormalization approach for later.)

The question is how to store the denormalized data. On the Web page, it’s presented in an unordered list. The data can also be downloaded in CSV format.

Some options include:

  • Storing the messages in an unordered list. The nice thing here is that in the default case you don’t have to do anything to transform the data once it’s fetched. Just print it. If you do have to parse it, HTML is not the most difficult thing to parse.
  • Storing the messages in YAML. It’s lightweight and there are already plenty of libraries to parse it. The downside is that the reports would always have to parse and transform it. Also, we’re not talking about an arbitrary data structure but rather a list of messages. So the flexibility of YAML doesn’t provide any value.
  • Storing the messages in line-feed delimited format. Lighter and simpler than including HTML in the field, but again, must be transformed in all cases.

I also considered some other HTML options, but ultimately decided against all of them because there’s no point in using HTML if it’s not going to be the HTML that’s actually displayed on the page.

Opinions?

Links from February 3rd

A few links from the past few days.

Older posts Newer posts

© 2025 rc3.org

Theme by Anders NorenUp ↑