First, AI will do unprofitable programming work

In a recent episode of NeverRewrite, Isaac and I discussed the implications of AI doing rewrites for developers.  

So what if things change?

AI will probably replace most of the coding that developers do day-to-day today.  Today’s developers don’t punch punch cards, don’t design circuits, or write assembly code.  The nature of development has changed in the past, and will change in the future.

The first killer app for the PC was Lotus 1-2-3, which made spreadsheets widely accessible.  People used Lotus to perform a lot of accounting functions, but we still have accounting software.  Spreadsheets didn’t replace special function software, they created a new category of general purpose tools.

Rather than eating software development jobs, AI is a general purpose tool that will enable an explosion of software at the unprofitable low end.

What is The Unprofitable Low End of Software Development?

Simply, software developers are expensive.  There is a lot of potential software that could be written, but wouldn’t be profitable enough to hire someone to write.  There are tons of single use, single purpose tasks that could be replaced with a small bit of code, but only if you happened to have a developer nearby.

No Code / Low Code solutions help narrow the gap, but there are tons of tasks that are still too small to be generalized.

For example, I recently took a 3,500 product catalog in CSV form and wrote some python to upload the products to Shopify.  It also performed a second step to pull in the images from the factory’s website and associated them with the new products.  Shopify has great tools, uploading the file would be easy, but adding the images would have been a daunting and dull manual task.

Easy for a developer though; I ran it once, and will probably never touch the code again.

Trust, When You Can Verify

AI can write mostly correct code today.  When you can verify the results, you can accept them.

In the Shopify example you can verify by checking to see how many products were created.  You can check to see if they have images.  If it showed up on Shopify, then the software is correct.  It is running locally so performance and security pretty much don’t matter.  Optimized string functions and defensive string escaping aren’t concerns when you are only dealing with one file, once.

Prediction: AI Will Increase API Usage

As a development tool, AI will turn the average user into a mediocre API developer.  There will be an explosion of non-technical people using company’s APIs to solve bespoke problems in ways that couldn’t be done profitably before AI.  This won’t reduce the need for developers, it will increase the demand for people who can write APIs that are resilient, performant and secure.

Expect a flood of customers using your API in ways you couldn’t imagine.  The question isn’t how to have AI write code for your company, the question is how to make it easy for AI to use your API.

I can’t wait to see what people come up with!

Net Dollar Retention For SaaS Developers

Net Dollar Retention (NDR) is one of the core financial metrics for SaaS companies, and one where software developers have an outsized impact.  This article explains NDR and how software influences can drive the number down.  Finally, it discusses three areas for developers to focus on in order to bring the number up.  

What is Net Dollar Retention?

Net Dollar Retention is the rate that your existing customers continue to spend money with your company.  Renewals are flat, churn makes it go down, and expansion makes it go up.

As a formula using AAR (Annual Recurring Revenue), it looks like this:

( [Renewed AAR] + [Expanded AAR] - [Churn] ) / [Previous AAR]

Besides being a core metric, NDR is a key metric for companies considering going public.  Typically, a company going public needs an NDR over 107%, and ideally over 120%.

Only existing customers affect this metric!  For Net Dollar Retention it doesn’t matter if you replace every customer that churns with ten new ones, your retention rate will be terrible.

How Developers Impact Net Dollar Retention

There are only two real levers with NDR: Increase spend and reduce churn; and there is little that developers can do that will directly increase customer spend.  

The top 3 developer levers to reduce churn:

  1. Fix any bugs that corrupt or lose data
  2. Make the system more reliable
  3. Make the system faster

Fix Any Bugs That Corrupt Or Lose Data

This is the big one!

Customers come to your service to get things done.  The more often they hit bugs, the faster they will churn.  Only developers can fix bugs and prevent data corruption.

Make The System More Reliable

Close second to data corruption is reliability.

95% success rates mean that you should expect a daily job will fail at least once a month.  If customers don’t trust your system to work, they will sit and watch the process.  Usually by continually hitting refresh on your site.  This is a massive waste for your customer and makes your SaaS much more expensive.

The less reliable your service is, the faster they will churn.  Reliability is more than just a developer problem, but developers will need to lead the architectural charge.

Make The System Faster

Speed is a distant third because it rarely impacts the value that customers get from your service.  Speed, especially UI speed, has a massive impact on the customer experience.

