Developers – Make Your Own Metrics

Writing software can have a bit of a pile of metrics to pay attention to. I especially hate being held toward measurements I cannot get control of. One of the worst offenders can be the ‘Story Point.’

The Problem of Story Points

The story point starts with the best intentions. It gives a way to for a team to build consensus about how big something ‘feels’ without the burden of a deadline. Project managers can get a general gauge of velocity, and an idea of how long a project will take to complete. But there are some glaring holes.

First, there is no baseline for a story point. What’s a 1? Without a definition of the base, what does it mean when a team estimates something at an 8? Is an ‘8’ in fact 8 times bigger than 1? If not, what’s the value of a velocity ‘sum’? If you can’t trust 1+1 to equal 2, the fact that your team got 35 points done in a sprint is meaningless.

Second, in my day-to-day developer role, I can only minimally impact the larger measure of velocity with story points. My largest impact is simply showing up for work. In effect, velocity largely measures who was on vacation for a given week.

Metrics I Care About

Things that get measured, get improved.

There are plenty of things I can demonstrably impact as a developer though. I can write more LOC, or less. I can measure test case counts and the code-coverage of those tests. I can measure the complexity of functions and classes. I can measure the depth of dependency usage, and the number of interface implementations. I can count external dependencies, or compiler warnings. I can do stupidly easy stuff and count the number of ‘.Result’ calls on async methods. (Quick tip, your target is 0.)

It comes down to a issue of my own design though. The trick is to decide what that design is, and how to measure it. For my own aesthetic, I prefer the following:

  • Small code, thoroughly-tested, released often.
  • Code which is apparent in purpose and function.
  • Code with minimal external dependencies, which can be quickly replaced when warranted.

These are my design preferences, and having them help lead me towards the metrics I care about.

Small code, thoroughly-tested, released often = Cyclomatic complexity + Unit Test Coverage * Count of the number of deployments. These are simple numbers I can get out of build tools, and can ‘fiddle with’ right there in my editor. I can target small commits that are easily released to boot. I might not be directly able to control the release schedule, but I can target code that CAN be released often.

Code which is apparent in purpose and function = Average function length / Average class size * Average length of time commits are in code review. Again, I can fiddle with function length and class size directly in my editor, and I can make smaller commits / review sessions. I can do this every day to improve these numbers.

Code with minimal external dependencies = Count them. Did I install a Nuget package that came with 6 dependencies? Is there a comparable package that only has 2? If not, can I make one? If I don’t have time, can I minimize the surface area of that package? All of those items are directly under my control.

Communicate, Communicate, Communicate

Since I have my design aesthetics and metrics that show them, I can use them to communicate value and even push them further beyond story point as a measure of value. Some examples:

PM: We only completed 25 story points this sprint. Last sprint, we got 32. 😦
Me: We improved our test coverage by 28%, and last sprint, we had only gone up 4%. Our system is more robust against failure.
or
Me: We released 7 times this sprint! Last sprint, we released 5.
or
Me: Our average function length decreased by 8.5 lines, and our cyclomatic complexity stayed the same. That means our system is easier to work with for the next sprint!

Will my PM always understand these metrics? Probably not, but then my job is to get involved and communicate my values!

I might have to compromise. You don’t get to win everything, but having your principles backed with hard numbers is a much better way to win something and exercise some authority on some of your work.

I would rather be a stakeholder in what I am building than a cog in the machine.

Developers – Know Thyself

I am not suggesting that we change everything about story points or project management in a software project. There are better minds than mine on that. However, developers should do everything they can to decide how they want to write their code, and how to measure their improvement. Be regular, diligent, honest and thorough measuring your work. It is the best way to improve what you actually care about.

On Passion

A debate recently rehashed on (of course) social media revisited the discussion about whether or not a developer is a ‘real’ developer if she/he were doing it ‘just for the money.’ Some folks argued that developers who were just in it for the money were selling out. Others argued that doing a job for money aren’t doing anything different than anyone else, and that just plain-old-engineering is a perfectly reasonable activity.

