Saturday, April 5, 2014

Lessons learned from reading the Pragmatic Programmer book

I started reading the Pragmatic Programmer book a few months ago. I kept notes, highlighted passages, and most importantly started integrating what I learned into my daily work as a programmer. Here are some of the things I learned...

Broken Windows theory

I already wrote a post about this here, Makguidetosoft: "broken windows" theory. In short, don't let broken, poorly designed code stay that way too long, or it will invite worse and worse code until it is unmaintainable.

Make better estimates

Everyone knows that making conservative estimates is smart, but here's a few things i learned about giving better estimates:

1. Use larger units of time. Instead of "days" use "months", instead of "hours" use "days". For example, instead of saying "this project will take 120 days", say "this project will take 6 months". It's all about perception. Being a few weeks off when you said 6 months is much better than being a few weeks off when you've said 120 days.

2. Update estimates as you complete things, or as you gain more experience with something. For instance, I was asked to estimate how long it take to port windows from one language to another. Since i've never ported windows from that specific language to that other specific language I gave a conservative estimate of "2 days per window". Well, there's a good chance i'm going to get really good at doing that task as I gain experience with it. So the first window might take 2 days, while the last one takes a few hours.  The lesson here is to update the estimate to the project stakeholders as you gain better insight into how long it will actually take. This may be vital for them to schedule other tasks for you, or to relay that info to other stakeholders.


Become effective at using a shell scripting language

I scoffed at the recommendation to learn a shell scripting language at first, because I didn't think Windows had an effective one. Then I started learning about Windows Powershell, reading a few books on it, and incorporating it into my daily work. It has saved me a bunch of time. The best part is there's an IDE so that you can use it like a command line AND write scripts for it in the same spot. This has increased my efficiency so much, because I try to write scripts for anything and everything that can be automated, thus saving me lots of time and making processes less error prone.

Get into the right mindset for debugging

1. Debugging is problem solving. Treat it as such, and not trying to blame others.

2. Don't panic, every bug can be solved with enough time and good debugging techniques

3. Explain the problem out loud to someone else. Sometimes your mind can unscramble your thinking when you verbalize it.

4. Most likely the third party software is not broken, assume that the bugs are in YOUR code.

5. Don't assume it, prove it! "The bug CAN'T happen in my super awesome function" - ok, so write some unit tests throwing all sorts of stuff at the function. Prove that it can't happen.

General debugging strategy

1. Be able to recreate a bug. Get all info, ask for clarification, and get log files. If you can't recreate the bug, don't even try to debug it.

2. Use a debugger / tracing to see variable values in the function that's having the problem.

3. Ask myself, where is this variable set? Where is this function called?

4. Backtrack to the root of the problem, don't just assume the bug is the root cause and not a just symptom.

Code generation

1. Write code that writes code. There are two types, active and throw-away. 
Active = T4 templating in Visual Studio.
Throw away = i've actually done this, use an excel spreadsheet to write the CRUD functions for the database

Templating goes well with design patterns, and can save you tons of time.

2. Design by Contract. Pre conditions, post conditions, and invariants. Even using comments that explain all of these is good practice. 

Defensive Programming

1. Crash Early. Don't catch and suppress Exceptions. That can lead to some painful troubleshooting if this code makes it to production. It's better to crash as early as possible, so that bugs can be tracked to the spot where they're happening, instead of 10 function calls later.

2. Use assert statements. in C# this is Debug.Assert(condition, message). This are extremely valuable during testing, because they help you quickly track down your mistakes. These are good to use with Design by Contract. In other words, if you have a function like private bool DoStuff(Thing thing), and your precondition is that thing must not be null, then put an assert in there to verify that thing is not null.

Refactoring

Refactoring is the systematic attempt to remove duplicate code and improve poorly design systems. I'm reading a book about this, see references below.

I've always done refactoring in my projects, but now with reading this book I'm learning better techniques to make sure i'm refactoring correctly

Testing

1. Think about how you're going to test code while you're writing it, in other words Design by Test

2. Write unit tests WHILE you're writing code. 

3. Make sure your unit tests are actually working. This can be done by purposely introducing bugs into the code that should cause the unit test to report failure.

4. Testing is more culture than technical. Be the catalyst for the testing culture.This goes right along with "don't assume it, prove it". Unit tests are there to prove that the code works. It's also wrong to say "it's a little change, let's just release it, i'm sure it doesn't break anything". That's the problem. The culture should be to test test test even if there are tiny changes. Prove that the software works and it'll save you headaches when it's released into the wild.

5. If a bug is reported, write unit tests to specifically test that bug. There is nothing worse than a bug that randomly appears after it's been fixed. Don't just assume this is going to be tested by others, write unit tests to PROVE that the bug is fixed.

Documentation

I've always left pretty good comments, never none and never too many. The purpose of comments in the code is to explain WHY something is being done. Comments are for other coders to read, so it's pretty safe to assume they know how to read code. Therefore, don't waste time with DUH comments. However, there's a few things i learned:

1. Build documentation into the coding process. In .NET (and i'm sure other IDEs), you can put in XML comments into the code, like this 
///<summary>This code does stuff </summary>
Then when you go to use the code the Intellisense picks up that XML comment. The XML comments can also be output during the build into an XML document by clicking a checkbox in the build options. There are tools that can parse this document into a user-friendly format. Instead of writing documents explaining what the code does, or what the API is, it's much more efficient to use this built in documentation generator.

2. Don't repeat yourself, even in documentation. Use the source control for documenting code changes.
Right now I put file header comments explaining the change I made, along with my name and date. Then I copy this into a Build Document, and then copy and paste it into the source control checkin. 

Instead, in the Build Doc keep a reference to fixed bugs and the changed files, and then put all the details in the source control checkin. If someone needs to see what the actual change was, they can go into the source control system and look at the changed file checkin comments.

Furthermore, comments with a revision history in the file header aren't necessary. If the changes are documented in the source control checkin then it's not necessary to bloat the file with unnecessary comments. 

Basic rules for commenting:
1. Leave relevant comments in the code explaining WHY something is being done a certain way. 
2. Don't clutter the file header with unnecessary repeated info
3. Don't clutter the class or methods with comment headers, use the XML comments instead so that they server a practical purpose in and outside the code.

References
1. Pragmatic Programmer
2. Effective Windows Powershell
3. Windows Powershell In Action v2
4. Powershell Disk Monitoring script
5. Refactoring

1 comment:

  1. Excellent post! I like the discussion on debugging and testing, which I think are critical for good code.

    ReplyDelete

There was an error in this gadget