Slow websites won’t make customers leave, but they will kill your net promoter score and leave them open to a switch.

They don’t want to waste time staring at a blank screen waiting to render.  When the problem is inefficient code, it is something that only a developer can fix

NDR is a Core Metric for SaaS Health

NDR is a core metric for health, and a critical one for companies seriously looking at going public.  Developers can heavily influence the number by reducing churn.

Fix bugs, improve stability and increase performance.

Developers can push these levers and improve NDR; no one else in the company has that power!  Become a hero to your business, pay attention to NDR and how you can reduce churn!

Reduce Long Term Customer Churn From Data Growth

Customer Relations are ever growing, a CRM must provide Management as well.  Punishing customers for loyalty is the inevitable consequence of not acknowledging and preparing for a long term relationship with your customers.  Destroying your customer's long term experience increases churn and kills your net-dollar retention.

Saving long term customers requires work and planning from the frontend to the persistence layer.

Here is one strategy for each layer to help get you started:

  1. Frontend: Dashboards over pagination.
  2. Backend: Historical limits by default.  
  3. Persistence: Data partitioning.  

Dashboards Over Pagination

New customers can see all of their contacts on one page.  Same for their marketing campaigns, tags, and deals.  That changes very quickly for customers who are using your system.  When customers can’t see all of their data on a single page, the solution isn’t pagination, you need dashboards.

When your customers go to their contacts, you could show them “Page 1 of 10”, or you could show them a dashboard with contact activity.  New contact counts, engagement rates, contacts who need a follow up.

A pagination is about databases, it is a terrible interface for getting things done.  Make your CRM about management and workflows with dashboards.

Historic Limits By Default

Add sensible defaults to everything to limit the amount of data searched.  Default to showing the last 6 months or 1 year of a customer’s interactions.  Keep the older data accessible, but don’t waste the user’s time loading history.

Put another way, how many extra seconds should you make customers wait to find out if a contact opened an email 3 years ago?  The correct answer is 0 seconds, and also 0 milliseconds; update your APIs accordingly.

Data partitioning

Event logs keep track of every email open, click, and website visit.  Because events rarely get deleted, these tables grow and grow with your customers.  Over time, the amount of data in the tables will cause queries to become slow.  The more successful your customers get, the worse your database problems become!

Partitioning directs the database to create different logical tables based on a key while presenting a view of the combined table.  Events are date based making them great candidates for partitioning by month or year.  The previous tip, Historic Limits By Default, places an upper bound on the data in a table scan.

Conclusion

Customer data accumulates over time, especially in CRMs.  Keeping customers for years requires preventing your system from punishing them for accumulating data.  Failing to address the problems will destroy the customer’s experience, increase churn, and reduce your net-dollar retention.

These three strategies will help you start thinking about data accumulation and how customer needs change over time.  Don’t throw away your loyal customers because your systems only consider the new user experience!

Phase 1 is a Millstone not a Milestone

Metaphorically, milestones are markers on your transformation from one state to another.  Millstones are useless, heavy, burdens that you can’t put down.

Project plans that seek to set out project milestones often end up burdening themselves with millstones.  The mistake is confusing the transformation with the project.  Millstones track the journey, milestones track the destination.

Things like “Phase 1” can’t be a milestone because there is no guarantee that completing Phase 1 means that you’ve made any progress towards your goal.  Yes, you worked hard and delivered a lot of code.  You’ve done the things you said you would do when you originally planned the project.  Can you objectively show that you’re closer to your destination?

Milestones, by contrast, are objective, external, measures of progress.  “Customers can use a feature” is a milestone.  “First paying customer” is a milestone.  They are points you expect to cross during the transformation because they demonstrate progress.  You can declare that some milestones are irrelevant, you can set new milestones, but you can’t move the milestones themselves.

Project based millstones like Phase 1 encourage movement and gaming to meet artificial deadlines.  Can’t complete a feature in time, just move it to Phase 2 and keep the project on track.  Phase 1 encourages wasteful death marches so that developers and project managers can report that the project is moving forward.

You can put down your millstones wherever and whenever you want.  Makes no difference to anyone or anything other than the artificial constraints you put on your project.  Today is a great time to let go of the weight.

Two Paths For Paying Down Tech Debt