I was easily sucked into this debate. Working on teams with passionate people is an amazing and wonderful experience. Hours literally melt away, even when doing simple drudgery work. The work needs to get done, and you feel a carnal pull toward it. Who doesn’t love getting lost like that?

Passion glosses over a lot of flaws though. The constant hours eventually drag on and drain you. Following passions and jumping from the next thing to the next thing to the next thing ends up leaving holes everywhere. “Passionate for technology” rarely correlates to “thorough and detail oriented”, and people sacrifice professional behavior under the guise of ‘passion’ way too regularly to be ignored. At the end of the day, you’re left with the same old technical debt you have on every other project with the added burnout of dealing with all of the passionate eccentricities.

Tech pays very well. Folks with ten years experience in their chosen field happily pull in the high 70s, when first year programmers leaving school with a comp-sci undergrad degrees get six-figures. That sort of incentive can attract a lot of people, regardless of where their passion lies. One of my ex interns once told me that if she could make the same money she would spend her time sewing clothes. She then told me about the similarities she saw in the nature of sewing, compared to programming: the detail and focus of the work. Would she rather be sewing than programming? Absolutely, but she was looking for a career, not a hobby.

I remember being a young kid hearing a news anchor on the TV describe someone as ‘middle-class.’ I remember asking my mom what class was and what class we were and she thought and said “something like a sort of upper lower class. We aren’t poor-poor, but we don’t really have any money.” I knew we weren’t ‘poor-poor’. Nobody in the house was starving. We were in good health, and lived in a house well big enough for everyone (my mom, stepdad, and the four kids.) We didn’t have a lot of the things other families had though, and I do remember being unduly aware of how much things cost, and how visibly bad it made my parents feel when we asked for more than they could afford. We had hand-me-down stuff. I started on a TRS-80, because that was available at a thrift store. We got an Apple IIe, when my dad, who worked procuring equipment for researching professors, was tasked to replace it. My mom bought a used 386, when 486s and Pentiums came out. The Apple wasn’t working for her schoolwork.

I grew up more and more fascinated by computers. I would describe it as a combination of passion, fascination, and an ability to create some control in a less than stable location. Starting from playing games written verbatim in Basic from books to connecting to bulletin boards for reasons I can no longer remember. I would fiddle with things just so, to the point where the computer would be unbootable an hour before my mom got home. My fear of her yelling (she was a prodigious yeller) prompted just enough ingenuity that I was able to restore the machine to a working state at the last minute. A unique first taste of just-in-time optimization.

From my beginnings, there is not a clean differentiation between passion for technology, or simple financial drive, and I am not sure the distinction is necessary. I will say plainly, as the breadwinner of a family of five, financial viability is the first thing that I look for. Passion for the work comes second. I am blessed to have found a position that met both criteria. I have a career that enables my passion for technology and service, and I make enough to support my family. But there is no doubt that the finances , I would move towards a career that made that possible, regardless of my passion.

Does that fact make me less passionate about technology? I don’t think so. I find that my ‘passion’ changes with the wind. Example: I deeply dove into functional programming with F#. I still love the language, but I am not spending every day pining about it anymore. What will I be passionate about five years from now? Will it be F#? Coaching? Writing? CrossFit? Spanish-style guitar? They are all some pretty good candidates given what I do now, but it’s entirely possible that will be something else entirely.

There’s a good chance I’ll still be a programmer though. In five years, my oldest will be in college. My youngest will be in his second year of high school, and my middle will be in her senior year. I will still need the same income that I do now, if only to continue to support them. I will passionately do so with the skills I started building with writing Basic games. I expect my ex-intern to do the same thing, to passionately support herself and her family with the skills she’s built, both programming and sewing. I guess I land on the side of being a passionate sell-out. As a wise man once said, “Take care of your chicken.”

