General development

Interfaces - necessary, but not sufficient

Using an interface seems like one of those rules.  Everybody knows they should do it, because it makes your code more abstracted and… stuff.

However, if you have a gigantic class with a ton of methods, or methods that are very specific to its implementation, then simply providing an interface that mirrors the public methods of the class is of little value.  To successfully swap one implementation for another, you would need to understand the behavior of the first implementation so well that you could accurately mimic it - and, frankly, that’s not very likely unless you’re the one to write the first implementation anyway (and probably not too likely even then).  While you’ve avoided implementation coupling, you’ve got a kind of conceptual coupling in its place.  This is doubly true if the interface specifies that it returns objects that implement another interface (likely as thick as the first).

So, using interfaces as kind of headers doesn’t really help us too much in this case.  We’re still realistically tied to an implementation, and now we have interface versioning issues to deal with (which, for C# at least, are worse than class versioning issues, as adding a member to a class does not break backwards compatability - but it does for an interface).

That doesn’t mean that I’m against interfaces.  In fact, I love interfaces.  I just think that there’s better ways to use them than as sim-headers.

Interfaces should be used to define questions that, as the class you’re writing, you want to ask of your dependencies.  This is a bit of an inversion - typically, interfaces are defined from the POV of the class implementing them, not the class using them.  But, by controlling the interfaces you use, there’s less chance of them breaking and causing major headaches throughout your codebase.

Interfaces should also be as small as possible, and represent a single aspect of what you can do with an object.  IEnumerable<> is a great example - it only lists things that you need to do to enumerate a collection.  And because of that, it can be very stable.  The more things an interface does, the more likely it is to need to change, and the more code that will be broken when it does.

So, if you’re using interfaces in this way, how do you implement them?  Especially if the class you’re dealing with didn’t own the interface to begin with?  This isn’t too hard - write a small adapter class that implements the interface, and calls the underlying object in the appropriate way.  This has the added advantage of keeping all your dependent code in one spot, making it much, much easier to fix if the dependency ever changes underneath you (assuming that you don’t control it).

General development

Comments (0)

Permalink

Anti-pattern: Silk-pursing

“You can’t turn a pig’s ear into a silk purse.”

“It’s not a global, it’s a singleton!”

Description:

An “acceptable” design pattern is placed on top of a concept that is generally avoided

Symptoms:

  • Problems associated with a known poor development practice start cropping up. 
  • Problem areas are defended by spouting off the name of the design pattern that they superficially resemble.
  • Patterns are used when the problem that the pattern solves is not demonstrated, but for tangental reasons.

Examples:

The most common form of silk-pursing is singletonitis.  Too often, globals are wrapped up in singletons, because that somehow makes them “okay.”  Inappropriate use of Service Providers seems to be the next version of singletonitis, in that it is often used to propagate globals rather than the actual purposes (extensibility, etc.)

Usage of try/catch/finally to simulate goto is another example.

Silk-pursing is related to cargo-cult-programming.  In both cases, a useful pattern is used inappropriately.  In cargo-cult-programming usually involves adding patterns/structures/algorithms/etc. for no apparent reason whatsoever.  Silk-pursing is different in that the pattern being abused is applied solely for the purpose of hiding a practice that is frowned upon.

Silk-pursing may seem like gold-plating, but it is different.  Gold-plating involves putting extra, unnecessary features into code.  Silk-pursing simply hides poor development practices.

Silk-pursing may or may not be a deliberate attempt to conceal.  In many cases, developers will actively believe that because they are using something they’ve heard is a beneficial practice, that what they are doing is actually better.

Fixing:

Treat the code as if it were the underlying development practice - treat silk-purse singletons as globals, etc.

Educate developers on the purpose of the design patterns that are being abused.

Educate developers on the fact that concealing a bad practice doesn’t make it any better.

Educate developers on ways to design code that doesn’t involve using the poor practice.

General development

Comments (0)

Permalink

Types of Dependencies

Dependencies and coupling seem to cause the greatest pain in software development.  I think it’s useful to look at the types of dependencies that can exist.

Contained Dependencies

A contained dependency is a dependency that a class has, but which is not communicated externally.  The class uses the contained object, and so is dependent upon it, but does not propagate the dependency.  This is the most benign dependency, as if the dependency breaks, the class may break, but it can not (directly) break other objects.

Direct Dependency

A direct dependency is a dependency which is exposed directly by the class, either in a return value, a parameter, or a base class.  Direct dependencies are worse than contained dependencies, as they can directly break classes that use the class under discussion, both in terms of compilation and functionality.

Indirect Dependency

An indirect dependency is a dependency exposed by another dependency.  This is worse than direct dependencies, as this is how dependencies propagate, causing the system to become brittle.

Hidden Dependency

A hidden dependency is arguably the worst kind of dependency.  A hidden dependency is a contained dependency that can cause side effects, causing other components to fail.  Globals are, generally, hidden dependencies.

General development

Comments (0)

Permalink

Thoughts on Pair Programming

Ahhh, probably the most controversial subject in development.  I don’t know of any single issue that is more likely to get people riled up, either for or against it.

My experience is pretty simple.  I’ve never done pair programming “full-time.”  But, like most programmers, I’ve done it at times - working with another programmer over a problem.

When I’ve done that, I’ve generally found that a few things happened:

  • My knowledge increased
  • Hopefully, the knowledge of the other guy increased
  • We both understood the system better
  • We generally produced better quality code than I was used to seeing from either of us, individually
  • We remained more highly focused

There’s been a number of studies done on pair programming.  Most of them use similar methodologies, and reach similar conclusions.  I’ll dig up references later.

In general, they take developers or students, and divide them into two groups.  One of the groups will pair up and work on a project, while the other group will approach the project individually.

In general, these projects are rather small.  In one experiment, they were class assignments, over a period of time.

The results generally found were that the pair took less clock-time, but more man-hours to complete the task.  Generally, the results from pairs were of higher quality.

One particular study continued the experiment over time, and found that the tax on man-hours dropped from 40% at the beginning, to only about 15% at the end of the experiment.

Now, that’s pretty impressive by itself.  If a project would normally take 40 hours for a single developer, and with two, you can get it done in 22 hours and with higher quality, I think that’s a win.

But, I think that the experiments described are testing the wrong things.

I see the real benefit of pair programming not in coming from initial productivity, but from the ability to sustain productivity over time, and to allow higher levels of scaling.

One effect noted was that for pairs to become highly effective, it took some amount of time for both the developers to get used to pair programming, as well as to get used to each other.  When doing an experiment on a small or micro basis (projects taking <1 day to complete), the initial cost of this can easily outweight any benefits.

Secondly, one advantage that I see is increased knowledge of systems.  By pairing, especially if pairs are not static, developers will work on multiple areas of the project, and will gain understanding of the “big picture” of what they’re doing, rather than their isolated area.  This should increase overall quality, as well as remove the “hit-by-a-bus” category of risks.  When working on small projects that can be completed in under a week of work, this is mostly irrelevant.

Third, by pairing developers, you will remove some level of the communication tax.  Given four developers, if they work individually, they must all coordinate.  If they are paired off, you now only have two groups that need to coordinate, instead of 4 individuals.  Because the “individual” developers worked as exactly that, they had zero communication tax.  Comparing paired developers to two developers collaborating as individuals would be an interesting metric.

Fourth, maintenance is very important.  While “passing tests” is an important measure of quality, the ability to maintain and expand code is also extremely important, if hard to measure.  If pairing increases quality, then this additional quality should (in theory) allow code to be more easily changed in the future - especially when a larger number of developers have insight into it.  Again, on small projects, this benefit is unimportant.

None of these benefits can be measured on toy or small projects.

So, how would I design a pair programming test, in an ideal world?

I think you’d only need to change a few things.

First, projects need to be somewhat longer - at least 40 hours to completion.  And that is minimum.

Secondly, to be fair, the test needs to compare equal-sized groups of developers to each other, working individually or in pairs.  In my experience, I’m not sure that adding a single additional developer actually increases productivity, but this is a more realistic comparison.

And last, ideally you’d want to scale out even further - four developers or more, working in pairs, against a team of the same size working as individuals.  Generally, in a realistic environment, the question is not “should we hire twice as many developers and have them pair?”  The typical question is “we have this many developers - should they work alone, or in pairs?”

I honestly don’t know how these results would turn out.  But, I suspect that they’d turn out very well for pair programming, especially if combined with other practices (such as TDD).

General development

Comments (0)

Permalink

Development, the fall line, and process

In skiing, there’s a concept called the “fall line.”  The fall line just means down.  But it doesn’t mean “towards the bottom of the hill,” it just means what is immediately down from the exact location you’re at - if you dropped a ball, or poured some water, which way would it go?

This is important in skiing, because you have to stand perpendicular to the fall line if you don’t want to keep moving.

There’s also a fall line in development.  The fall line in development is simply what is the easiest thing to do at the time to solve the immediate problem.  This can also vary by individual knowledge level.

In C, if you want to add some function, the fall line is just to declare it before you need it, and go on your merry way.  If you need it multiple places in the same file, put a declaration at the top of the file.  Only if you actually need it in another file is there any reason to expose it via header.

C++ is kind of opposite in this aspect - if you want something to be a class member, it has to be included in the header.  So a lot of little internal methods that, in C, may have been completely hidden from the world become exposed, at least to the extent that they’re in your header.  Yes, you can do things like separate implementation classes, but that’s, again, adding more work.

Because of this, I firmly believe that in any kind of API development, you want the easy thing to be the safe thing to do.  If something takes more effort to do, people will avoid it unless they absolutely need to do it.

Sometimes, the easy thing to do in a language, or application, isn’t the right thing to do.  Sometimes it’s the wrong thing to do.  And the typical answer to that is to add process, and force people to do the right thing.

I’m going to suggest that all process can do is add inefficiency, and by doing so, change the fall line of development.

That’s not necessarily a bad thing - if the fall line leads you to write bad code, then adding inefficiencies to gain later benefits can be very useful!

But, there’s two things to keep in mind:

First, if people don’t understand the purpose of the process, they’ll just follow the steps of the process while continuing, essentially, the same underlying behaviors.  Imposing a process alone will generally not change the mindset of anybody.  If you’re really looking to get a change in behavior, you’ll have to do that through education.

Secondly, the reason that process works is because it adds inefficiencies, and people will avoid inefficiencies.  The more heavyweight a process is, the less it will be used.  If your checkin process takes a day to navigate, then people will avoid checkins, and do them in large batches.  And that might partially defeat the purpose of your checkin process in the first place.

You should always use the minimum process that you can, and use process deliberately to add inefficiencies.  The goal of a process should never be to get people to do what they should do, but rather to get people to not do things that they shouldn’t.

I’m a big TDD proponent.  I would never suggest that somebody institute a TDD process that was mandatory.  If you don’t “get” TDD, then all you’ll do is write bad tests, and make the unit test suite less usable to me, without even getting any of the benefits.

Instead, I’d make a process (probably as part of the build) that ran the appropriate suites, and make some kind of check to make sure they were either run prior to checkin, or immediately afterwards.

Yes, I want people to write tests.  But the best way to get them to do that is by example, and showing them how useful the tests can be.  What I don’t want is for people to break the tests, rendering them useless.  And, I don’t want poorly written tests that are likely to fail due to configuration issues, or take forever to run.

If I make users manually run tests, it’s another process that they have to do - they’ll put it off as long as they can.  And if there’s a break, they’ll probably have worked well past the original error, and have to rework a lot of code in order to get everything to work again.  They’ll end up hating the unit tests, and the quality of the suite will degrade.

If the tests are in another directory, developers will have to sync two directories, and switch directories to build/run tests.  Again, this will make them run them less often.

By making the tests run as part of the build process, I make it hard to break the tests.  If the tests break, you don’t get a successful build.  Now, you have to circumvent the build to get anything done.  If it’s your change that broke the tests, it’s probably easier to just fix your code, since you’ll have to do it anyway.

And, if the tests are part of the build, slow or failure prone tests will become painful for everyone - as long as it’s easier to move the tests to the appropriate suite than it is to circumvent the build, they’ll do that.

General development

Comments (0)

Permalink

Test-Driven Development Demystified

A lot of people have probably heard of test-driven development, and the buzz around it.  There’s evangelists and zealots, frameworks (unit tests and mock objects and acceptance tests, oh my!), and a lot of heated discussion.

What I don’t see a lot of is the basic ideas of test-driven development, distilled and put into a form that most programmers can relate to.

A typical pattern that I’ve seen is the creation of separate applications or workspaces to isolate a component while you’re developing it.  If you were to do that with a stack, it might look something like this:

static public void main(string[] args)
{
   Stack s = new Stack();
   s.Push(”foo”);
   s.Push(”bar”);
   string test = s.Pop();
   System.Console.WriteLine(test);
}

In some cases, you’ll write this before you even write the stack class, as a way to define your API in an outside-in way.

After you’ve written your Stack class, and you get the results you want, you’ll probably look at the insides of it to optimize it, or make it designed better.

If you’ve done this, congratulations, you’ve used test-driven development.  No, really.  Everything else surrounding TDD is nothing but tools to help write and run these types of testbed or sandbox programs.  For an experienced developer, it really is much ado about nothing.

Game development
General development

Comments (0)

Permalink

TDD Tidbits

A couple of thoughts I’ve had on the TDD process that may not be inherently obvious.

  1. If you already have a complete spec with all of the API, and cannot deviate, you are not doing TDD.
  2. When writing the test first, the failed compile is a good thing. This helps prove that you don’t have any kind of strange name overwrites that you’re unaware of. The value of this, of course, depends on language.
  3. Once the compile errors are fixed, the failed tests tell us that the component isn’t “accidentally” doing what it needs to be. If it is, we need to figure out in what circumstances, or why.
  4. One of the big problems people seem to have with TDD is not refactoring. Refactoring is, in my opinion, the most important step. Without refactoring, using TDD, you will have garbage code (though it’ll probably have a nice API).
  5. People seem to balk at the idea of writing the minimal code to get the test to pass.  They somehow think that this is supposed to be final code.  It’s not (necessarily).  The point is to allow you to enter the “green” (refactoring) phase earlier and with less work.  When possible, we want to be in the “green,” so that we know if we do something that causes a break.  If we try to write our ultimate design up-front, that just means that a lot of code is being written at one time without any assurances that it works.
  6. If you find that you need to refactor to make a test work, comment out the test first, and then do the refactoring. Always refactor when green. Otherwise, you’re getting into the trap of refactoring while changing functionality, and that’s a slippery business.
  7. People think TDD means no design. I don’t agree. Generally, you start with a class, which implies a certain amount of design. But TDD folks think about design, a lot. They just don’t think about design a huge amount up front, except for high-level architectural decisions, and they retain flexibility to change the design in case they were wrong.

And a final though: Since adopting TDD, I find development without it to be somewhat weird. Just as non-TDD’ers think we’re weird for writing tests first, I think what they’re doing is strange.  To me, writing tests last (or not at all!) is essentially writing a bunch of code, and then trying to figure out what it does.  It just feels very unsafe, and I just get a weird feeling when doing it.

I don’t know how valid that is, or if I’ll think I’m an idiot in five years for thinking like this.

Game development
General development

Comments (0)

Permalink

Plans vs. Planning

“Plans are nothing.  Planning is everything.” - Dwight D. Eisenhower

One of the common criticisms I see of any kind of agile development (note: agile with a little a, not a capital A) is that people seem to believe that agile development means that you don’t plan, don’t design, and don’t document.

In my opinion, this couldn’t be further from the truth.

In fact, I’d go so far as to say that agile development involves more planning, more design, and more useful documentation than other methodologies.  The key difference is when you do the planning, to what extent, and what information you derive from it.

I’ve worked on projects that planned to the extreme.  There was a gantt chart which specified what you would be doing at 2pm on Thursday.  Now, that’s somewhat okay, except that the Thursday in question was two years into the future.

Let’s come up with a hypothetical example.  Let’s say you’re going to start a brand new Generic Fantasy MMO from scratch.  Do you just start diving in and writing code and making art?  I’d hope not, and I doubt anybody with a brain would suggest that.

You start with planning.  You know you’re going to need art, some levels, some amount of design documentation, and code.

You’ll know you’ll need some areas for people to walk around and swing their swords.  How many?  Well, that’s a function of how large they are, but we’ll say 100 distinct “areas,” where each area is more-or-less self contained.  How will we make them?  In Max or Maya?  A custom tool?  Who will make them?  If designers are doing the layout flow, we probably don’t want to have them use Max, so we’ll need a custom tool.  How will that tool work?  Will it plug together pieces Lego-style?  While it give more freedom, and then allow artists to perform a beautification pass?  How many levels will be inside vs. outside, and how does that impact what tools are needed?  What are the plans for future expansion after release?

Once we have some of these answers, we can start putting together a plan.  Let’s say we want a 50/50 mix of outdoors and indoor areas, so we’ll need relatively strong tools for both.  We want designers to do at least initial layout, and we’re pretty sure we can use a “Lego-brick” approach.  We’ll still need artists to create the bricks.  But, we can start using this knowledge to make a plan for what resource we’ll need, when we’ll need them, and how we can go about putting this thing together.  In this case, we’ll probably need at least one programmer pretty quick, with at least some art time not too long after that to create some sample “bricks” (once we get past the programmer art stage).  We can make a rough guess as to when at least some functionality will be done, and start making sure we have more level designers and artists for when that happens.

And the plan will be wrong.  Period, end of story, no matter what.  Your estimates will be off.  Things will change, your knowledge of the problem will increase, and you will have to adapt.

So, in that case, what’s the point of planning?  In this case, the simple act of planning gave us a good amount of the information that we needed at that moment to make the decisions we needed to, and could make, right then.  It gave us enough information to start making staffing decisions, and helped us define the scope of what we were doing.  It made sure that we thought the problem of “how do we make levels” through, and didn’t miss any major pieces of that particular puzzle.

We didn’t try to nail down too many specific details.  We didn’t say exactly what each dungeon should be, or how we were connecting areas, or anything at all of that nature.  Those are details that are unimportant at this time.  They don’t impact a single thing that we’d do for the next month or so.  So, instead of wasting time arguing about them now, do another planning session in a month (or 2-3 weeks, or whenever), revise the plan as your knowledge has increased, and work from there.

People using agile development (I refuse to use “agile” as a noun or to capitalize it) do plan.  They plan a lot.  They just see the value of planning in the information that comes out of the exercise, not the specific set of dates and requirements.

This seems directly counter to what I’ve seen in BDUF-type organizations.  Plans, in those orgs, tend to focus excessively on the detail level, and actually focus less on the high-level decisions.  In my experience, those are the wrong things to worry about at the beginning of any project.  They’re almost always easy to change, require knowledge you don’t have anyway, and subject to iteration.  Yet, somehow, I see planning documents that focus extensively on these minor details, and merely imply the larger decisions via these details.

General development
Uncategorized

Comments (0)

Permalink

Decoupling Code

Everyone’s had to deal with it.  The big, nasty project, where everything links to everything, and anything you do can have seemingly random effects in apparently unrelated areas.

So, let’s look at some ways to avoid that.

But first, let’s define what we mean by “coupled.”  Two pieces of code (classes, modules, whatever) are coupled if they have to know how each other work in order to function.  Couplings can exist one-way, or two-way.  Some coupling is good - programs probably wouldn’t do much without them.

Where the sinister evil starts to sneak in is unnecessary coupling, and unnecessary intimacy.

To start with, let’s look at a piece of code:

public class SomeClass
{
    public void DoSomethingToCharacter(Character c)
    {
        string username = c.Connection.User.Name;
    }
}

Okay, so it doesn’t do much at this point.  But it’s a pretty good start as to where there might be a problem.

And what problem is that?

Well, it’s pretty apparent that this method needs to do something with the character’s name.  But to get that information, we have to go through both the connection and user properties.

This opens us up to problems.  First, it means we have a physical dependency on those classes, which can create compilation time issues.

Secondly, it means that to get the data we want, we have to know quite a bit about the class we’re using.  We have to know that it has a connection object, and that that object has a user object, and that object has a name.  I don’t want to know that much.  I just want the user name from the character!

The worst problem is that we open ourselves up to build breaks every time we use this access pattern.  If any of those classes change, we break.  And probably in lots and lots of places.

Let’s look at an alternate:

public class SomeClass
{
    public void DoSomethingToCharacter(Character c)
    {
        string username = c.UserName;
    }
}

Ah, yes.  Isn’t that pretty?  Now our code only cares about the character we class.  We don’t know how many layers of ugliness are going on underneath, and we don’t need to.  Even better, if one of them breaks, the damage is going to be limited to inside the character class itself - which means an obvious place to fix, instead of hunting down those chains of objects all over your codebase.

Oh, and for what it’s worth - those chains of objects have a name.  They’re called “train wrecks,” after all of those objects smashed into each other.  It’s not a term of endearment.

And what I’ve been describing has a name as well - it’s called the Law of Demeter.  It basically states that a given method can only use methods internal to objects it owns, on objects that are passed in, or on objects it directly creates.

General development
Uncategorized

Comments (0)

Permalink