Monday, February 29, 2016

Being a new parent; a software alagory

This weekend my son turned 1. This got me thinking about how so much of what I've had to learn as a new parent is similar to working in the software industry.

You don't understand the scope till your responsible for it

Prior to my son being born, we had no hands on experience with what it's like to have a child. Sure we babysat, a lot actually, and were comfortable around kids. We'd changed a million diapers. But we'd never sat up all night with a child with a fever. We'd never had to monitor a child's eating or sleeping routines. Babysitting, was just not the same as actually having a child. I've found that with parenting, most of the challenging stuff happens in the not-so-obvious areas of life. I think it's similar with engineering.

The challenge of working on a software product isn't on the surface. It's not about just understanding the language or platform. It's not about intellectually understanding the features and road-map. It's about understanding the nuance and not-so-obvious areas of the product. It's about understanding where your customers will be spending their time and what their pain points will be. You can understand software at an intellectual level but it's not until you try to change something, build a new feature, and/or take on operational ownership that you really start to understand the new product.

Everything has limitations

Every person has limitations. Newborns for instance can't talk. They can't crawl, can't feed themselves, can't really do much for themselves other than cry, sleep, and poop. As a new parent you learn the limitations of your child and (in the short term) help them compensate for their limitations and (in the long term) help them learn the skills necessary to overcome them.

A software product is much the same way. In order to help the system really thrive and succeed you need to understand it's limitations. Sometimes you have to put in short term fixes or mechanisms that allow them to work around these limitations. But in the long run, you need to be looking at how you can make the system better. How you can help the system overcome it's limitations. Sometimes this means refactoring. Sometimes it means prioritizing tech debt over new features. Sometimes it means recognizing a systems in ability to succeed and failing fast.

It doesn't grow unless you feed it

You're responsible for the care and feeding of the system. To do that you need to learning about the system as a whole unit, understand what change is necessary, and help to shepherd those changes through the system. Your software has upstream and downstream dependencies. Your job is to identify those dependencies and work to harmonize how your system runs in the context of the existing ecosystem.

Monday, February 22, 2016

Finding buggy code using git history and a binary search

Some bugs in software are easy to understand. Things like a null pointer exception are obvious and don't need a lot of context. But some bugs are more difficult. Some bugs just aren't obvious until you have the context of the change that was made that introduced the bug.

What I like to do when I'm hunting a bug down is to apply a binary search algorithm to my git history. This has two benefits:
  1. You're able to find the exact commit a bug is introduced in
  2. You've narrowed down the surface area of the code the bug could possibly be in

#1 above is important as it gives you the ability to reverse apply a patch and see if the bug goes away. If it works without breaking anything that's come to rely on that code it means that you've got a "quick fix" that can be issued to relieve the problem while you find a longer term solution.

Unless your team is a team of developers that goes dark #2 above is means you have found the handful of lines of code that contain the problem and the context of the code dependency. Simply seeing the inter-class dependencies may be enough to make an ambiguous bug make more sense. It's also a good place to look for violations of SOLID which make code less 'ible (maintainable, scalable, flexible, etc...).

So how do you accomplish this?

1. Find the starting point

Start with the git commit from your last release. Create a build from that and see if the bug reproduces. If not you've found your starting point. If it does reproduce and has been in the system a while, keeping going back release by release trying to find the commit of a build that does not contain the bug.

Hopefully you're tagging your releases or creating release branches.'

2. Use now as your ending point

3. Pick the mid point in time between your starting point and ending point

Using git log you:
  1. Get the hash of the commit closest to the mid point in time.
  2. Create a build using that commit
  3. Check to see if the bug reproduces
If the bug does reproduce you've got a new starting point: Repeat step 3 with the new starting point.

If the bug does not reproduce: Repeat step 3 with the new ending point.

Using this binary search you'll find the source commit of your bug fairly quickly (limited only by your build and validation time) and you'll have the context of the commit to fully understand the change that introduced the bug.

Monday, February 15, 2016

Leadership and Mentoring

Over the last ten years I've paid a lot of attention to the successful people in the companies I work at. While my definition of success has changed quite a bit, the common thread that hasn't is that a successful person is someone who enjoys their job, is respected and sought out by their peers, is not afraid to fail, and is given opportunities to take on new challenges.

As I've tried to dissect what makes someone successful I've noticed a trend. Most of the successful people I know have a mentor and have someone that they're mentoring. Upon further review I believe there are several reasons why being a mentor and having a mentor contribute to individual success.

Successful leaders are mentored by others

At it's core being a mentee means you have someone who you can get an outside perspective from. Why is that so important? 
  • You have someone who can provide objective insight into the success or failure of something they're not intimately involved in. 
  • You have someone that can ask you though questions to help identify your blind spots or personal biases that are getting in your way.
  • You can learn from different life experiences.
  • You have someone that is able to look at your situation through a different set of biases.
  • You can learn from their successes and what has lead to their failures.
  • You can talk through ideas, plans, and problems and gain an outside perspective.

Successful leaders mentor others

Being a mentor is not just about having the ability to impart knowledge to another person. It's about being able to ask the right questions, being an outside voice, and being able to break apart problems into smaller more solvable pieces.