Four Best Practices of CI Builds

Continuous integration builds (also called CI builds) are an absolute process game-changer, turning a local ‘works on my box’ coding and deployment strategy into an automatic and reliable process. Once a team gets a taste of an automated and reliable build process, it is easy to fall into a trap of adding all of the things to your CI build. Integration tests, security scans, performance tests, etc, until eventually, the CI build has lost the features that make a CI build implicitly valuable. The best development teams keep continuous integration builds simple.

Best Practice: With no changes to code or steps, the result of CI builds should be the same.

Responsibilities of the CI Build

A CI build’s job is to collect all developer changes, and create a releasable artifact, ensuring changes from all developers on a project are included in the product, and don’t cause conflicts with each other. A CI build must be fast, so that changes that break a build can be immediately corrected; a quick feedback loop is essential to the CI process. A CI build should perform the following steps:

  1. Collect all source code and changes.
  2. Restore dependencies.
  3. Compile / construct the build.
  4. Run unit tests and build verification tests.
  5. Create the artifact.

Assuming the same code input from step one, and no changes to any of the steps, a CI build’s result should be the same, every time.

A new CI build should be executed if the state of any of the five items above are modified. If there’s a code change anywhere, step one has changed. If any dependencies are updated, in the framework or libraries the product uses, step two has changed. If a build setting has changed, like going from 32 bit to 64 bit, or from ‘debug’ mode to ‘release’ mode, that is step three. Unit test changes typically are manifested as code changes, but any test settings changed would be an item for step four. If the artifact construction process changes at all, that’s step five.

Best Practice: Execute a new build on any individual change to those steps.

Tempting Steps You Should Avoid in CI Builds

  • Code Security Checks
  • Integration Tests

Code security checks are tempting items to add to a CI build, but fail the ‘no changes to code or steps’ rule. Most code security checks are rule-based in nature, getting updates when there is a new known vulnerability. The process is similar to a malware database updates. With no code change, and no change to steps, but an invisible-to-the-developer modification to the security changes, builds can succeed or fail seemingly randomly. Also, the scope of secure code changes can be larger than common unit / build verification failures. A security change can be very small, but more commonly is larger and design-related.

Best practice: Include code security checks on a regular schedule, not directly connected to the CI build, and have those check failures create backlog items the developers can research and correct.

Integration tests are tempting to add to a CI build, but fail the rule of failing fast. Any system large enough to have integration tests in the first place will be a fairly complex set of tests to run, which may take quite a while to execute fully. They also tend to rely on a lot of scripting and setup work.

Best practice: Include integration tests as a post-CI step in an automated pipeline separate from the CI build.


To recap: Continuous Integration builds should be quick, automated, and provide a fast feedback loop. They should contain the following steps.

  1. Collect all source code and changes from the repo.
  2. Restore any dependencies.
  3. Compile / construct the build.
  4. Execute Unit Tests and Build Verification tests.
  5. Create the artifact.

Remember the best practices of good CI builds:

  1. With no changes to code or steps, the result of CI builds should be the same.
  2. Execute a new CI Build on any changes to the five steps.
  3. Include code security checks on a regular schedule, not directly connected to the CI build, and have those check failures create backlog items the developers can research and correct.
  4. Include integration tests as a post-CI step in an automated pipeline separate from the CI build.

Happy building!

Six Questions You Need To Answer When Learning a New Programming Language

Are you someone who wants (or maybe is being forced) to learn a programming language? Learning to program isn’t just syntax and structure. Here are six questions you should answer about your programming language before writing your first program.

While learning the syntax, structure and tools, make sure you can answer the these questions.

1. What is latest version of your language?

By keeping yourself with the most up-to-date versions of your language, you minimize the risk associated with using old software with known security flaws. Building software can be risky, if not done carefully, so make sure you are using the most up to date version of your language.