In my last post I discussed two ways of making Tech Debt an expensive problem that gets fixed.  

I was trying to show that a rewrite or major project requires proving that the problem is very large, and convincing leadership that you can solve it in a cost effective manner.  A key piece is that the problem must be large to justify fixing it.  Rewrites and projects encourage you to raise the stakes to create urgency and justify the costs.

Iterative Delivery is about lowering the stakes.  The stakes are low, the urgency is low, and the costs are low.  You can “just do it” by adding a few hours onto your regular development cycle.  Instead of needing to convince leadership it would be strange to mention it all.  The stakes are too low to bother them at all.

Here are the two paths as a flowchart:

TheeSeeShipping, iterative delivery, brings results faster.  Choosing this path will have you paying down technical debt while rewrite plans are still being written.

There is another major difference between the paths.  A rewrite requires you to complete the whole project before you can measure the impact.  You don’t get to know if your project was worthwhile after you have spent all the time and money.  Maximizing the stakes also maximizes the risk.

Iterative delivery gives you unlimited opportunity to evaluate progress and change course.  Some changes will be worthwhile, some won’t, and you get a chance to access and correct after each change.  The stakes are low and so is the risk.

Picking a rewrite over iterative delivery increases risk and delays results.

Tech Debt is a Big, But Not Expensive, Problem

A common mistake among developers and line managers is to mistake Tech Debt as an Expensive, instead of a Big, Problem.  For tech debt to be an Expensive Problem the CTO and VPs of Development have to believe that the value the company will get from paying down tech debt is greater than the cost.

Leadership doesn’t reject pitches for rewrites and other major initiatives to address tech debt because they don’t believe that Tech Debt is a Big Problem.  The initiatives get rejected because they don’t believe that the results will justify the cost.

There are two ways to get around the Big vs Expensive problem.

The first is to use data to prove that the problem is Expensive.  

Find a way to measure the costs of tech debt: lost developer time spent fixing bugs, increased developer time building new features and above average customer churn.  Then, find a way to estimate how much better things will be after the big initiative.  Finally, estimate how long the transformation will take.  If you can credibly show that the improvements are greater than the costs, you should have no problem getting your initiative approved.  

Remember though, that you’re estimating the value of the improvements and length of time.  Credibility is as much about leadership’s faith in your delivery as it is in the numbers.

The second way to get around the Big vs Expensive problem is TheeSeeShipping, aka Iterative Delivery.  

Make small improvements every release and show that the cost of the problem is shrinking over time.  Less time spent fixing bugs, faster feature development, maybe even a reduction in churn.  Demonstrate that Tech Debt is an Expensive Problem by fixing it and providing more value than cost.

You’ll find that you won’t have any trouble getting approval, because you won’t need any approval at all.  You just need to start.

Separating The Work Of Today From The Work of Tomorrow

Scaling software has tension between the needs of today and tomorrow.  How do you resolve the tension?  Where does the work of today end?  What makes the next step part of the work of tomorrow?

Consider this simple rule:

For any piece of software in your system, you should scale it when it is the primary constraint, and stop when a different part becomes the new primary constraint.

Easy to say, and easy to do…if you can measure the performance of your system in part and as a whole.

If you don’t know which piece of your software is failing to scale, if you’re guessing about the work of today, don’t be surprised when your scaling efforts don’t impact the system as a whole.  Sometimes the scaling work of today isn’t scaling, it’s observability.

A Garbage Collector in 2 Shell Scripts

My previous post about a creating lightweight garbage collector for settings was a little obtuse.  This post is an example implementation for companies using LaunchDarkly and Gitlab.

Context, You've Got a Mess of Distributed Settings

Remember, this is a technique for getting a handle on your settings AFTER you’ve created or inherited a distributed mess.  Not making a mess in the first place is always a better idea.

This technique is to help you get started cleaning up a mess.  A mess is an ambiguous problem, it doesn’t have a central mass.  There’s no “worst” and no particularly good or bad place to start.

A Garbage Collector will help you get started by showing you the easiest things to clean up!

Step 1 - Extract Your Settings From LaunchDarkly

Create a shell script, extractSettings.sh

Calling ./extractSettings.sh <your api key> will give you a list of setting names, one per line.

These are the unique strings that you need to search for in gitlab.

Step 2 - Search Gitlab for Setting Strings

