Friday, August 29, 2008

"Make Something People Want"

I came across this article in the Wall Street Journal regarding issues that sellers have been having with eBay. This reminded me of a recent conversation I had with another software developer friend of mine regarding how craigslist could be improved with...something else.

If a potential competitor of eBay were to read about its users' woes then it would definitely be a nice blueprint on how to build something better. Why? Because it is "something people want" but are not getting.

I don't know if eBay's problems could necessarily be solved via technology (although some looked to be that way). But, it serves to show that just when you think something has been "solved" then think again. Has online auctioning really been "solved"? Has online "classified ads" been solved? Has "[fill in the blank]" been solved?

Classic example is Google. When they first entered the search engine market everyone believed that search engines have been "solved" and it could not possibly succeed against the more "mature" search engines available at the time...well, we all know how that story ends. But even with Google what it is today, still, you can not assume that search engines have been truly solved. For example, there are folks that do feel it is not solved and therefore are attempting to take on Google. But given Google's own beginnings it does not sound strange at all and should serve as an illustration that it can be done (or at least attempted).

If you do want to build something people actually want then keep some of following things in mind in respect to your competitor:
  • Keep your features list smaller- More features != better product. Most people think this makes for a better product but that is a complete fallacy that has been proven time and again. Keep it simple and focused on features that people actually would use. It does not matter how many features your competitors has in their product. It only makes their product worse and harder to use. Check out the book 'The Inmates Are Running the Asylum' to get a better idea as to why this is true.
  • Make it easier to use- Sounds "easy" but it is not. You really need to cut down on the amount of friction it takes in using your software as compared to your competitor. Make it goal oriented and not task oriented. Check out the previously mentioned book as well as 'Don't Make Me Think!' for infinitely better explanations than mine.
  • Stay smaller and leaner- Your main goal is your product. Try not to worry about building an empire. Do not focus on other unrelated products that you could make. Do not aim to take the whole market because in some markets even as low as a 5% share can be quite lucrative (you might be serving some niche that is not being adequately satisfied with whoever is the current market leader). Do not hire extraneous folks which only serve to drag down your costs. And so forth...
  • Ignore your competitors- Seems like a contradiction to the previous ones but not really. Who cares what your competitor is doing? Care about what they are not doing and what that means for the users.
Finally, as a software developer/engineer/programmer/hacker what can you do? I suggest you start here.

Tuesday, August 26, 2008

Mocks vs Traditional Asserts

I encountered something extremely interesting regarding assertions versus mocks. Traditional assertions (e.g. the NUnit asserts) are typically for "state-based" type testing while mocks are for "interaction-based" type testing.

I find that I am using assertions less and less. I'm not sure if that is a good or bad thing. A few weeks ago, I was working on adding some functionality to one of the domain objects for the project at work which unlike for Controller classes in MVC tend to be more state based testing than interaction based. At least that's what I thought.

Below is a simple method that I needed to test:
// domain object- TaskManager
public IList<Task> Reassign(IList<Task> tasks, string newTeam)
{
foreach (Task task in tasks)
{
task.Team = newTeam;
}

return tasks;
}
The following test uses traditional assertions:
 [Test]
public void CanReassignTasksToNewTeamWithAsserts()
{
TaskManager manager = new TaskManager();

const string oldTeam = "Old Team";
const string newTeam = "New Team";

// setup test data for tasks
Task task;
for (int idx = 0; idx < 3; idx++)
{
task = new Task();
task.Team = oldTeam;
tasks.Add(task);
}

// assert the re-assignment
IList<Task> updatedTasks = manager.Reassign(tasks, newTeam);
foreach (Task updatedTask in updatedTasks)
{
Assert.That(updatedTask.Team, Is.EqualTo(newTeam), "The task's team was not re-assigned.");
}
}

Now here is another test whose intention is to test the exact same thing but using mocks instead:


[Test]
public void CanReassignTasksToNewTeamWithMocks()
{
TaskManager manager = new TaskManager();

const string newTeam = "New Team";

// setup test data for tasks and set expectations
Task task ;
for (int idx = 0; idx < 3; idx++)
{
task = Mocks.CreateMock<Task>();
tasks.Add(task);

// set expectation to assign task to new team
task.Team = newTeam;
LastCall.Repeat.Once();
}

Mocks.ReplayAll();

manager.Reassign(tasks, newTeam);

Mocks.VerifyAll();
}

Guess which one I wrote first? Of course the one with mocks even though I started with the complete intention of doing it with state-based assertions but it quickly morphed to using mocks.

It was really interesting to produce these two tests that are functionally different but accomplish the same goal. They both "fail" if you remove the line:

task.Team = newTeam;

or if you place a different value:

task.Team = "Make this test fail.";

Since they fail by doing either of the above that means both tests are good, valid tests, right?

