Monday, March 21, 2016

Transitioning well

Way too many times I've seen people leaving their jobs and transitioning poorly. Some see their decision as a free pass to express their frustrations. Some are fed up and want others to know about it. Some just aren't aware of what they're doing. Whatever your situation, here's a short guide to transitioning out of your current job, company, or role well.

Don't Sow The Seeds Of Discontent


There may be many reasons you're leaving your current role. You may be unhappy. You may feel slighted. You may disagree with the direction of the team. Or you may be leaving for some other reason entirely. It's important to remember that just because you feel this way doesn't mean everyone else should. It's not your job to make sure everyone else shares your grievances. That is a sign of immaturity. If you're having interpersonal conflict where you're at, chances are that you're at least a small contributor to the problem.

Be mature and don't be the poison pill that's trying to get everyone else to make the same decision as you. Transitioning is not the time to let everyone know what you've been secretly thinking about them, the project, or leadership. HR is the correct place to vent any of these frustrations.

Don't Burn Bridges


You've probably heard not to burn your bridges on your way out. And you've probably dismissed it as irrelevant to your situation. But there are two good reasons why you should take that advice to heart.

First, Though you may not be able to imagine ever working on that team, at that company, or in that role again you don't know what your future holds. There may come a time when you do want to come back. Maybe the leadership will have changed. Maybe they'll be solving a really interesting problem you're excited about working on. Maybe you've matured and seen the error of your ways. Whatever the reason may be, there may come a time when you find yourself wanting to come back to a job you've left. Leaving on good terms and being helpful on your way out leaves that door open to you.

Second, you don't know when you're going to run into your former colleagues again. You don't want the last impression you leave with those colleagues to be a negative one. They may be in the critical path for your success at some point in the future.

Do Your Best To Set The Team Up For Success


What can help your soon to be former team the most is to make sure that any tribal knowledge you have is documented and understood by the current team. 
  • Document the things that are currently in flight by you.
    • Make sure you state what the problem is, how you're solving it, and what's going to be left to solve.
  • Go through your calendar for the past three months and look for any one off meetings you've had about current or future work and debrief the team and/or your manager on the problem space.
  • Make an external point of contact list with the names and roles of every external team you interface with and share this list with your manager and current team before you leave.
  • Make an internal point of contact list that can be shared with your external points of contacts and share this list with them before you leave. 

Monday, March 14, 2016

You Shouldn't Backfill Unit Tests

Recently I've found myself in several conversations about unit tests, and the lack of them on a given project. It seems that almost everyone on the team knows that writing unit tests is a good thing and it seems that most of them also wished they'd written them from the start. But, as is the case with most fast moving projects, the team finds themselves in the position where they don't have adequate test coverage. This leads to reduced confidence in the code and not being able to catch bugs far enough upstream to effectively prevent them from ever being released to customers.

What this usually leads to is people on the team making comments, in response to a bug or regression someone is working, that if they only had unit tests they would have found this bug earlier. What I've seen most often in that situation is someone finally getting fed up enough with bugs and/or regressions and picking up the unit test torch and leading a crusade to backfill all the missing tests. While I appreciate the spirit of this, it's not the right thing to do.

Why's it not the right thing to do? First, you're not actually solving your problem. Your actual problem is that you can't ensure that the code you're currently changing 1. does what it's meant to do and 2. doesn't do something it's not meant to do.  Second, depending on how old the given code is, you may not know how it was actually supposed to work vs how it actually does work. You may end up writing unit tests are aren't correct, and in the worst case scenario cause you to change working code. Lastly, when the team is done backfilling the tests, they haven't learned new behavior (i.e. to write the tests when you write the code) but, more likely, have grown a disdain towards writing unit tests.

Now before you start to think I'm advocating against writing unit tests I'll flat out tell you I'm not. In fact I've come to realize in my career that writing your tests first is the only way to assure that you have working code. So what am I advocating for then?

Make a decision as a team to write unit tests and then write unit tests for all the code the team writes from that point forward. You'd be surprised at how much better your code coverage will be after just a short amount of time. Why? Because you'll be writing unit tests for code that you're fixing bugs in. You'll be writing them for new features or changes to existing features. Essentially, you'll be writing tests in the hot spots of your code that are requiring change. The very code that is either causing bugs, or is likely to have bugs introduced in.