Create the second shell script, settingsToProjects.sh

Calling “./settingsToProjects.sh <your api key>” will give you a directory full of files.
Note: You need an admin level API key so that the script can see all projects.  Otherwise you might miss some references in projects you can’t see.

Each file will be “settingName.txt” and contain results like this:

“project_id”: 1
“project_id”: 15
“project_id”: 243

Find the Unused Settings

This doesn’t even need a script, run:

This will give you a list of every setting and the number of projects it is used in, sorted highest to lowest.  Anything with 0 lines is used in your codebase, 1 line means that it is referenced by one project, etc.

Take Out The Garbage

Start with the zeros.  Any file with 0 lines is either brand new, or no longer used.  That’s an easy check in LaunchDarkly.

Next, check for the single project use cases.  Some of those will be unused strings in constants files.  Clean up the constants files, and clean up the settings that fell to zero.

Because your garbage collector is tracking references, you can stop at any time.  You’ve automated the massive data gathering element, which makes cleanup cheap and manageable.

Fight Settings Cruft With A Lightweight Garbage Collector

In service oriented architectures adding new application settings like environment variables, constants, and feature flags costs almost nothing.  Cleaning them up, however, is expensive.  

Ideally developers would keep track of settings and remove them when they are no longer needed.  More often feature flags get set to 100%, everyone moves on, and the old code path lingers for months.  I have personally spent hours updating code, only to realize that it is effectively unreachable and needs to be deleted instead.

Talk about wasting time and money!

The High Cost of Doing Nothing

Doing nothing seems like a cheap solution.  The code gets a little bloated, the services use a little more memory, and API calls send a few extra kilobytes.  No single unused feature flag or environment variable has any impact.

Eventually you end up with hundreds of unused settings, on thousands of servers, distributed to hundreds of thousands of customers.  

The cost of those crufty settings add up in terms of performance, development time, and outages.

Cutting Cruft Is Expensive Too

A key disadvantage of Service Oriented Architecture is that settings get passed from one service to the next.  It’s rarely safe to remove unused settings because they may be gathered into a collection and passed along to a service that does use them.

Figuring out what is used where across multiple services is a slow process.  When you’ve got hundreds of settings to investigate, it’s daunting and demoralizing.

A Very Basic Garbage Collector

A Garbage Collector keeps track of references to objects, and when there are no more references, cleans them up.

You can make a very basic collector by scripting out a few API calls to your git repository.

The three basic steps are:

  1. Download and parse the constants file(s) from the parent app and extract a list of settings names
  2. Make API requests against your git vendor searching for the strings
  3. For each setting name make a file which lists which repo the string appears in

That’s it!  You now have a rudimentary system that tracks references to settings across your repos.  Any setting file with only one entry isn’t used anywhere else and can be deleted once the parent app is done with it.

Conclusion

A garbage collector is overkill if you’re curious about a handful of settings, just use regular search.  But when you’re facing hundreds of settings and you need to figure out which can be targeted for cleanup, a garbage collector might be just what you need.

The Pause

A common component of code rewrites is The Pause.  No new development, just for a few months, so that developers can replace the existing code. After the rewrite, development will be so much faster!  We will quickly come out ahead of where they would be without The Pause.  

I have seen managers, directors, and even CTOs go to stakeholders and convince them to allow a pause.  No matter what everyone agrees to, new development is rarely fully paused, the rewrite is never finished by the original date, and unforeseen events always occur.

Put aside the reality of why The Pause won’t work for a moment and examine the premise itself.  The Pause is all about getting tech what it wants on the assumption that this will make things better for everyone in the long run.  The Pause excludes all other departments.  Basically, The Pause says:

Yes, in the past, we failed to understand and anticipate changes from the rest of the business.  We made our life so difficult that we can’t keep making changes for you.  But don’t worry your pretty little head, we are so much better at understanding you now!  

We are going to go off by ourselves for a few months and create new technology that will handle and anticipate all of your future changes.  We understand you so well, and our work is so difficult to explain, that we are going to do this work without you.

The Pause is an insulting fool’s errand.  If the technology group were capable of anticipating future changes by themselves, they wouldn't need a rewrite.

Instead of asking for The Pause, try a dialog with the rest of the organization.  Bring them in instead of shutting them out.

Site Footer