Paying attention to the version information is also a great way to date the information and numerous resources you find out there in the wild. C# is in version 8 now. If you find a book about C# 2, it is NOT new, and can probably be recycled.

2. Who hosts the documentation, and where?

Programming languages will either have an organization, or a corporation which acts as the owner / maintainer of that language. C# is owned and maintained by Microsoft, and the C# documentation is hosted on their website. Python is hosted by the Python Software Foundation. Java, by Oracle.

Find the documentation website, and favorite it.

3. How do you manage dependencies and libraries?

Nowadays, nobody codes anything entirely by themselves. All languages start with a basic platform library that contains the very basic commands, keywords and structural expectations. C# has the .NET runtime. Java, the JDK. Often times open-source community provides the rest via a packaging system.

Learn your packaging platform, and how it works. Each package will often be just like the programming language itself, with versioning, docs, etc.

4. How do you test your code?

Unit testing has been a best practice for software development since the early 2000s. Unit tests are an extremely useful tool in your belt, enabling you to prove out functionality you are exploring or have written yourself. Every major language will have a library associated with writing unit tests. Using the packaging platform from step three, your next step should be finding out how to test your code. You, and your users, will be grateful that you did.

5. What risks are there? What should you watch out for?

In general, programming is a ‘high access’ activity on your computer, your networked environment, your data, etc. The convenience of doing things quickly or in bulk is precisely what a programming language can enable, so be careful. Make sure your SQL statements have WHERE clauses, and are guarded by a transaction that can be rolled back, if done in error. Make sure your loops have defined end states. Make sure you know precisely what your memory pointer is pointing to. Low-level compiled languages have more potential to damage computers directly by overwriting memory or restricted data. High-level interpreted languages tend to cause file or data related issues.

A computer does EXACTLY what it is told to do, and nothing more. Remember that, and be VERY sure it is doing what you intend.

6. How do you package and deploy the code you write?

Remember that code is just part of the story here, and is largely just a work product to the end result itself. Hosting a JavaScript site on a localhost isn’t enough, nor is a bunch of class files for a JAR file. When you write code, the goal is to ship an artifact of some kind. Don’t just start with Hello World, but start with Hello World deployed somewhere!


There are lots of resources out there for learning programming in a digital age. As you go through your learning, make sure you can answer these six questions while you’re learning the basics of the language. Happy coding!

Managing Expectations

Non-F# content warning: Skip to the next one if you’re not interested in general stuff.

Generally, a working programmer doesn’t have too many difficult “non-programming” tasks. Difficulty is the name of our game, and we like it that way. That said, one of the most critical skills a developer has is to manage folks’ expectations of you. Thought-work, in general requires a level of communication that seems nonstandard and maybe a little unnatural to your work.

The reality of being a working programmer is this: Your boss probably doesn’t exactly understand what you’re doing. Your boss may be relying on you to do a good job, regardless of his/her detailed understanding of your work. Making sure those expectations are set properly is key to keeping this relationship copacetic.

An Example: A customer asks you to sneak in a quick feature. You’ve taken a swag at it, and it looks like it won’t take more than a few hours and doesn’t impact anything, so you agree. Your customer leaves you happy, and everything seems fine. Fast forward to a week from now. The feature you were supposed to be working is late, and blocking everything going out. Your customer, who felt like his request was tiny, and shouldn’t impact anything, complains to your boss that the feature is late. Your boss, who has no idea that you agreed to anything, has now the unpleasant task of defending why the feature is late, even though she/he didn’t know it was part of the release. That makes her/him look disorganized and incompetent, and that’s not how you want to make your boss feel or look, even if you hate her/him.

Take a look at your day to day interactions and communications. Do folks know what you are doing? Do they know when you releasing your work?

Here’s a tip. Don’t assume that folks are reading every email, or “making the connection.” Make yourself very clear about what you are doing, when you expect to be complete, and if there are any items blocking you. If you are not sure yourself what to be doing, there is a very good chance you have not managed expectations well.