So, which should I use? Truthfully, the test with mocks is less brittle because you do not need a real instance of the "Task" object. But am I taking it too far? One "problem" I seem to have is that since I have been using mocks for so long my mind is wired to use them for everything (once again, is that a good thing or an anti-pattern?) Basically, when I think about how to test something I immediately think in terms of expectations with dependencies.

Perhaps mocks win out in this situation and in most it is better because true unit testing means that the only real instance of an object is the one that you are trying to test and essentially everything else should be mocked and/or stubbed somehow. Perhaps assertions are best with objects that are not primarily defined by their dependencies and that simply perform complex algorithms that return value types results (for example, static classes and methods). Of course, I could be oversimplifying that but I find it really hard to know when to use plain vanilla assertions.

Well, shortly after stumbling upon this "dilemma" on my own, I then read Martin Fowler's article named Mocks Aren't Stubs and it became much clearer to me what I was doing and why (as it always seem to happen whenever I read any of Fowler's stuff). According to him, I would be classified as a "mockist TDD practitioner".

Honestly, some of the reasons he lists for choosing not to be one (as opposed to a "classical TDD practitioner") are things that I definitely felt on my own especially recently when I was struggling with writing a bunch of mock heavy tests that started to get unwieldy and far more complex than the thing I was actually testing (let's just say it was a weird, dark period in my recent dev efforts that I was really questioning the use of mocks).

The quote below from him is definitely something that I thought to myself off and on for as long as I have been doing "mock testing":

"...A mockist is constantly thinking about how the SUT ["system under test" a.k.a. the object under test] is going to be implemented in order to write the expectations. This feels really unnatural to me..."

Monday, August 25, 2008

Applying good software development practices to VBA and MS Access (and tools, too!)

After working with TSQL almost exclusively for the last six months the time came last month where I had to make code changes to a Microsoft Access front-end application at work.

Based on what I have learned in the past several years or so regarding software development in .NET, I decided to arm myself for tackling legacy code in a platform and language notoriously known for not being ideal for software development.

IDE Tools

I accidentally came across MZ-Tool a plugin for the VB Editor IDE and wow! This made all the difference in the world. It was nice to find a free tool to inject a little ReSharper-ish support into the rigid VBA IDE. The product apparantly started in the VB\VBA world and when .NET came along it was ported to Visual Studio.NET. (It can actually be considered as a direct competitor to Re#. Note that the .NET version is not free.)

Here are the features I was using actively during coding:
  • Replace In All Projects- This was huge in that it allowed me to actually perform the refactoring technique, 'Rename', with various levels of control. What really made it possible is the actual visual tree view of your code where the text you want to change shows up as well as showing what function/sub where it can be find under. I was not afraid to actually change names of things that were either goofy, confusing or antiquated in coding style into much more meaningful names. In the end, I had significantly less fear in breaking code. (This feature is equivalent to Re# 'Find Usages Advanced')
  • Procedure Callers- Similar to Re# 'Show all usage" for a method or variable (and it's also navigable via a visual tree view)
  • Code Templates- This allows me to create and permanently store boilerplate code that I needed for testing code using VBLiteUnit (see next section). This feature opened my eyes to more actively use and create with 'Live Templates' in Re#.
  • Add Procedure- Slick and fast way to create more boiler-plate code for procs/func.
  • Add Error Handler- This was a gift from the heavens. Being able with a simple keystroke drop in code for error handling in any sub/function. Error handling is horrible in VB/VBA so this significantly helped in reducing the pain.
  • Add Module Header and Add Procedure Header- It's just like having GhostDoc. Adding comments is very important in legacy code.
  • Sort Procedures -Helps organize your code. It is equivalent to Re#'s 'File Structure Popup' which I use all the time for the same reasons: drag-n-drop your code to how you see fit.
  • Private Clipboard- This can be big in legacy code and in a language where you do end up with a lot of cutting and pasting. Actually, better than Re#'s version because you can actually control what is stored in it and can retain it for as long as you like within the duration of your session.
  • Review Source Code- A extremely limited version of code analysis in Re#. It only tells you if a variable, constant, procedure is not being used. But good nonetheless to clean up your code and get rid of cruft.
The following features were interesting but less used day to day:
  • Generate XML Documentation- produces a very nice readable xml doc about your code comparable to XML CHM output in VS
  • Statistics- You can actually see how your lines of code is distributed in your code base.
The one thing I wish MZTools had which IMHO I consider to be one of the two most important refactoring techniques is 'Extract Method' ('Rename Method' being the other). If it had that it would be quite the rock solid refactoring tool for VBA. Nonetheless, MZTool just like Re# in Visual Studio has given me control over my code instead of the code controlling me.

Unit Testing

Being a dedicated practitioner of Test Driven Development (TDD), this was important for me to do on a lot levels. After looking at two options I settled on VBLiteUnit because it is extremely lightweight and the ramp up learning time is short especially if you are familiar with any of the other xUnit frameworks (which is exactly what the author intended in creating it hence the word "Lite" in its name. My belief is that the author might have thought that the existing one out there, VBAUnit, was too bulky and cumbersome to use and maintain. Definitely a much more "pragmatic" and "agile" approach in his solution.)

The author decided to use the VB construct 'Select Case' (think 'Switch') with each leg of your 'Case' defining an individual test. Impressively it works really well (and added bonus is that your test descriptions can be more descriptive and natural in tone because it's just string text. Interesting to note as compared with a blog post on Unit Test Naming Conventions written by a developer I used to worked with)

To implement my new changes, as expected, I did have to do some refactoring of the code that required to be touched. This generally resulted in new testable classes but I had TDD with VBLiteUnit (and MZTools) to lead the way.

All in all it was very satisfying to be able to actually do TDD in Access/VBA. It gave me that same feeling that I get when doing TDD in C#. The platform for a moment felt much more real as software development than it ever had before.

Results

Some lessons were learned of course ("evolve or die"). If you have no choices, resources, etc. in a situation no matter how "trivial" then you still attack your problem 100%. Why? Because you not only get to apply and transfer knowledge and techniques to another area of software development but also you might actually learn some new things that you can in turn use later on. For example,
  • I started using the Immediate Window much more now in Visual Studio.
  • I started using features in Re# that I had not used or dismissed before (like the live templates, copy clipboard, etc.)
  • Design patterns can still be used even with what some might consider a "rudimentary" language. For example, I was actually able to implement a variation of the Repository pattern (ala Eric Evan's DDD) that hydrated a domain object and make it work. Hence if you understand design patterns and how to use them then it does not matter what OO language you are using.
However, I can see why VB developers don't know OOP. One good reason is that VB is lacking in some key features of an OOP language. The biggest one in my opinion is that it does not support implementation inheritance. That was frustrating because I was trying to use a technique that Michael Feathers described in his book, Working Effectively with Legacy Code, to test legacy code. That entails creating a seam in your code by inheriting and then overriding an external dependency. Unfortunately, VB simply just enforces the interface contract but does not carry over the implementation code from the base class to its derived ones.

Nonetheless, using VBA with VBUnitLite and MZTools had actually turn out to be a much more gratifying and, yes, may I even say aloud, "fun" experience than I expected. The main reason beyond the more obvious such as being to do TDD was that I was doing so much TSQL just prior that is was like being transported out of the stone ages. The TSQL language and Microsoft's IDE for it (SQL Server Mgt Studio) was so frustrating to use that working back in a programming language designed for applications even as "minor/toy" and with so much stigma as Access VBA was such a breath of fresh air and extremely invigorating (It was like giving a tablespoon of water to a very thirsty person).

TSQL was and still is such a struggle even with TSQLUnit. It has so much limitations when it comes to creating flow logic, reusable code, and testability. (Granted it is a DSL specialized and intended for manipulation of data and its storage structure but I feel like that the SQL language has not really evolved much in its odd 30 years of existence. In areas that it has changed it ends up resembling other non-SQL languages so what's the point? Perhaps it's time for a better replacement language(s)?) In the future, any application developer that I encounter again who says "sprocs are the way to go" will get an earful and maybe more.

TSQL is so painful in its existing form that, believe it or not, I rather be working in VBA than in TSQL if those were my only options!! I know that sounds crazy and shocking but that's how much I prefer not to have to do database development and deal with TSQL. I'll leave it to the folks who actually enjoy it. But sadly it is the bulk of my work these days. (The one thing I do like about it is it's language support for "dynamic SQL" but that is not enough of a motivation for me.)

Who knows? I went from C# --> SQL --> VBA --> SQL in the last six months. If I had gone from C# --> VBA I probably would have a different opinion and experience. Hard to tell in retrospect.

Don't worry I still do C# and have been doing it for the last six months in parallel on side projects and supporting processes at work. Unfortunately, I am back to doing TSQL for the next several months. Aargh!!!

Final Thoughts

What was the point of all of this other than to rant on about a language no one cares about if you consider yourself a "serious" programmer? Well, just like VB6, Microsoft plans on retiring VBA and possibly allowing Office apps to be supported by any.NET language including C#!! Therefore, the tools mentioned above are "dead" in the sense no new development is going be done on them especially that their respective authors have appeared to have moved on from doing any new releases.

IMHO, I think what Microsoft really should do is to allow dynamic languages to support their Office apps. That is where dynamic languages (ex. Ruby, Python, BOO, etc.) seem like such a natural fit and obvious for the nature of that work. Just imagine you can write code very quickly with ever-changing requirements and it does not have to perform fast (as compared with statically typed languages.) Seems like such a "no-brainer". (maybe in the far, not-too-distant future, power users could even be writing MS Excel or Word macros in F#? Just imagine that!)