Fixing Cars and Fixing Bugs

Mechanic repairing a car's engine
Photo by cottonbro studio: https://www.pexels.com/photo/a-person-fixing-a-machine-7564871/

Lately I’ve caught myself watching YouTube videos about car repairs. I don’t do car repairs. The last time I changed my oil or rotated my tires was decades ago.

What gives?

I spend my work day supporting a legacy desktop Java application, tracking down subtle bugs hidden in impermeable god objects. Unfortunately, the owner of this software would be most displeased if I were to share the problems and solutions online.

Actually, most businesses have the same attitude. They want to keep their special sauce secret. Consequently, debugging videos are hard to find. I have found some, but the editing on these car repair videos makes them more like watching a mystery show as it unfolds.

One interesting thing I’ve discovered is that the lessoned learned in car repair are often applicable to my world of debugging and software development.

The first lesson is probably the most obvious: a systematic approach to finding the problem will save a lot of time!

When they get a car that’s making that ticking sound, they first check to see where it’s coming from: on top of the engine, underneath, in front…

Then they lean on experience. When have I seen this in the past, and what were the causes? Which would be the quickest and easiest one to check? Let’s try that first.

If the quick and easy checks don’t turn anything up, let’s talk it out with someone before I spend a lot of time on it.  Bring in someone else and see if they have any ideas.

If none of the quick checks work, it’s time to get down and dirty. Digging into the ugly guts of the thing and taking things apart.

This is how I do my work as well. I do my best to reproduce the problem and track down where it’s coming from. I’ll try a few quick things that have worked for me in the past. If those don’t work, I’ll talk to someone else about it. If those ideas don’t get me there, that’s when I start digging through logs and debuggers and profilers and all of the time-consuming work.

Another thing that’s fun: finding the source of the problem. The reactions are very similar, too:

  • “Oh, I can’t believe that! That little thing caused all of this trouble!”
  • “What a stupid design!”
  • “How was this working before?”
  • “Just a little maintenance would have saved all of this hassle!”

Maybe it would be fun to start working on my car again…

Software Tools: Counting Lines

Last time we counted characters. The next logical thing is to count lines. Let’s look at the code to do that:

# linecount - count lines in standard input
character getc
character c
integer nl
while (getc(c) != EOF)
if ( c == NEWLINE)
nl = nl + 1
call putdec(nl, 1)
call putc(NEWLINE)
stop
end

We have a NEWLINE constant that represents a standard character for the system running the program. Using that keeps it portable.

We also introduce the idea of using “==” for a comparison to differentiate the operator from the single “=” which is used for assignment. This makes it easier to catch ourselves accidentally doing an assignment when we expected to do a comparison. In Java it’s not even allowed, so the compiler catches it for us!

We continue to use getc() and putc() as fundamental building blocks that handle system input and output. This allows us to use any input or output without worrying about the implementation. We just check one character at a time. Such a powerful design!

How do we make sure it’s working properly? Our first thought is to test for boundary conditions: a file with no lines, and a file with one line. If these are handled properly, the general case should be handled automatically.

So for an empty file, it won’t make it into the while statement, and since the nl counter is initialized to zero, it returns the correct answer.

For a file with one line, it will find that one line once. The counter will be properly incremented, and it will return the correct answer.

Is it overkill to test a tiny program like this? No, it’s called prudence. Good habits. If you get in the habit of thinking about boundary conditions when putting together a program, you’ll write more robust programs.

This book (and this series) is all about developing the proper habits to write great code, so pay attention to the little things. They matter.

Question for the reader: what if the file doesn’t end with a NEWLINE? How should that be treated?

Software Tools: Counting Characters

The ability to count characters (or words or lines) is incredibly useful – especially if you are working in a text-based scripting environment (like Linux). Having a simple tool to do that would be especially helpful. What would a character-counting tool look like?

# charcount - count characters in standard input
  character getc
  character c
  integer nc
	
  nc = 0
  while (getc(c) != EOF)
    nc = nc + 1
  call putdec(nc, 1)
  call putc(NEWLINE)
  stop
end

This is Ratfor again. Why don’t we use a real language? (Ahem! Ratfor is a REAL language!) Because by using a simple language like this, we can show how these functions work in a very simple and understandable way. From there, it’s easy enough to convert it to Java or Python or whatever language you want.

So here are some noteworthy points about the code above:

