In episode 22 of Never Rewrite, Isaac Askew and I discuss an iterative refactoring workshop I have been running to improve my colleague’s development skills. This episode dives into how the workshop is run, what the developers get out of it, and how it directly improve’s the company’s codebase. If you’ve ever wanted to help your fellow developers but didn’t know how to start, this show is for you!
In episode 20 of Never Rewrite, Isaac Askew and I discuss the reality that sometimes company shrink instead of grow and how that impacts your work, your team, and your career. In this episode we discuss what to expect from a shrinking company.
Scaffolding is a temporary structure used by workers to build or repair a permanent structure. Scaffolding goes up, the building gets built, the scaffolding comes down.
In software development scaffolding is code and tools that you create to help you as you develop, that are also destroyed in the development process. Incremental refactoring steps are scaffolding. So are no-op interface implementations, dirty shell scripts used to glue things together, and ideas that fail.
They are ephemeral ways to build software. They may live forever in your source control, but you’ll only use them for a short time.
This makes scaffolds different from tests. Tests not only help you build software; they increase in value as they age. Tests are support beams inside your application.
Throw away work is when your software works correctly, but it never gets used. Features that get built and never get used are throw away work. Throw away work doesn’t create new opportunities, it often exists as a software crutch for uncomfortable decisions. It rarely serves a purpose and never provides value.
The biggest difference between scaffolding and throw away work is how it makes you feel. Scaffolding should be energizing and opens new horizons. Tests give you confidence. Throw away work leads you to a dead end.
When in doubt ask yourself how long the code is supposed to last and what it would take for it to be a success.
In episode 19 of Never Rewrite, Isaac Askew and I give a name to a strategy we employed in a previous project. The Beachhead Strategy helped us dramatically improve the experience for 90% of our customers, without the constraints of TheeSeeShipping or cost and delay of a full rewrite. The Beachhead Strategy is a hybrid approach where a specific subset of functionality is rewritten in pursuit of a specific improvement.
It's not a general solution strategy, but when it fits, the results can be amazing.
Listen to it at NeverRewrite, Spotify, or Apple Podcasts and let us know some strategies your company uses to safely upgrade your systems while minimizing the risk of downtime and negative impact to your customers.
SmileAndDial CRM was built around the concept that people are nothing but a number. Phone numbers were a fundamental constraint in the software; it was impossible to have a contact that didn’t have a number. With the introduction of TheeSeeShipping and months of Invisible Shipping SmileAndDial has been able to free themselves of this incremental constraint. Through many iterative releases the company has slowly been transforming itself.
The data model has gone from using Phone as a key in all tables.
To a normalized model with foreign keys that don’t carry extra meaning.
Changes were small. They were low risk and had no customer impact. There was little work in flight, and occasional priority shifts didn’t result in code rot. Their slow accumulation removed a fundamental constraint that was built into the company’s founding principles.
SmileAndDial CRM is still the go to CRM for boiler rooms, pump and dumps, extended car warranties, and other outbound call center activities.
Now, as if by magic, they are also ready to help their customers expand and spam prospects with ads for bitcoin, blockchain technologies, and of course, male enhancement pills.
Thankfully this is a fable and we can pretend that this is a happy ending!
Onward with SmileAndDial CRM, and their quest to remove phone numbers as a fundamental constraint! Part 2 introduced the concept of TheeSeeShipping, a low risk, iterative way to make large sweeping changes. At the end of part 2, the database looked like this:
New Id columns have been added, but they are unused and null.
Now SmileAndDial’s developers can TheeSeeShip small, incremental, low risk changes to production. These changes are invisible to users and can be worked in with day-to-day work.
TheeSeeShipping works like a ratchet; once a change is complete, it stays complete. Whether the work is done quickly or slowly, change is inexorable and one way.
The Second Series of Releases - Propagating ContactId
The second series of releases is to insert the new Contact.Id value into other tables’ ContactId value when rows are inserted.
This requires lots of small changes - getting the new Id after inserting into Contact and adding it to the insert statement in other tables. But, because the fields are nullable, there are no foreign keys, and no query logic; these changes can be done incrementally.
Fix one or two inserts every release. These are small, easily testable changes. Grab the Id, add it to the insert, confirm that the row was written with the correct ContractId.
TheeSeeShip it in low risk, two line changes until all new rows have a ContactId.
The next step in this series is to backfill the existing data. The Contact table has an Id for all rows. Run an update query for each table to backfill the data.
Guess what, since the data still isn’t used in the system this is also a low risk query.
Now every row in the database has a value for ContactId, and every new row will get a value on insert. The time has come to remove the nullability and add in the foreign keys.
The Third Series of Releases - Updating Selects
With ContactId propagated to every table in the database, the time has come to update the Select queries. Instead of selecting from every table by phone number, SmileAndDial needs to run off of ContactId, or join Contact to use Phone
Each of these changes can be made incrementally in a separate release. They are small, easy to test, and independent of each other. TheeSeeShip it; the data model is different, but to customers it is still SmileAndDial.
After any bugs or missing ContactIds get fixed, it is time to remove the foreign key constraint on the Phone field. Note that this can be done at any time that is convenient to the DB team. There’s no rush and no impact if a bug with ContactId does turn up.
The Fourth Series of Releases - Removing the Fundamental Constraint
Everything in the first three series of releases was incremental and non-breaking. Each change was minimal and non-breaking.
Even at the end of phase 3, the discovery of an unmodified table would have no impact on the system. The table and code would continue to work as it always had. Any mistakes were easy to roll back.
Everything had changed, and everything was still the same.
In the fourth series of iterations, Email will be removed as a fundamental constraint in the system. This, finally, is a breaking change that is not trivial to undo.
But, it is also a change that is easy to do in an incremental, low risk way.
Incrementally remove the Phone column from all tables except for Contact. At this point there are no foreign relations or Select statements that use Phone.
Finally, when Phone is gone everywhere else, make Contact.Phone nullable. Update the service and UI logic to allow the creation of a contact without a phone number.
Phone Is No Longer Fundamental
There are a lot of incremental changes and releases in the four series. The key is that each change was very small and very low risk. After each release customers had a fully functional, up to date, version of SmileAndDial.
Unreleased work in progress was low and work could have halted for months at a time without any of the completed work suffering from code rot.
TheeSeeShipping changed the fundamental nature of SmileAndDial without ever taking SmileAndDial out of the hands of its customers.
In episode 16 of the Never Rewrite podcast, Isaac Askew and I discuss some tricks and tactics to facilitate conversations with your team. We dive into the psychology of how being obviously wrong can get people talking, why leaders need to hold back their opinions, and giving teams permission to disagree. If you're having trouble getting your team to brainstorm and collaborate on ideas, this episode is for you!