If you never change a particular set of code again then you don't really need unit tests for that code (remember I'm talking about unit tests and not integration, system, or other types of tests).  If you do change that code, then because you've decided as a team to write tests, you'll add the missing tests when you go in to make the code change.

So how do you get started? It's easy, just follow my 3 step plan.

1. Make a decision to not put up with having incomplete code (i.e. code without corresponding tests).
2. When you write your next set of code, write tests!!!! (preferably first)
3. Enjoy the fact that you now have less buggy code that you can have more confidence in.

Monday, March 7, 2016

Apple, Encryption, and the FBI's request

Encryption has been in the news a lot lately with the recent stand Apple has taken against the FBI's request to help them break into an iPhone. Whatever side you're on with this I think there's some interesting things that may be a bit misleading to the general public that I'd like to weigh in on from a technologists perspective.

I don't work at Apple or the FBI so all of my information about what's going on is from what I've read in the news, from Apple's and the FBI's public statements, and from what I know about how software is built and how operating systems work.

1. Apple is being a bit disingenuous when they say that they're being asked to create a new operating system. I think I understand why they're using this language. I can't find the source to cite here but I believe the legal guidance around the All Writs Act that the FBI is using to claim legal jurisdiction is that a company cannot be compelled to create something new in order to comply with the request. In Apple's case, saying that they're creating a new operating system makes then case stronger in their favor.

What Apple is being asked to do is create new code or remove existing code (likely somewhere in between) in their existing operating system that would weaken or bypass the current security of the system. The reason I say this isn't a new operating system is because an operating system at it's core is a system that interacts with hardware, sensors, and peripheral devices by providing tools and services that applications can build upon. Operating systems do things like interact with your hard-drive, memory, graphics card, and etc. While security is part of the operating system, 99% of what Apple would be delivering with a change would be the same as what's in their operating system now.

Regardless of whether what Apple would need to create is a new operating system or not, they're being asked to create a product that does not exist today by writing (or changing) code that would allow for a brute force attack. So I think Apple is being genuine in what they're trying to say, but not in the way they're saying it.

2. Apple's correct that you can't just write something and then throw it away. 

The only way to achieve what the FBI is asking without having any trace of the source code would be to have a machine from which the source could be changed and the operating system build that didn't have a hard disk or memory attached to it. If there is a hard disk or memory there is a "record" of the change at the lowest levels from which the changed code could be re-constructed. This isn't likely as it would require physical or network access to the machine from which the code was written. You could prevent network access by never plugging the machine in to the network. And you could prevent physical access by destroying the machine immediately after creating the modification to the operating system. Neither of those two are really feasible in today's modern software development ecosystem.

Virtually all software written today, likely including Apple's, is written using source control. Meaning, there is a system that contains every line of code and tracks all changes to that code. This is done for many many reasons. For instance, as software engineers we often have to re-create a build at a given point in time in order to find and fix bugs in a particular release. By the time software is released, we're already working on the next thing. Being able to recreate a build exactly as it was allows us to create targeted changes (or updates) as well as gives us the ability to reproduce errors. Additionally source control gives us an audit mechanism for changes introduced into the system. We can see who, when, (and often) why a change was introduced. With a source control system it is possible to go back to a snapshot of any code in the system at any point in time.

Trying to make changes that never get saved up stream to the source control system isn't that tough. But what is likely tough is getting a fully releasable build created using a build system that assumes the build is being created from source control. It's likely that the Apple's code that builds Apple's operating system is done so through a pipeline of tools that gets the source code from source control. Meaning, all of Apple's processes are likely setup around the use of a source control system.  So if engineers at Apple were to create the requested software it's likely that it would have to be added to the source control system in order to create the requested build of the operating system. Once these changes are added to source control, they're forever there and forever accessible (to an extent).

3. This is about more than just 1 phone. As much as the FBI wants us to believe this is just about one phone it's not. One of the ways our legal system works is through the setting of precedent. Once an act has been performed that can serve as an example for future similar cases precedence has been set. If Apple complies with this request there's precedence that can be used to compel other hardware/software manufactures to do the same.

4. Security is about trust and at the end of the day that is what this is all about. Apple, rightly so, does not want to lose the trust of those in it's ecosystem. It doesn't matter whether Apple thinks this is the correct thing to do from a moral, legal, or ethical standpoint. If Apple loses the trust of those in it's ecosystem that would spell imminent doom for the company.  

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:

Design

  • 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.
Development
  • 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.
Deployment
  • 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.