First, we introduce the character data type. What’s the difference between a character and an integer? For the purposes of the book, it’s just a documentation thing. A character has a specific use. It is used to read and write character text data. Integers are used to count things. So just like the NEWLINE is a special name for a specific, system-dependent value, a character is a specific name for a value with a specific purpose.

Next, we call the putdec() function. That is a special function (which we’ll define later) that takes a numeric value as the first parameter, formats it in a character string the size of the second parameter, and outputs it to the “standard output”. It does this by using the putc() function (as we’ll see later). So we’re already taking advantage of the software tools we’ve built already.

Finally we notice that there is a separate call to putc() to write out the NEWLINE character. That seems like a waste. Why would we do that? If we want to write multiple numbers on the same line, we can’t have putdec() inserting newlines. So we keep the function simple and that keeps it flexible. And it all hangs together in such a simple, clever way!

It’s like it was designed to be that way!

Software Tools: File Copying

The book begins with a simple function, getc() that reads a character and then returns that character as its return code. It doesn’t matter where it reads the character from. Consider it an “input stream”.

Next it introduces another simple function, putc() that takes a character as a parameter and outputs it. Again, the output destination is unimportant. Consider it an “output stream.”

So we have two trivial functions that perform trivial work one character at a time. What good is that? Well, if we put them together into a single function, we can take input from anywhere and output it anywhere. You may recognize this function as cat on a Linux system.

The only thing I have to worry about in this program is how to detect the end of the file. To solve that problem we choose an end-of-file character that we will call EOF. The book introduces a programming language, Ratfor, a Fortran pre-processor, that resembles C. Here is our function in Ratfor:

# copy - copy input characters to output

integer getc
integer c

while (getc(c) != EOF)
    putc(c)
stop
end

It uses integer values rather than chars to keep data types simple for the example code. It also uses indentation rather than curly braces or BEGIN/END statements to mark off code statements. And EOF is a symbolic constant to keep the code readable rather than using a magic number.

All of these are helpful practices for making code more readable. Martin Fowler’s quote, “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” came decades later!

Also consider that this kind of function is the basic building block of the Unix (and Linux and BSD and…) operating system. Take some input (any input) and put it on the output (any output). With it I can read a file from a disk and print it to the screen or to a printer. This is why any file or device on Linux is defined as file. It keeps the tools consistent and simple.

One tiny little program. It does one thing and does it well. It is an ideal software tool. With a collection of similarly designed software tools, we’ll be able to accomplish powerful work.

What are some other simple tools that you use?

Have a Farmer’s Mindset

“The true meaning of life is to plant trees, under whose shade you do not expect to sit.” – Nelson Henderson

Farmer working in a field
Photo by Jed Owen on Unsplash

One of the great success factors is to adopt the mindset of a farmer. This is the idea that some things cannot be rushed. It takes time to grow a crop. We’ve all heard the quote, “You can’t have a baby in one month by getting nine women pregnant.” Trying to force things to happen more quickly than they should will just leave you frustrated with poor quality results.

If you try to cram all of your learning before the final, you may past the test, but you won’t have learned anything that you will be able to use long term. To learn something well you need to put in consistent effort over time. Consistency beats intensity every time.

This farmer’s mindset is important and to make the consistent effort more effective, it’s critical to be strategic about it. The farmer plants at the proper time of year. The farmer plows up the ground to soften it up before planting. The farmer harvests when the fruit is at the proper ripeness.

In the same way, you need to be strategic about how you learn a new skill. And about how you practice it. There is a time of day when you are most effective. Often it is about two hours after you wake up. There is an online test you can take here to help you determine when your most effective time is. Use that information to be strategic about how you learn. You’ll learn faster and retain more if you do it at your most effective time.

Also plan out the things you want to learn. It’s fine to learn for the sake of learning, but if you have a specific goal in mind, you’ll want to learn the most important things first so that you can quickly get started. Then fill in the details as needed.

Finally, choose the proper learning approach. Will taking an online course be the best use of your time, or would it be better to get a book on the topic so you can pick and choose the topics and order you want to learn? Should you poke around on YouTube looking for a useful tutorial, or would it be better to find a tutor or mentor to streamline your approach?

In the same way that a farmer gets a jump on spring planting to get the most out of his crops, you’ll want to maximize the effectiveness of your learning. What do you want to learn, and how to you plan to do it?

If you’re considering a mentor, I can help with that. As we are halfway through the year, let’s take stock and see how to finish strong. The last two weeks of June I will open my calendar for strategy sessions. If you want to spend an hour with me strategizing your goals, you can schedule some time here.

Keep Your Big Goals Secret

