A network of sites, tools, and technology to bring ideas into reality.
The Digital Tumbleweed
Thoughts and ramblings of an enthusiast
Fixing Mistakes – Some Thoughts On TDD/Rot/Debt
Software development is always a good way to realize that you’re human. I’m sure there are other professions that give you this feeling as well, but my experience is limited to the software development field so I’ll talk about it from that light. There are really two ways to go on this subject. I could talk about code rot and the need to clean it up and/or talk about test driven development. Because I think they both have something to do with each other, why not make it about both eh?
The Church of TDD
Test Driven Development is a nice concept. The key here is concept. The idea here is that you write tests for a piece of functionality (ideally you know what you’re trying to get out of your function) and then write the actual functionality such that all your tests pass when your functionality is complete. Why you might ask? Well, I’ll answer! The reasoning is that when you’re 3 months into your project, breaking Brooks’ law, and trying to cope with the ever changing requirements of your project, you’ll simply have to make your change and re-run your tests. If they fail, you caught the problems at test time rather than at 3 AM when your boss friend calls you up and lets you know that he was just informed about emails being sent around to customers with usernames, email addresses, phone numbers, and contact lists for about 500,000 users.
Obviously a made-up case, but I have read about similar scenarios. That said, test driven development is only useful when you’re testing the right things. Testing functionality isn’t just about testing that you get a string back in all cases. Let’s say your working with Java and StringTokenizer’s. You might need to test the return values of each token. Also you may have to test the number of tokens or if a token is supposed to be empty that it isn’t null. If an exception should be thrown, you should check that case too. There are plenty of example cases to check here, but the point is that if you’re testing a method and only checking that something was returned then you aren’t finished.
Start out with a plan. This works in either the agile or waterfall methodologies. By this I mean, think about what you are about to produce. It usually helps me to take a step back and process what the method is expected to do. “What do I expect to see when I call x()?” “What assumptions do I seem to be making about x() where I’m calling it?” Running through questions like these are a good way to get a base set of tests for your functions.
So now you have a handful of tests that should make sure your code works right? Right!?!? Not necessarily. Let’s go back to my first line here. “Software development is always a good way to realize that you’re human.” You’ll miss something. It’s inevitable and, what’s better, it isn’t because you are bad at what you do. There are so many other things that are likely going on in your brain. If you are anything like me the whistle of a dart flying by your head or the ping and the pong of a game going on in the distance is enough to bring you out from your “I should write tests” concentration. What’s more, there are just going to be cases that you miss. It is O.K. to miss things, but there is a stipulation here. When you do and when it is caught, you need to write a test that checks for the situation/case.
Subscribing to TDD for the sake of it wont get you far and will likely slow your productivity. But, if you take a pragmatic approach to TDD and write tests as you think of cases your source base will likely be more stable since you’ll find bugs when you run the tests instead of through the client. And, you’ll have a system in place for those bugs that do slip through so that you can make sure they don’t come up again. Clients are a lot less understanding when you have issues with your code base and you can’t assure them that you wont ever have that problem again because you have no tests in place to ensure it.
Code Rot and Technical Debt
Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite…. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object-oriented or otherwise. – Ward Cunningham on Technical Debt
Software development is one of those knowledge based fields. You write software with what you know at the time. If you are any good at what you do, you should still be learning every single day. The old saying “you can’t teach an old dog new tricks” really doesn’t hold water in this industry. Once you stop learning new things, techniques, and methods, you’ve effectively signed yourself into retirement or unemployment. That is just the way our industry works.
So, with this new-found knowledge and all powerful ability you’ll begin to smell something. It’s a familiar smell. You’ll be working on your code base and look at a method you wrote a couple weeks ago and have to plug your nose. That, my friends, is code rot.
The two, technical debt and code rot, are interesting. Understanding that you may take shortcuts to get a project moving only works when you refactor. If you do not refactor your code after you’ve introduced the questionable code you’re in for a “fun” time.
Lets not get the two confused. Code rot is typically when things change external to the code such as your ability to program or changes in the industry that your software works with. Technical debt tends to be what you introduce knowingly to the code with the intention of cleaning up later. However, as you find code rot, it becomes technical debt when you do nothing about it.
Technical debt is something that needs to be paid back. Relating this to real life; imagine yourself going so far into debt that you cannot imagine yourself ever getting out from under the load you carry. You will either be stuck with extreme payments the rest of your life or you’ll claim bankruptcy. In a software project, the equivalent of bankruptcy is a complete rewrite. You have invested time, sweat, tears, and likely a decent amount of money into whatever you’re working on. You don’t want to lose what you already have, but sometimes it’s inevitable.
The point I’m trying to make here is that you need to be willing to pay back your technical debt such that when you incur more debt, you aren’t overwhelmed by it. Paying that back can be related back to time and effort. Hell, even if you spend 5-10% of your time just refactoring your code you’ll have been paying back some of the incurred debt.
I’m probably beating a dead horse here so I’ll move on.
Problems
There are always issues right? “Sure, what you’re saying makes sense, but we don’t have the time or the budget to go through our code and fix it.” I know. I’ve heard and said this before. But, think about it like this.
I have a car. I drive it places and it serves me well. I put gas in and all is right in the world. Then one day I feel some light vibrations when I press the brake. I don’t think much of it because the car still _works_. I don’t have the time to get it taken in to the shop. About a week or two later I feel a stronger vibration and every so often some squeaking coming from the car. Again, no time- I’m a busy man! Another couple weeks pass and now the squeaking is a screeching and it’s loud. It pierces my ears. I know that sound and realize that it means I likely need to fix more of the car. Now things are getting pricey and I don’t have the money to fix it all at this point.
You see what’s happening? I put it off so long that it became prohibitively expensive to surgically remove the rot. Instead now it is going to cost me a fair amount of cash, time, and effort to actually get these fixed. And, who knows, if I continue on the current path I might end up in a wreck.
Still when you are under constraints that you have very little control over there doesn’t seem to be much that you can do. Most of the time you are forced into situations where you either piss off the PM’s and management or just continue to let the code grow it’s warts. Ideally, you’ll prove to those that make time and budget based decisions that your changes will be worth it. By worth it I don’t mean “the code will be better”, I mean “in the long run, we’ll say 30% and gain 5% in revenue”.
Solutions
One of the serious mistakes that developers make with manager types is that they think they are relating to them with terminology and analogies. Typically it requires actual impact to prove that you are right. In order to get impact values you have to gather some metrics. Hopefully some of what follows can help there.
If you already have tests in place for the code you’ve written you can do a couple of things. Lie to the people that are asking you what you’re working on. *cough* working on that scalable synergistic thing-a-ma-bob that will grow our profits exponentially *cough*. Or, you can tell them the truth. Regardless of what you do, you can have some faith in the fact that your system should operate in the way you expect it to because you have tests in place for just this reason. At some point this code was going to be changed and you wanted to make sure that you did some CYA when it did change.
If you don’t have tests you can again, lie to the people. Or, you can explain to them why it is important and some tactical approaches to solving the problems. Some fuel for the fire:
- Measure and Frequently Repay Technical Debt – Intel Software Network Blogs
- Start Paying Your Technical Debt – The Mikado Method – Thoughts of a Goldfish
- The IT Manager’s Dilemma with Software Debt – Chris Sterling’s Blog
Think about things like this. You want to get rid of this technical debt. It’s very likely that the project manager does too. But, explaining these things to the people who are interested in release dates can be challenging. Try explaining that customers are more happy when their software works. The more you can ensure that the better. Often it’ll require charts and figures with bug numbers over time. Be sure to show where you’re making improvements too. For instance, “as you can see we refactored the code on 3/12 and the number of bugs being reported decreased by n%”. By doing this, you are effectively showing ROI and how your changes affect the bottom line. For people concerned mostly about money that is important.
And, if all else fails, show them this video!
Sometimes it’s better to just ask for forgiveness in doing these things. Even if it means temporary irritation, the benefits outweigh the downside.
Beaker – Yet Another Web Server
In the pursuit of learning a new language I picked up Programming in Scala. I had fumbled around the Scala examples and read some of their documents like Scala by Example. I did replicate one of their examples by implementing a Quick Sort. I don’t feel it’s sufficient to know the language by taking an example they have provided and merely reimplement it, so I’ve decided to try my hand at a web server from scratch.
So far it’s been quite fun. At first I figured, “All I have to do is spawn some threads and write to the output stream”. Then, my curiosity got the best of me, per the usual, and I thought, what about if I just take the bytes from the files and write those instead of just reading lines from HTML. Then I can support any content types. Obviously just using file extensions wasn’t going to be enough for me so I figured I’d integrate mime-util as I’ve had some good experience with that in Axiom Stack. And, I’ve been working on a implementing Handlers in the way that allow different handlers to manage different paths. So, now what do I have?
I have a functional web server that provides 200, 404, and 500 level response codes. Ultimately I have an experiment that has gone pretty well. To get a feel for whether I was actually headed in the right direction with web servers and Scala I decided to take a peak at the Lift source. While I’m obviously not there yet, it seemed as though I had the right idea in terms of how they thought it should work which is comforting to me (something to keep in mind is that I do have some experience with web servers since I’m an active committer to Axiom Stack).
So. While it’s great to have a static content web server, that’s really just the tip of the tip of the tip of the…stack overflow…iceberg. I’d like to bring this server into a better set of compliance, make it faster, and truly test the “scalability” of the server. I know that it handles me slamming on F5 pretty well but that is the only kind of testing I’ve really done with it so far. Additionally, I’d like to figure out what it would take to get the distributed requests and such working well within it. I might try to bring in Terracotta for that portion of it. There are a lot of things I’d like to do with Beaker but I just don’t know whether it is worth my time to continue to develop the server. We’ll all find out together I guess. ;D
Also, while all this is great, the biggest reason for doing this is to really get a good personal comparison of Scala and Erlang. While the threading model for Scala is stolen from Erlang, the language similarities essentially stop there. I may try my hand at replicating this server in Erlang at some point.
If you’re interested and haven’t yet fallen asleep you can grab the source for Beaker on Github. Fork it, hack it, let me know what a noob you think I am. I can handle it.
Enjoy.
*Update 1* I suck at art. No making fun of the beaker – it’s hawt (on second though, maybe I should lace it with bacon…).
Foreplay and Programming Languages
Programmers will tell you that you should learn a new programming language every year. I’m not going to tell you otherwise. In fact I agree with this. Here’s why, I believe that a language is just a tool to get your job done. More over, Python is not how you program, Python is a means by which you write programs.
When I got out of college I didn’t really grok this. I knew there were many different programming languages, but Java was how I programmed. When I thought of a problem, I saw the solution in Java. It’s almost like communicative languages. If your first language is English and you are taking French, you translate the French to English before really understanding the French.
This is what I would do with other languages and Java. It’s not the best method to learning the language I’ve found. In fact, every language is different so trying to transpose one language to the other tends to push the write Fortran in any language approach (no scientific study, just my experience). So, if I take a Java programmer and give them a project and tell them that the language being used is Javascript, they will write Java and the code will likely get written, but poorly and need to be completely refactored.
Going For The Goods
The way I would approach new languages was to take some existing problem and attempt to solve it in the new language. While this is one of the steps you’ll need to take to really know the language, shouldn’t you get familiar with it first? Think about your education for a moment. When you were in school taking Spanish, did the teacher start you off by saying english(”I”) and then spanish(”I”) or did she start you off by saying spanish(”Take out your translated version of Tale of Two Cities in Spanish and read”)? I’m going to assume the first scenario as this is what my experience was.
For me, diving into an existing problem and trying to tackle it with a language I’ve had no experience with just ends messy. It’s almost like when you…ok I’m going to try not to make the Rails mistake. But, really, everything we as humans do when learning is experience based. We crawl, then learn to stand, then walk, then run…and so on. So why not start out with the same approach and build momentum for your language? I’m not saying that you need to spend hours relearning what a for loop is. I am saying that you should spend some time getting familiar with the syntax and differences of one language before trying to “go for the goods”.
The Foreplay
Because I noticed that I was trying to run before walking with languages, I started taking a new approach. Instead of transposing language constructs, I instead started to rewrite common/well known data structures or algorithms in the language I was learning. There are a couple reasons to do this. First, I constantly feel out of practice when it comes to algorithms/data structure design. I don’t claim to be a math wiz so re-reading and implementing them is great practice. Additionally and perhaps more importantly is that the algorithms/data structures I’m implementing aren’t new ideas. These are tried and tested concepts that span languages. Thus, I will have comparable results.
Take this for instance. If you write a merge sort in one language, you’ll most certainly be able to write it in another language, it will just be written differently using the appropriate syntax and language designs. Since you already know how a merge sort jiggles when you poke it, you can compare your version to the typical. Plus, you can calculate the speeds of doing said algorithm in the new language. This will provide you with some benchmarking for better decision making about the language.
Another Analogy
If you need another analogy, I used to play instruments. Typically, outside of August Rush, people who haven’t touched a musical instrument must go through some period of time to learn the instrument. You need to learn how to caress it so that it will make music rather than just a mixture of noise. When you start out you don’t learn Für Elise you start with notes and scales. The notes and scales apply across instruments. You have to learn them for the instrument you’re using, but you understand the concepts.
Conclusion
Warming up to the language seems to work best for me as I can compartmentalize the diffs of the languages preserving my memory for other interesting things. Then I can pull out what I need from each language. Think of it like this, the algorithms and data structures are your minds libraries and the syntaxes of the languages are the methods written on top. The algorithms aren’t likely to change, but you’re trying to evolve your syntaxes.
To summarize: I have a specific methodology for learning languages that I’ve found works really well for me. Although I’m sure many of you will have your own method for learning them, maybe this will help someone trying to get more familiar with differing languages and maybe give you a different approach.
Disclaimer
Always leave room to learn more about algorithms. Who knows, you might be the one to figure out how to make quick sorts obsolete. So, don’t write them off, but know that they are tried and tested and because of that, produce predictable and comparable results. That is my reasoning for recommending them.
Implementing Java Interfaces from Javascript with Rhino
Rhino is a fairly awesome tool. You get the full capabilities of writing Javascript, plus the availability of the Java ecosystem. However, there is another awesome feature that I didn’t know about until a few months ago when I read Todd Ditchendorf’s post about thread synchronization in JS. You can actually implement Java interfaces from your Javascript. For example, let’s say you want to override the toString method on a String object.
I used his technique when I was writing a module to allow HTTP calls from the JS side of the house, on the server side. Below is the code that allows for asynchronous requests to be made. Very simple and very much like Todd’s examples, but that is all it needs to do and it works beautifully.
...
ajax: function(url, data, callback, type) {
var r = new Runnable() {
run: function() {
type = type || 'get';
callback(axiom.HTTP[type](url, data));
}
};
new Thread(r).start();
}
...
In essence it creates a new Runnable object, defines the run method, and then passes that Runnable object to a new Thread.
While this code demonstrates the functionality with the Runnable object, you have the capability to do this with any other interface right from within your Javascript.
It’s really handy and took me a while to find so I thought I’d post something about it. Hope it helps.
Git: Tying a Remote Branch to an Existing Local Branch
As I was cleaning up my code directory and forking projects to have personal dev branches up on Github, I ran into a problem. I needed to tie a remote branch that I had created to an already existing branch.
So, I had branch already in my list of local branches. I did one of these:
git push ncb000gt master:refs/head/branch
This made the remote branch and then a:
git fetch ncb000gt
Pulled it into my view. Now I have two branches, one local, and one remote. I had changes and commits in the local one that I didn’t want to lose.
I could have tried to solve the issue following the .config method, but instead I decided to do it a different way. Basically by moving/renaming the existing local branch:
git branch -M branch branch_temp
Then, create you local branch that is tracking the remote branch and check it out:
git branch --track branch ncb000gt/branch
git checkout branch
Then all you have to do to maintain the existing commits is merge the code in.
git merge branch_temp
That should be about it.






