Throw it away, throw it away now
A few weeks ago, I was fortunate enough to attend a talk by Marcus Radich from PageProof at the Microsoft Ignite conference.
Marcus is one of the founders of PageProof, a startup that not only had a big idea but managed to achieve global growth extremely quickly.
In his talk, Marcus made a point that really resonated with me from a security perspective. He spoke at length about the benefits of throwing away your prototypes and early experiments.
He was speaking from an engineering and product development point of view but I thought I would explain why this has some unexpected benefits for the security of your solutions too.
The truth about rapid paced business and product growth is that we don’t always know if something is going to work.
In fact, let’s be brutally honest, sometimes there are so many new technologies and challenges in our environment that we don’t always know how to effectively operate them all to begin with (regardless of what we are trying to build).
When we are doing new things, solving new problems or tackling hard questions we often write simple scripts or prototypes to rapidly iterate possible solutions.
These become the basis of our validation. They show us that we can build it and that it can be done.
These are two pretty fundamental realisations in those early stages. They form the foundation on which you can start getting market validation and acquiring early adopter clients.
The dream in this scenario is to then archive this code and engineer the production solution from scratch.
You’ve already built it though?
The trouble is, for many young companies there is a pressure to move at a relentless pace. Every second is vital and nothing can be wasted.
This pressure ripples down to the engineers who have to meet these deadlines and deliver the solution. While the intention is normally to engineer the solution properly, often we decide to reuse our prototype code and experiments as a temporary solution.
Is there a difference between prototype and production quality code?
To the outsider or to those who have not been around software development for very long, there is sometimes that assumption that the difference between prototype or experimental code and engineered code is very small.
To illustrate that this isn’t always the case though, I spent some time this weekend going through this process of re-building and documented the results.
To replace a single Django application prototype. This prototype was functionally complete but was written hastily to prove a concept so not considered viable production code.
Note: I write a lot of python so I tend to be using python frameworks. The findings in this article however are universal and apply to almost all languages and frameworks.
The before picture — prototype code
The prototype provided 8 different functions across 2 models.
The prototype had over 800 lines of code.
The prototype had no tests.
The prototype had 2 levels of role based permissions which were included in the code 19 times.
The prototype was a full stack application (including the model, view and controller aspects). The prototype validation however showed that the view part wasn’t really needed as it was to be replaced with integrations to third party software or a mobile app.
The after picture — production code
The production version uses the same 2 models but now uses a framework. Framework consolidated code into just 2 functions and provided a full REST API.
The production version has 50 lines of code.
The production version has 17 tests.
The production version has 3 levels of role based permissions which are now only included in the code twice (once for each model).
The production version is a REST API that can be called from a number of frontend applications
Measuring the improvement
So what sort of benefits do we get from starting over and how can we understand their impacts on our product and organisational security?
Less code can be easier to maintain
It should be pretty simple to see the benefits in terms of maintainability and simplification. We now have much less code to deal with and we even have some tests now.
In our case we used an existing well documented framework to do the heavy lifting. This isn’t cheating.
Using a well maintained framework reduces the cognitive load on your engineers. They don’t have to work through hundreds of lines of custom code as the framework has taken care of that. The remaining code should be simple and context specific.
Let your engineers use their talents to solve your problems for your domain. Don’t waste time on problems that have already been solved and have reached a mature, secure and stable state in common frameworks.
Only provide the functionality you need
Separating and removing the redundant front end features has reduced coupling and means that the application can be delivered in a range of ways without heavy changes to the production code.
From a security perspective this is great. The rule is that if the code is there, if the functionality exists (even if it’s never used) you have to know about it, protect it and monitor it. The easiest way to secure this redundant functionality was to delete it.
Security people will sometimes refer to this as ‘minimising your attack surface” but in short be mean keep it as small and simple as you can and there is less someone can attack.
Don’t code for a rainy day. Don’t build a feature in ‘just in case’ it becomes useful one day. Build as little as possible to get the job done.
Simplified and centralised permissions
Authentication and authorisation are hard to do consistently over complex applications. Reducing the points at which roles are defined means that we can easily identify and control these areas.
Ideally, when you come to change your roles or authorisation, there should be a predictable model to follow. These details should be in a few predictable places for every feature you write.
You should never have to guess where the authentication and authorisation checks should go. It should be a repeatable and intuitive model that places these controls in as few places as possible to achieve maximum coverage.
Be brave, throw it away
While reusing our experimental code is always a temptation for those of us pushed for time and resources, it can be one of the most costly security mistakes we can make.
Taking the brave step of packing your experiments away and re-engineering for your production version can not only make your code smaller and more elegant but it can also make it easier to secure.
Your experiments are a fantastic way to learn fast and validate both your problem space and your skillset but don’t let this code define your approach.
Keep it clean, keep it simple and keep it secure — from your first production code onwards.