Photo by Kristina Flour on Unsplash

“The goal is not to be perfect by the end. The goal is to be better today.” – Simon Sinek

You’ve probably heard that if you want to achieve an important goal you should announce it to the world so that they can hold you to it. This makes sense logically: if I tell others I’m going to run the marathon, and then I don’t do it, I’ll be embarrassed and I’ll lose credibility. That will ensure that I do it!

But in practice, announcing your big goal actually undermines your chances of achieving that goal. Why would that be? By telling others that you’re going to do something big, you feel like you’ve already taken that first step. You can visualize it happening and you can see yourself having already achieved it. Your friends will congratulate you on taking this important step. That all feels great!

Then the hard work starts and you realize it’s not going to be that much fun. You’ve already gotten a good feeling by announcing it. And the achievement is a long way off. And that’s probably not enough to carry you through to the end.

But if you keep your big goal to yourself, and just start doing the work, you haven’t gotten any validation yet. No good feelings. No dopamine. It’s all just heads-down and taking that next important step. Once you’re a few days or weeks down the road, you can look back and see your progress. THEN that great feeling of accomplishment is truly earned! And it pushes you to continue!

I like how Derek Sivers explains it in this TED video. It’s short and clear.

What big goal are you pursuing? (DON’T TELL ME!) 🤪 Have you achieved a goal that you kept secret? What was the result?

Develop Grit

Photo by Lucas Myers on Unsplash

“What is grit? Grit is refusing to give up. It’s persistence. It’s making your own luck.” – Peter H. Diamandis

Grit is the ability to overcome difficulties in pursuit of an important long term goal. The more grit you have, the more successful you will ultimately be in your life. Grit helps you to weather the storms and keep moving forward.

We admire people who have True Grit. Michael Jordan was cut from his high school basketball team. But he refused to give up, and eventually became one of the greatest athletes of all time. Thomas Edison was sent home from school for being a slow learner. He went on to become one of the most successful inventors in American history. Helen Keller lost her sight and hearing early in her life, but with the help of Anne Sullivan, she became the first deaf-blind person to earn a bachelor’s degree. She became an influential author, activist, and educator.

What if we don’t have grit? Or what if we do and want to develop it even more? According to psychologists, there are a few habits you can develop, some reframing, and refocusing you can do to develop your “grit muscle.”

First: Clarify your purpose. What kind of person do you want to be? What do you want to achieve? What do you want to be remembered for at the end of your life? Think seriously about this, write it down and refer to it often.

Focus on growth rather than results. Make some small progress every day, and celebrate that. Don’t keep focusing on what you haven’t achieved yet. Keep your eye on the prize and keep moving forward. That’s the sign of a true winner!

Be consistent. Consistency beats intensity. Have a farmer’s mindset. A little bit every day. You can’t grow a field in a week. Consistency is your greatest ally on your road to success.

Face your demons. Don’t give up when you run into challenges. Turn it into a game and figure out how to win. Usually those monsters we fear so much turn out to be tiny lizards.

Develop resilience. We all get knocked down from time to time. Have a plan in place to get back up when it happens to you. Have supportive friends, or keep a journal, or go work out. Do something. Keep moving. The quickest way to overcome a setback is to get back up and start doing something.

Discipline beats motivation. Don’t wait for the muse to inspire you. Do the work. Now. Get started. If you have writers block. Fill a page with a nonstop stream of thoughts. The motion is what matters. Are you noticing a pattern here?

Find a support community. Often times your friends will hold you back. Find friends who will call you forward. If you want to get in shape, go to the gym. If you want to improve your technical chops, join, or form, a group of like-minded developers and help each other grow.

Keep score. Keep track of measurable improvements. How much time did you spend practicing this week? How many pages have you read? How many programs have you written? The scoreboard doesn’t lie. And if you’re honest with yourself in keeping track, you’ll notice when things are not working and be able to make the necessary changes.

For more information, I recommend Angela Duckworth’s book Grit or her TED Talk.

What do you do to develop grit?

Why “Software Tools” Still Matters: Lessons for Today’s Developers 

There are a number of excellent computer science books that were written decades ago, and were essential to any programmer’s library, but newer developers may not even know that they exist. Some of these books contain timeless lessons that continue to shape everything we do today. One such book is Software Tools by Brian Kernighan and P.J. Plauger—published in 1976, yet still incredibly relevant for modern software development. 

