Wednesday, January 13, 2010

Your Tests Are Making Your Code Inflexible

A Very Naive Approach


Most of us will agree that making code flexible is a primary motivation in writing Object Oriented code. Otherwise, we would write our app as one giant class, with one giant method, and call it "efficient'. We would copy-and-paste everywhere, because we don't want to introduce any "complexity" by adding methods. We certainly wouldn't want to create whole new Classes... then we would have to look in more than one file to figure out how the system works! That is way too prone to error!

Coming back to Reality

No, of course we don't have that mindset. Our code should be split up into as many classes is necessary for each of them to be responsible for one thing. Each class should, in turn, have the appropriate number of private methods to make each of them trivial to understand in isolation. And the public API of the class should be small and cohesive, so as to keep it from having to change for more than one reason.

And tests! We need lots of tests! We need to make sure that each of our classes is tested at a sufficiently low level to be able to test every feature and expectation. This is where we run into a problem.

What is wrong with this code? (Borrowed from JUnit and Clean Code by Robert Martin):

 assertEquals("expected:<b[a]> but was:<b[c]>", failure);

I have only shown a few tests for brevity, but there are many more like it in the book (pg. 283 of Clean Code). Uncle Bob comments on the code, "I could explain it further, but the test cases do a better job. So take a look at Listing 15-1 and you will understand the requirements of this module in depth. While you are at it, critique the structure of the tests. Could they be simpler or more obvious?"

Simple and/or more obvious, does not a good test make.

I agree that the tests are very simple and obvious. They convey what they are trying to test very clearly. However, I have a problem with these tests. They are not very DRY. In fact, on the scale of DRYness, they are unbelievably WET with duplication.

Those who know what DRY means, know what I am talking about already. Basically, there is a ton of duplication in this code. I am about 87.3% sure that Kent Beck (or whoever wrote these tests) used CTRL+C, CTRL+V more than a few times when writing 50 unit tests that look almost identical. It seems that most people think this is okay, because they’re tests. That you should be writing similar code for similar tests in the name of readability. However, I think if you find yourself writing the same code over and over again, you have a problem with focus. Each test should focus on a feature.  You are probably testing the same thing in every one of those tests you copy/pasted. 

Just like you don’t want one giant test that tests everything under the sun, you don’t want tons of tests that all test the same thing when they shouldn’t care about that thing!

In this example, that something is the format of the return string.

Why Won’t the Maintenance Team Invite you to Lunch? Because you Copy/Paste Test Data

So how does this make it inflexible?  What if we wanted to change the "<" and ">" surrounding the discrepancy into "[" and "]". Well, we would do a simple search and replace in our IDE, you say. What if the substitution isn't so easy? What if we wanted to change the first "..." into "--", but not the second set? We would have to manually go into each test and modify the relevant portions.  What about adding an extra parameter to the constructor that these tests don’t care about?

You have to make a change to every one of your tests.  You have to muck around with the code until it passes again, and now you have more nulls, or even worse, more “magic” numbers, in your tests.

One Solution

