The elephant on every screen across the world
Software quality is degrading and I think we all know it
Working in software development and cyber security at the same time has allowed me to have several unique views into the software space. I get to see both insecure software patterns and practices from the security analyst’s perspective, as well as some of the reasons that software ends up in this deeply flawed state.
Over the last week, I’ve written several blogs on software quality and why it is, frankly, shit:
It’s a subject I’m fairly passionate about, and one that more or less affects all of us, especially those of us that are… unfortunately Extremely Online. Whether it be glaring security issues, bugs, horrible UI/UX experiences or a combination of all of the above, one cannot shake the feeling that software is getting worse.
I speak frequently about how constantly I stand upon the shoulders of giants. This blog is written upon their backs. I’ll be frequently citing greats like Jonathan Blow, Casey Muratori, Ryan Fleury and John Carmack in this article, and to them goes the recognition.
I - The Giants and Their History
It will not likely come as a surprise to you that things were both more difficult, yet simpler in the days of yore.
On Lex Fridman’s podcast, John Carmack talks about building massive games like Quake and Doom essentially from scratch using C and Assembly, a far cry from the bloated engineware games that make up most triple-A titles in the gaming scene now.
A bigger name in the modern from-scratch software scene is Casey Muratori, who, alongside Ryan Fleury, have built a burgeoning community dubbed the Handmade network that strives to build better software by pushing the bounds of DIY and building things from absolute scratch. Ryan has an awesome blog post with a game dev focused reasoning why he believes in the from-scratch movement.
All of that is to say that the world of ridiculous dependency-hell is a relatively recent one. The software development space is still made up of plenty of system’s programmers who started building things from scratch, or who are doing so still, because they see the flaws in the constant dependence on engines, frameworks and libraries.
Many of them take issue with the pitfalls of trusting third-party code, either from a centralization perspective or from a security perspective. A lot of them simply have issues with inefficiencies and problems with ease of use. Jonathan Blow gave a great talk in Russia on the matter, and gave plenty of examples of modern software with horrible problems.
II - Possible Explanations
There are a multitude of reasons we are in the spot we are in today. Let’s address the obvious first: nobody wants to constantly have to reinvent the wheel, unless of course you’re the type who does enjoy that, like the aforementioned Handmade network.
Building sites and web apps that are “up to snuff” compared to those you will be competing against completely “from scratch” is a mountain of a problem to deal with. Building a modern, reactive web application with, say, vanilla JavaScript, HTML and CSS, without using any frameworks, is absolutely possible but the time it takes will often mean by the time your development cycle ends, you’re already months or years behind your competition.
And that is what ultimately causes a lot of the problems we see today: time.
The dependency hell is often entirely caused by tight deadlines and a focus on shortening development time without much attention paid to the costs. Sometimes this is simply a patience issue, but more often it’s fiscal.
Hell, I’ll use myself as an example: I’m developing a small web application called How’s My Pass. As part of the front-end development, I wanted to include a couple of social links in the form of icons representing my Twitter, the GitHub page, etc. Now, this is a pretty trivial problem to solve: it’s a matter of finding the SVG’s for the icons, sizing them properly and embedding the right links.
But, just like most developers, I’m lazy and I don’t want to take the time to do all of that… so what did I do?
I found an NPM package that handles the majority of that for me.
That sounds insane, trusting a third-party library just to embed some simple images in my front end, but it’s an incredibly common approach. The most-often cited example of this is an NPM package that simply checks to see if a number is even or odd, an operation that takes one small line of code using a modulo (%) sign.
This package receives over 170,000 downloads per week.
Time is the most common explanation, but it isn’t the only one. Many developers simply want to abstract away difficult problems. The Python Requests library is a great example of this: I could build out a much lower level implementation of the http library using Python to make simple HTTP web requests, or I could use the requests library, which abstracts away a lot of the implementation of the HTTP protocol for me.
After all, if you’re constantly re-hashing low-level details, this often takes away your attention from what you want your code to do. I want to build efficient web scrapers, not an HTTP library wrapper.
Programming languages like Python themselves are abstractions from machine code. You could technically write just about anything in pure Assembly if you have some kind of masochistic streak, but who really wants to do that?
Finally, there is convenience, which really is just a combination of the reasons of abstraction and time. It’s simply difficult to learn all of the things you need to know to write things from scratch with as few dependencies as possible. It’s frankly more convenient to implement social icons with an NPM package. The code is technically more readable (as long as the reviewer isn’t also having to review all of your dependencies) and I don’t have to worry about CSS sizing properties and coloring SVG’s.
So, I’ve given you plenty of excuses… let’s talk solutions.
IV - Possible (Partial) Solutions
Am I going to ask you to write your blog/CMS stack from scratch, then?
No. I actually just switched mine over from Webflow to Ghost, so I’m not going to be rewriting mine at all any time soon, much less doing so in vanilla JavaScript.
We don’t need people trying to rewrite the wheel at every turn, especially on critical components governing security and encryption. Nobody wants to visit a site that rolled their own SSL.
What we do need to do is build a deeper understanding of the technologies that underlie the systems we are building, and we need to take an approach of minimizing dependencies as much as humanly possible. We need to have less “is there an NPM library for this?” and more “do I need an NPM library for this?”
When we do implement third-party libraries and dependencies, we need to actually audit them. The current joke in security is that open-source is only more secure if more people actually review the source code available to them. As the past has shown, this “joke” is anything but.
In security, we apply a zero-trust, adversarial approach to software and security. This “assume breach” type of mindset can be hugely valuable when applied to software: when you implement a third-party library or use a framework you didn’t build yourself, assume it is insecure and do as much due-diligence work as possible to prove otherwise.
Finally, we need to fight back against the convenience, time- and cost-saving mindset that currently governs software development. Will taking this hesitant mindset toward third-party code make development cycles take longer? Of course. Will it improve security and stability? I think so.
We have to slow down and take a good long look at the software we are building and decide if it is truly necessary to prioritize profit and convenience over security and stability. For my part, I’ll be doing this wherever possible…
… even if it means writing more CSS.