Posts

When Technical Debt Costs You MORE!

We've all heard of the metaphor of technical debt by now. Maintaining poorly written software costs more in the long term, even if it saves in the short term. Thinking of this as a form of debt helps explain this in terms business-oriented stakeholders can understand.

Metaphors are valuable because they can meaningfully convey a concept through a different context. They bridge the gap between two different ways of thinking. Sometimes we can take the metaphors a little too far, and they become disconnected from what they are actually trying to represent. This has happened with the metaphor of technical debt. Other times, we can explore the metaphor to find deeper relationships between the real concepts and the metaphorical ones.

Financial debt has the concept of interest in it. Interest is an extra charge on top of the original value lent. It covers risk and provides incentive to the lender. It is calculated as a percentage on top of the principle amount of the loan. So a loan of $…

Untangling Nested Code

Image
There is code out there that is ugly. I mean really ugly. I know, can you believe it? But it's true. One such example of really ugly code is code that has lots of deeply nested calls. The tests are trying to test a dozen different methods in every case. The methods look so simple with just a few lines and a few calls. And then those methods called have a few lines and a few calls. And then again, a dozen or more different calls deep.

We want to use private helper methods to make our code clearer and cleaner. Calling methods is also largely what programming is about. But sometimes we overdo it. Deep call hierarchies are difficult to follow and they can mask what the code is really doing. Each call means that we have to look all over a class to see what actually happens. This makes debugging hard. This makes testing even harder.

Say we have the following code:

class DataLoader { void loadNationalData(Nation nation, int year, DataReader reader) { for (State state : natio…

Break Down Code to Make It DRYer

Image
We are always looking to make our code DRYer. Code that is not repeated is easier to maintain. We can make a change in just one place rather than hunting for different incarnations in many different places. Making code DRYer is not always easy, and sometimes how to remove the duplication is not apparent.

Let's say we have the following two functions:

public List<Stats> processLines(File file) { List<Stats> stats = new ArrayList<>(); for (String line : lines(file)) { Data data = extractDataFrom(line); Stats dataStats = calculateStatsFor(data); stats.add(dataStats); } return stats; } public List<Stats> processLines(List<File> files) { List<Stats> stats = new ArrayList<>(); int fileNumber = 0; for (File file : files) { for (String line : lines(file)) { Data data = extractDataFrom(line, fileNumber); Stats dataStats = calculateStatsFor(data); st…

Every Case Is Special

Special cases are everywhere. This one little thing has to work this other way. Soon, there is an if/else chain twenty conditions long. Worse, that if/else chain is embedded in another chain of twelve conditions, all in one happy method. The next person making a kind of change has to tack on another condition and hope nothing blows up.

We know it's bad when we see a bird's nest like that. How can we deal with it? Why should we? The problem with code no one understands is that no one understands it. We will have a huge problem the day it stops working. We assume that, if it works now, it will work forever. That is a faulty assumption. The world changes around us. The solid rock beneath that code can erode away. And our hair will be on fire when that day comes.

Special cases are special. Normal cases are also special. Every case is special in some way. There are some classic special cases common to many code bases. There are quirky special cases unique to your own code. We need …

Making Wrong Code Be Wrong

I was recently perusing when I came across a link to a Joel Spolsky blog post. In it, he describes how a form of Hungarian notation can be used to make wrong code look wrong. In the process, he describes the interesting history of how Hungarian notation came to be, and how the common use of it today was not the way it was originally intended.

He describes how Hungarian notation was created to convey application-level information about a variable. It could be used to distinguish between two different types of dimensions that might both be typed as ints. He termed this Apps Hungarian. While the compiler could not tell them apart, the human eye would be able to with a cursory glance. Later, the notation was instead conflated with the type that the compiler saw. An int iWidth carried redundant information that could actually get in the way if the type ever needed to change. He termed this Systems Hungarian.

He gives several examples in the post. Notably, he describes how Apps Hungarian ca…

Bug Hunts: Better Together

Bugs are demoralizing. Bugs are draining. Bugs are frustrating. Bugs suck.

Nobody really wants to have bugs, and nobody really wants to be the one who has to track them down. Bugs are a reality of software development. They happen in even the most meticulously managed software. They always seem to come from the obscure or not-understood part of the code. They give error messages that make no sense and are completely unhelpful. I'm looking at you, NullPointerException and equivalents.

Getting assigned bug tickets is the software development equivalent to latrine duty. It is a necessary task that needs done, but no one wants to do it. A developer could spend hours or even days banging their head on their desk just trying to figure out what could possibly be causing the error. All the while, they are not creating new business value.

For some team members, finding where the bug is coming from is easiest. For others, discovering what is causing the software to get into a bad state in t…

Change the Wrong Way

Many factors can force software to change, such as new business requirements or new technology requirements. As software developers, we have to handle the constant stream of new demands in a maintainable way. But sometimes we don't have the time, or we don't have the resources. We just need to make it work because they need it like yesterday! When we allow ourselves to get caught up in the frenzy, we let quality slip. Other times, we just didn't know. Or we had bad practices that we thought were fine. Quality slips all the same. Can we see these issues just by looking at the code?

public List getPersons(String name, String firstName, int contacts, boolean sort, boolean dir) { ResultSet rs; List persons = new ArrayList(); if (name != null) { rs = db.query("SELECT * FROM People"); addAllPersons(rs, persons); if (sort) Collections.sort(persons); if (dir) return persons; } else { rs = db.query("SELECT * FROM People WHERE last…