You don’t have to sacrifice readability to soak up all that wetness in your code.  Lets take one step forward here, shown in the next example (# of tests cases reduced for clarity):

assertFailureHasProperMessage("[b]","[c]",failure);

So we’ve split out each assert into a method. One big win here, is that the formatting of the message, which is clearly not what we are trying to test, is tucked away in the method.  The string still gets tested just as before, but now we don’t see it in each and every test – which now more clearly shows the bits we are really trying to assert.  Unfortunately, passing in multiple parameters gets hard to read really fast, and we want to be able to use our tests as documentation.  Also, wtf is the first number in the constructor supposed to do?  You have to look at about a dozen test cases to figure out its purpose.

Domain Specific Languages

A really good way to make your code self-documenting is to have lots of small, descriptive function and class names.  Well, since our tests ARE our documentation (at least to other developers on the team, and your future self), we should follow this pattern even more.  instead of:

 image

We could have something like:

image

This allows us to concisely state, in almost regular language, what we want the test scenario to be.  It is a mini-language, called a DSL, or Domain Specific Language.  Notice, also, how the “.compact(null);” section is missing.  That is because we don’t care about it.  We aren’t using the message passed in, so the builder object inserts the null for us.  If we don’t care about it, we don’t want it showing up in our test.

Another benefit we get from this approach, is that we aren’t directly manipulating any of the code; we are calling functions on an object, which eventually manipulates the code.  In my opinion, this separates two concerns that rarely get separated: the semantics of the test, and the syntax of the test.  If we change the constructor to take more data, all we need to do is add another function to the interface, and all the tests will again pass (unless there is a bug, of course). 

You see, we shouldn’t care how many parameters the constructor needs in the tests, we just want to input some data, and make sure the output was correct.  We want to work at a higher level.  We are manipulating at a low level, but describing at a high level.  We do this in our production code as programmers, why not in tests?

Now, we can make our test harness handle null information for us, and handle the passing of intermediate data like the “String failure” in the first example.  Below is the entire Test class with the harness.  Obviously, it looks large as there are only two tests shown here, but the harness is mostly a one-time cost, so its effort in proportion to the benefit gets smaller over time.

 image

What Have We Done Here?

Essentially, we have created our own domain “language” for testing.  It isn’t flexible enough to describe all code; just this class or set of classes.  We can also reuse frameworks like this in other tests.  Generally this pattern is called the “Builder” because of its property of returning itself from a setter method.  This allows us to chain methods together and “build” an object with very little boilerplate code.  It is generally used with fluent interfaces and Domain Specific Languages because it allows for a more language-like syntax directly in the code. 

This type of testing may not work for every case, but I would seriously consider it on your next project, and try it out for yourself.  DSLs are somewhat hard to write well, so practice makes perfect (and I am new at this as well, so I have a lot to learn).  You may find out interesting properties of how your code is structured by writing a DSL for it. 

Disagree? Leave a comment.  A colleague I respect “whole-heartedly disagreed” with me on this, so I am open to a little discussion :).

Saturday, July 18, 2009

“Theft”

What is theft, really?  From my perspective, theft is removing an item from a person or organization without their consent.  It does not necessarily dictate that the thief keep that item, or what happens to it after it has left the protection of the original owner.

He drinks your screwdriver.  He drinks it up.

Why am I trying to define this term?  I am trying to figure out why it seems many people object to stealing software, and why others seem to think it is okay.  I am also trying to figure out which side I am on (although my natural instinct is to justify my past actions by saying it’s okay).  At the moment, I am thinking that it’s the business model and economics of software that eventually need to change, and not the morals of all the download-happy, wAreZ surfing, iso-kiddies.

Analyzing a few scenarios