This book isn’t just an introduction to programming; it’s a guide to thinking like a programmer. It teaches the value of small, composable functions, discusses the importance of structured programming, and building reusable tools—all principles that remain foundational, whether you’re writing shell scripts, working with cloud infrastructure, or crafting clean APIs. 

Why should you care? If you develop software today, you’re standing on the shoulders of giants—people who helped establish the best practices that still define our field. The authors of this book also wrote other essential references (including much of the Unix operating system) and wrote in a clear and approachable way. Software Tools succinctly shows how simple, well-written code leads to scalable and maintainable systems. Whether you’re diving into Unix internals, building microservices, or scripting automation, the principles in this book are everywhere. 

We will take a deep dive into this book and discover the essential and timeless wisdom hidden there, and see how we can apply it in our work today. We’ll see how some of these tools still exist in modern Linux, and how the ideas discussed influenced programming languages, like C and even more modern languages, like Python and Rust.

Some key ideas we’ll explore: 

– The power of small tools: Why the Unix philosophy emphasizes writing simple, single-purpose programs that easily connect with one another.

– Understanding character input and output: Concepts that remain crucial for handling file streams, parsing data, and even writing efficient CLI tools. 

– Code readability and structure: How naming conventions, proper language idioms, and thoughtful code structure improve readability and maintainability. 

– Thinking about edge cases: Why seemingly simple tasks can often hide deeper complexities in software design. 

As we work through this book, you’ll see that what seemed like niche technical wisdom from the ‘70s is actually a timeless guide to writing clean, effective software. We’ll start next week!

How to Get Unstuck

Photo by Jeremy Bishop: https://www.pexels.com/photo/person-on-blue-hammock-2710128/

“The way to get unstuck is to start down the wrong path, right now.” – Seth Godin

We all get to that point. We’re cruising along, firing on all cylinders, making great progress. Then something happens and we can’t seem to get back on track. Or we reach a level of achievement, but just can’t get to that next level. We’re stuck at a plateau. Now what.

The danger is that we either just stay there and resign ourselves to the fact that we’re about as good as we’re going to get, or, worse, we give up and just stop doing anything. But what is the alternative? How do we start moving forward again?

The most important thing is to start moving. Do something, even if it’s wrong! Motion creates energy. You can’t drive a parked car. You have to be doing something in order to make a change. Just do something different.

Make a change. Any change. Try it backwards. Go for a walk. If you’re stuck on an algorithm, try implementing it in a different language. If you can’t find a bug, change some of the parameters. Or comment out a piece of code in the middle. Just change something randomly that forces you into a different perspective. Go from dark mode to light mode. Write it in Visual Basic. Call functions out of order.

I can’t count how many times a good night’s sleep got me unstuck. This is an idea explored brilliantly by Rich Hickey who calls it “Hammock Driven Development.” Hammock Driven Development – Rich Hickey

The important thing is first to notice that you are stuck. Then do something to step out of it. Take a walk, meditate, take a nap, eat an apple. Just get out of the stuck mindset. Then change your perspective in some way. It doesn’t have to be big, but it has to be different.  If that doesn’t work, shelve it for a while and do something else. When you come back you will likely come up with some great idea you hadn’t considered before.

What do you do to get unstuck?

Give Yourself Eight Weeks to Learn a New Skill

Photo by Eric Rothermel on Unsplash

“The only skill that will be important in the 21st century is the skill of learning new skills. Everything else will become obsolete over time.” – Peter Drucker

Earlier we discussed how it takes deliberate practice to learn a new skill.

But what does it take to just be competent? What if I just need to know enough of a technology to solve an immediate problem? I don’t need to master it, and I don’t have time to master it anyway.

Many of the world’s leading schools divide up their programs into time spans of 8-12 weeks. US military boot camp lasts between 8 and 13 weeks. When preparing for a mission astronauts spend a few months to a year in training. The Bolshoi Ballet has 3-week and 6-week intensive training sessions. Why is this?

First, it takes time for your brain to establish the neural pathways that it needs so that it can recall the proper actions and processes that you are learning. This is also why Five Minutes a Day Beats an Hour a Week.

Next, complex skills take some dedication and grit to really understand, much less master. You need to have patience and grace with yourself. Allow yourself to work through the periods of ignorance and failure so that you can come out the other side really knowing how to do it. As my father used to tell me, “If it was easy, everybody would do it!“

So when you struggle to learn a new language or framework or technique, that’s OK. Remember, it’s supposed to be hard! The important thing is to accept this truth, allow yourself the freedom to do things wrong – until you can do them right!

What are you struggling to learn today?