I believe there to be a causal relationship between being a mentor and being a successful leader. There are several reasons I think the causality works this way.

  • Mentors are able to proactively identify and correct potential problems in their lives by helping someone work through their problems.
  • Good mentors can break problems down into smaller more solvable pieces.
  • Good mentors ask a lot of questions. They try to reduce ambiguity.
  • Being a mentor means being introspective and able to talk about your own failures and successes.

Monday, February 8, 2016

Difference between a programmer, developer, and engineer

Coder, programmer, developer, software engineer and others were among the many different titles I had in my career while writing code. Some were sought after and some were not depending on where I was at in my maturity writing code.

When I first started out I wanted to be called a coder. I worked in IT divisions of small companies where some people in the group were in charge of configuring and maintaining the servers and some were in charge of writing the software that ran on the servers. In those early days  I wanted to distinguish myself from the former group and I put a heavy emphasis on distinguishing my self as a coder or programmer (usually the later). I wanted people to know that I was responsible for the logic of the programs that were running on the system, not responsible for using those programs to manipulate the system.

As I grew in maturity as a programmer I learned that good programming involved refinement and iteration. I started to learn that good programs, ones that were run for years on machines weren't simply written, they developed over time. Developing a system over time required recognizing tried and true patterns and best practices. It required abstractions in order to iterate over the system. Programs weren't simply the logic used to solve a problem. Programs were a set of requirements that grew and changed as the program became more complete.

As I started to master my trade I learned that the best developers were really engineers. People responsible for the design, implementation, and deployment of software. In my mind I started to realize that a great developer was really an engineer. Someone that was able to look at the requirements and design a system that met the need but was also resilient to change. I learned that the one constant in software development was change. Being adaptive to change required a solution to be engineered. You start with an idea, built a system around that idea, and put that system into practice.

As I honed my craft, I started to recognize the different between software programmers, software developers, and software engineers. Some key differences are:


  • Programmers think in terms of languages, SDKs, and APIs. They build systems based on the tools they know and are comfortable with. Programmers value creativity and cleverness.
  • Developers think in terms of requirements, components, and interactions. They design systems using patterns and best practices that meet the requirements. They're able to evaluate, investigate, and determine if particular platforms, languages, and/or frameworks meet the need of the requirements.  Developers value completeness.
  • Engineers are problem solvers. They solve problems regardless of platform, language, or tool. They think about architecture. That is dependencies, single points of failure, scalability, and resiliency change. Engineers value simplicity, flexibility, and adaptability. They recognize that a system is never fully complete.
  • Programmers value the most creative or clever code.
  • Developers value the most abstract, generalized, and re-usable code.
  • Engineers value the simplest code that can be maintained and changed.
  • Programmers don't typically think about deployment. They throw their code over the fence to operations folks who own and maintain the production systems for them.
  • Developers think in terms standardized tools and processes. Developers value the ability to rollback.
  • Engineers think in terms of automation, repeatability, and reliability. They think about the surface area of the change, and how to measure success.

Monday, February 1, 2016

Executing Well

Regardless of the industry you're in or the role you have executing well is crucial for you to be successful. It's also, very difficult and takes rigor to do well. He's some tips on how to execute well.

Understand what you're being asked for

This sounds obvious, but it's amazing how often during the course of a day I see a group people walk away from the same conversation with different understandings of the expectations on them and their team. It's important to ask clarifying questions and even more important to repeat back what you're being asked for so that the other person can validate or correct your assumptions. One tip to do this well is to simply restate the action items at the end of a meeting or conversation.

If, when you're asked for something, the person doesn't specify a time don't assume that you can do it whenever you want. Ask what the expectation is for you to deliver and if it's unreasonable, negotiate.

Take Notes

Your memory is not as good as you think it is. The context that seems obvious in the moment isn't going to be obvious 4 hours or 4 days later. The details about your initial approach may not be clear later.

Don't make assumptions

If you're not 100% sure about something clarify it. Making assumptions is always a losing bet. Best case scenario you're assumption was correct and you lost a non-tangible amount of time clarifying your assumption. Worst case scenario your assumption was incorrect and you were going to do the wrong thing or do something that is sub optimal.

Follow Up 

It's important to remember that your stakeholders job isn't to be in your problem space 100% of the time. That's your job. The farther up the management chain you go the more your space is competing for the attention of your stakeholder. You should assume your space is not the highest priority right now for the other person. You should also assume that your space is crucial for their and your teams success.

Even if you haven't started a particular ask or aren't complete, give periodic updates. Don't wait to be asked. This helps those that are relying on you to have confidence that you're thinking about the problem and are going to deliver on the ask. It also empowers others to help you by removing roadblocks, taking other lower priority tasks off your plate, identifying dependencies that you're unaware of, or helping to manage expectations with others.

When you see a problem, do something about it

You should assume that the problem also affects someone else and that the others affected aren't empowered to do something about it. You should also assume that no one else is going to do something about it. Don't leave broken windows unfixed.

Know your stakeholders

Understanding the level of abstraction your stakeholders work at is key to executing well. The people responsible for solving the problem will want to talk about the details and the methods used to deliver. As you communicate up the management chain you should transition what you talk about from the more intricate details to timelines, dependencies, and risks involved in executing.