But all I have are ogg vorbis files! :(

So what happens when an item gets stolen in the real world? Well one person physically removes that item from the store or person, and then either keeps it for themselves, or sells it.  The person who originally either created or bought that item, now doesn’t have it.  That original owner has lost some quality of life simply because another person decided they wanted it.

In contrast, what happens when a piece of software gets “stolen”?  Digitally, each bit is accessed and copied from one medium to another, creating an exact duplicate.  That duplicate is then usually made accessible to the internet, which then allows other computers to access and copy each bit for the purpose of storage on their own machines.

In the first case (“real world” stealing) – after the “act” is carried out, there is still one item in existence.  That item is now in the hands of the thief and not the rightful owner.  In the second case, there are now a total of 3 copies.  One, still unchanged, in the owner’s possession, one in the “thief’s” hands, and one for the person who downloaded from the internet.

Copying software in this way doesn’t harm the original person’s quality of life.  In the case that the original owner created that item, it will cause them to have a harder time selling it if the copies start getting widespread visibility.

OSX Leopard on Windows 7

Motivation

Getting paid is clearly the main problem people have with copying.  The copier doesn’t (usually) pay the creator for that software.  Yet, the creator obviously spent many hours out of their life creating it.  They deserve some sort of compensation for their contribution to mankind.  If this person got no compensation for the work he/she did, there would be no real motivation to do it.  It would make more economic sense to work at a company and get paid a steady salary.

I will assume that last paragraph’s statement is agreed upon because anyone against it would be proposing that we start being communists.  We need money to motivate us in a capitalist society!

Without the creator making the software/music/video/etc for the masses, nobody would be able to copy and enjoy it.  However, copying is so easy in this digital age, that I believe it is unreasonable to simply expect people to just not copy this stuff.

“Real World” Analogy

What is the “Real World” analogy to software piracy?  I think it would be like someone inventing an “Atom Copying” machine.  If someone could go into a store, scan a product, and then leave with an exact replica of that item, it would be comparable.  Now keep in mind, that each scan costs the user some small price, but they don’t pay the creator this price.  Obviously the store keepers would start getting angry that people keep walking into their store, scanning items, and walking away with a copy!

Are laws really the best solution, though?  If this “atom-copier” happened, I think we might need to re-think commerce.  If we can copy anything, couldn’t we then copy things like food, and then ship it to 3rd world countries?  We could copy the dollar bills in our pockets to make more money!  The whole economy would collapse!  I suppose the new form of currency would be the raw materials the machine needed to create these things.

Although software hasn’t caused the whole world economy to collapse, it certainly seems to have shaken up the music/movie industry.  They have relied upon the fact that people can’t get their hands on unlimited listening of their music or watching of their movies without paying them.  I think this is a shaky assumption – and has clearly been broken down by the invention of bit torrent.

What to Do?

So what do we do about the current situation?  The people who get media from the creators would like for them to make money.  They just don’t want to (or can’t) pay them themselves.  My current thinking is that we need to start creating things that cannot be copied.  We need to create value for people that they can’t do for free (like copying bits).  Now that we cannot charge for copying bits, we need to think of another way to create that value.  The fact that copying bits is so easy sets off a signal in my brain that it no longer has monetary value.  It’s the “idea” that counts in this case.  Obviously, I am getting at “intellectual property” now, but I am not sure it should work the same way it does currently.

Should there be some sort of government setup for people creating ideas?  Sounds like a law to me.  I really would like to avoid arbitrary laws to keep society functioning – it always seems to fight the natural flow of humanity and eventually becomes more hassle than it’s worth.

Maybe we just need to set up web services that force the user to pay.  Just simply arranging 1’s and 0’s in a particular order is not really enough to make money.  If we have a web-based application, we can require a log-in, and then most of the code is on the server anyway – so there is no way that anyone can copy that asset.  The downside to this is forcing a hosting fee for your entire user-base.  That sucks!  Now you have an O(N) cost complexity just because you don’t want people stealing your software!

However, if you think about it, regular products have an O(N) complexity for their users as well.  They need to physically produce each product they create and then physically ship each of those items to the proper location to be sold.  The lack of this process is partially why we like software, but for now it might be required to enforce morals on the seething masses.

So anyway, I have thoroughly confused myself about the subject, so I would like some feedback if anyone is so inclined.  What do you think we could do to take advantage of our awesome technology of file-sharing, while also paying the developers that make awesome software?

Wednesday, April 1, 2009

Working at Union Pacific

Recent Happenings


So anyway, it turns out I'm now in Omaha working at Union Pacific. It's a railroad company, and its actually pretty cool. I am working on a very crucial product for the business (it's called PTC or Positive Train Control).

I am being challenged every day here, so this is a plus. I know that I absolutely need to keep learning at a break-neck pace if I want to move up in the world. Especially with technology companies. I bought a book called "Agile Software Development" by Uncle Bob (Robert Martin) to better understand the "theoretical" best way to decouple my designs and utilize TDD. I also discovered a book called "Clean Code" by the same on our e-learning website. Since my current team here isn't enforcing any particular software development practice, I am on my own to learn one. This is not because I think that there is one particular method that will fix everything, but because I think it is important to at least know one or two of them so you can start to learn WHY they are there in the first place. Then you can eventually become comfortable enough to roll your own "methodology" and proclaim yourself the lead evangelist if you like ;)

Procrastination and laziness


From my previous post, I was brainstorming ideas on how to maximize my learning while away from work. This didn't turn out as well as I hoped. I sort-of hinted at what I was suspecting about my job - was that I would be tired and not really in the mood for programming afterwards. Well, its not because I hate my job, but more because there are lots of time-wastey things to do at home that keep me from getting things done. Here are my personal evils:
  • Google Reader
  • Gmail
  • Hulu
  • Netflix
  • Peggle (yeah...)
  • 50 Cent: Blood on the sand (Ok, I can explain. My friend had me rent it for multiplayer! I swear!)
  • Intoxication (it doesn't take much alcohol to inhibit the "i want to think" part of the brain)
  • Working out/ Losing weight
The last one there isn't really a time-waster, but it sure is a will-power draining task. I have been at that since I started at UP and it really does take some motivation to keep going. After that, I feel like I deserve a break - not more stress and coding.

Even with these setbacks, I have managed to get something started. I am working with Django trying to create a website about goals. Right now they are fitness and diet goals, but I would like to generalize them to any type of goal or aspiration. I think it is useful to be able to track this stuff online in a social atmosphere. However, the pace has been painfully slow since it takes so long to "wind up" my brain for coding - and my brain usually isn't rested from work until about 11pm - an hour after I should already be in bed.

Reality Setting In


One thing that has changed in me since my last post, is all the excitement I had for the future. This isn't to say I am not excited about it, but that I see how many challenges and hurdles I face. I initially thought that since I'm a self-proclaimed "smart person", that I would figure out a way to succeed. That may still be true, but the more I learn about starting a business and what is already out there, the more I realize that ideas are a dime-a-dozen. This means that the startups that succeed are the ones who make it through thick-and-thin AND can adapt to the market. Not necessarily the ones who have a good idea to begin with.

Even if they have that, there is no guarantee however. There might be some minor thing you did to make your users wary of your product and nobody buys. Maybe nobody ever told you that you aren't supposed to do X so you did it and lost all your money. Life is unfair like that, and only the people who take those setbacks as challenges and fight back are the ones who succeed.

Take Mark Zuckerberg. He is incredibly successful with Facebook. He is a multi-millionaire and owns one of the coolest companies you can imagine! If he wasn't so nerdy I'm sure he would get all the chicks! But Mark is in a big dilemma right now - how to monetize? They could go under just like anybody else. How would he feel if Facebook could never really keep revenue > expense and eventually died out? It is possible, and Zuckerberg knows it. That must be terrifying.

I guess my point is that there is no time in life where you just go BOOYAH! and you now have money, women, friends, assets, and free time and not a care in the world. Well maybe Tim Ferriss does, but nobody else.

I still think that I will get the most out of life by trying the entrepreneurial route. However, I now realize that my "happiness" will not likely be some stress-free life. It will be filled with problems that need solving, and it will be up to me whether I sink or swim. I hope I swim, but that is yet to be seen.

So what's your point again?


Everyone wants to have a good life. But it's not easy. My level of happiness is probably comparable to what it will be as an entrepreneur in the future. I will just have higher standards for certain things, and maybe lower standards for others. The only thing preventing from me being happy right now is the thought that I should be doing more to get better. So really, I am trying to say everything is relative. Make the most of it while it's happening and stop worrying so much about the future (like I do)!

Thursday, December 4, 2008

Crunch time declared over (almost)

Well, I just turned in my last assignment of my college career. Of course, I still have two exams next week, but i'm not worried. I am looking at a few different companies for after I graduate, and thats really all they care about.
Anyway, I am trying to figure out what I should do in my free time once I start working. I am a firm believer in continuous improvement and learning, and it needs to happen as much outside work as in. I will either be working on Java or .NET technologies at work, so I will have that covered. But what to do in my free time? Here are some ideas:
  1. Graphics technologies like OpenGL or DirectX
    • 3D screensavers
    • Study pixel shaders
    • Novel 3D networked application (3D browser that doesn't suck?)
  2. Web applications
    • Website that tracks progress toward a goal on projects
  3. Web comic
    • Maybe not a good one, but a good experience nonetheless
    • Programming webcomic? Should research existing ones first
  4. Deviant Art stuff
    • Learn about art more professionally - get used to Photoshop CS4
    • ACTUALLY READ the design books I bought a while back
  5. Web business
    • Create a Super-low cost business, and fail at it (well try not to)

Those are just some Ideas floating around in my head at the moment, but its so exciting to be choosing between these things. The world is my oyster! I just hope I don't hate my job so much that I am exhausted by the end of the day consistently. Oh well. More ideas to come (and maybe even a comic!)

Monday, November 24, 2008

Omaha Trip


The view from Omaha. Who knew that Omaha was such a big place! My trip to Union Pacific was great and I got to meet some really interesting people. I was a little worried at first, because the first thing I heard when I got off the plane was light country music, and then I saw a guy in a cowboy hat..

Once we got into the city, however, it was just like Chicago or Boston. Tall buildings, people always on the go, tons of restaurants and things to do. There really is nothing bad about Omaha. Housing prices are fairly low, gas is cheaper, people are nice, AND you can always have something to do. We will see if Union Pacific gives me an offer; it will be a tough decision.

Expensive dinner


Surf n Turf room service in Boston

Monday, November 17, 2008

Raytheon trip (Hyatt Hotel)

    I'm in Boston, MA right now getting ready to go on my trip to IADC (Integrated Air Defense Center) in Andover, MA.  Sounds fun! I don't have any interviews today; just touring Raytheon and then a formal dinner at 6pm.  Tomorrow I will go through a series of interviews and then be done around 1:30pm.

Check out the video below (this is the view just outside the hotel lobby).