Building and Testing Code: Weeding Out the Complexity

    Code Is Not Magic

    Arthur Clarke once wrote, “Any sufficiently advanced technology is indistinguishable from magic.” Code is not magic.

    Software is, in fact, pretty simple. The same basic commands and concepts since the beginning. Declarations. If statements. While loops. Simple instructions that make computers do what you want them to.

    Declare that a variable exists, and give it a value. Check to see if something is true, if it is, go in one door, if not, go in another. And while a variable holds true, run loops instructions over and over until something changes or you run out of data to sort. It’s just a game of dominoes, where the pieces are arranged to fall in a certain way when struck. (Did you know Boole’s paper on logic was published in 1847, making published Boolean Logic about 100 years old by the time it was adopted for computing?)

    Now, code isn’t inherently complicated, but it’s written by people. And people tend to be complex. We have different goals and different aversions. We don’t always do the best job of showing our work, communicating intent, or documenting any of our thought processes… and so the code gets to be complicated. And we end up with a slew of different approaches to the simple question of “How do we make the computer do what we want it to do?”

    These approaches manifest themselves in the form of different software languages. This all has added to the perceived complexity of it all. Some people like to tell computers what to do in Java, some like to tell computers what to do in PHP, others prefer Objective-C. They all have pros and cons, some had enough following to stand the test of time, and some were just fads designed to solve one specific issue. The longer you work in the industry, the more you’ll see that diversity is the spice of life.

    Languages for Diversity, Frameworks to Accelerate, Standards to Align

    Languages are just like, well languages. Each country has its own.  Sometimes a smaller, or newer, country adopts the language from a larger, or more established neighbor. Languages on their own are wide open, offering freedom to choose just about any way you want to do anything. Freedom is good, until it’s too much. And early on, people had to choose on their own how they were going to handle basic things like garbage collection, database connections, and routes. This made it really hard for a software developer to go from one company to the next, as each company—even those using the same language—did things their own way, and so much of what each software developer knew was relevant only to their role at one company. It also meant that all of these decisions had to be painstakingly debated, and documented, for every project.

    Frameworks help accelerate development by making a bunch of choices upfront. They hand the developer a bunch of pre-built basics that, in theory, every project needs. So frameworks can be thought of as a regional accent on the language, if you will—complete with slang and idioms. React, Vue, and Angular are all frameworks based on JavaScript, and are recognizable as JavaScript, but they’re all just a little different. At the end of the day, we don’t really care, just pick one and build… all you have to do is find a language and framework that your team can align on. Oh and maybe write a few best practice coding standards so everyone can stay on the same page. Easy.

    (A quick note on coding standards: so many teams skimp out on coding standards, and there’s no reason to. Most languages, and most frameworks, have a plethora of pre-defined coding best practices you can adopt for your project. It is hugely beneficial to align with these practices as it makes it easier to not only copy and paste the code from one file to another, but also to make your functions play nicer with each other. Early on, one of the best things a manager can do is ensure the team isn’t expected to just start writing code on day one… give them plenty of time to make these decisions—you’ll thank yourself down the road.)

    Also, something else to think about, if you have a minute: Ideally, your decision won’t require a separate team to support modern vs. legacy systems, or any of your current or future integrations. Will legal be OK with the licenses you are bringing into your project? Hopefully, the language and framework you pick will have both momentum and sponsors behind them so they’ll stay current and your team will be able to find new developers in the future. And… lastly, is that framework a truly good fit? It’s a bit of a Goldilocks situation: does it have enough features and well-maintained libraries, or does it over-prescribe the code to the point where you’re swatting mosquitoes with bazookas? These decisions aren’t just technical, they are decisions that require business alignment to get right.

    Platforms to Accelerate

    Are you trying to build something that someone else has already built? Great, that can really simplify things for you. You can have a lot of the language, framework, or what feature library questions if you want to skip to just picking a platform. Now, a platform is a pre-built piece of code designed to do something, and you can leverage their efforts by either paying them, or finding an open-source platform to accelerate your build.

    Need an eCommerce platform? There’s hybris, Demandware, Magento, Shopify—your choices there range from super complex platforms that can do anything with the right modifications, to basically just “pick one of our default color themes.” Need a brochure site? There’s AEM, Sitecore, WordPress, Drupal, HubSpot, Wix…about a million others, a similar range of options, from highly customizable to rigidly prescribed.

    Platforms can be great, but there are a few things to watch out for. First, a platform can make a very junior dev seem like they know a lot. So you ask your developer, Joey, to build you an eCommerce platform and he clicks a few buttons (following a setup script) and presto you’ve got Magento installed. And you ask him to change the colors, and he can do all that with ease. Then you ask him to change the checkout workflow… and Joey’s got a bit of confidence from winning the last two tasks, so he boldly marches in and hacks the core  to make it do what you want.

    And at first, you’re OK with it because everything seems to work OK and it’s doing what you want. But a few months go by, and then there’s a security patch. And it won’t apply right. And Joey didn’t bother setting up test environments, or automated backups correctly, doesn’t have a containerized deployment workflow, and all the other bells and whistles designed to help you keep things running smoothly… and all of a sudden you’re in a world of hurt. Similar issues… by modifying the core, you can open your site up to additional vulnerabilities, you can decrease performance, make it impossible to do version upgrades, and so on. And your platform has gone from jumping-off point, to a brick wall, slowing all progress.

    Luckily a lot of platforms come with tests to verify the integrity of their “core” files, and often unit tests, and even front-end tests for things like the admin tools. Always aim for testing code in ways you can inherit from the platform, and always work to keep the platform as upgradeable as possible. Platforms make a lot of choices for you, and often come with a wide selection of extensions for easier customization and integration—and that makes them faster to set up, but it means you have to play by their rules, code conventions, and often won’t have all the developers on-hand (at least not the same way you would if you build everything in-house) who know how to fix everything when something goes wrong.

    Turning Human Logic into Code is Complex

    So back to basics. It’s all so simple when you start. Except there are always exceptions and edge cases, and all sorts of business logic that have to be taught to the computer so it can carry out the right actions. Think of something as “simple” as calculating the days since your last birthday. Easy? You’d set up a function and tell the computer to count back from today’s date, one day at a time, until it got to your birthday. More or less? Except, what about time zones, leap years, and those pesky calendar changes  that have happened from time to time? Computers are simple, but we bring a lot of complexity from our world with us.

    And code is always changing, growing. And there are teams of people involved. And, after every change, we need to be testing code to make sure it’s still working. And we need to track all the changes in case we ever need to roll back some changes. So we need a shared repository to allow multiple developers to contribute, and explore how to fix bugs or make improvements without corrupting the master set of files. Think of how complicated it is to manage just one PowerPoint file via email, “Do you have the latest, does Maria? Is the correct one Presentation-FINAL.pptx in the email sent on Wednesday, or Presentation-FINAL.pptx sent on Friday? Or is it Presentation-FINAL-3-JoeEdits.pptx? Or is there a new one?” And there are millions of lines of code spread across thousands of files.

    Is your software this complex? Don’t worry, software can help!

    Repositories to Help Organize, and to Ctrl-Z When Needed

    Code will always evolve. Every time we factor in evolving requirements, or optimizations, or attempt to make it all more reusable, our code changes. Over time, software repositories, like Git, let us organize and track versions of files over time, and group specific versions of specific files to be a release. This allows us to cleanly deploy the exact same files to different computers as needed. We can roll files back and, assuming we take regular backups of the database, we can revert everything to how it was at any given point in time. This enables teams to confidently move fast and break things. Whatever we do, there’s always an undo button. And always a way to see who has contributed and who hasn’t.

    Using a code repository, every developer can have their own feature branch, so every edit they make can be spun up on a test server that you can then run regression tests against before merging the code back into the production branch ready for release to your customers. Using this method, all code* is tested and goes through a thorough peer review to make sure it’s stylistically consistent and matches coding standards set by the team.*

    Open-Source Software, Re-Use, and Transparency

    And the best thing about languages, frameworks, and libraries, all stored in repositories, is that they are so easy to share. Developers love adding their own flavor and reinventing wheels, they also hate to solve the same problem twice. The power of leveraging open-source software is that you can move so quickly, you can rapidly accelerate your time to market by leveraging tried and true and tested software as part of your own application. You have access to the source code, you can review it, modify it, fix bugs, post those changes back. And you can leverage these changes others have made to extend your own functionality or help keep your application more secure.

    Think of how prevalent software is, and how it’s in cars, trains, and planes. Since virtually every car on the road has an anti-lock braking system, you can’t even press the brake of your car without software being called. The car weighs the instruction to apply the breaks for each wheel against tire traction sensor data, and makes a decision on what to do—and it makes this decision faster than you could react if you lost traction on an icy road. But every time you get into a car, you’re now entrusting your life, and your passengers’ lives, to the software. Thousands upon thousands of lines of code. Do you know who’s reviewed that software, or if it needs to be updated? Do you know if it’s secure or been tampered with? Do you know how it’s going to make decisions for you in a pinch?

    Physically, cars are well tested, but if we just test outcomes and ignore the code it’s not always possible to find all the bugs—especially if the bugs were intentionally put there. For that matter, we have no way of knowing if the code shipped with a mischievous if statement in the mix, “Apply brake, unless it’s Friday the 13th, 2019 at 1:13 PM.” A bug or hack like this would be hard to test, hard to reproduce, without looking at the actual code. We put a lot of trust in software to be written correctly and securely. Often without a lot of checks and balances.

    Apple got in a lot of hot water for the way they designed their iOS software to account for phone battery health. Apple intentionally slowed the performance of their phones in an attempt to help older batteries last more hours each day—a choice they made for users without telling users they had made it. While likely a smart move, the decision lacked the informed consent of the users, and the backlash was severe andthe remedy was expensive. If your organization relies on closed-source tools, how many decisions are made for you, and more troublesome, how many decisions are made for you by software that doesn’t let you know the decisions have already been made?

    When starting a new project, do you want to have to build out a series of tests to validate someone’s work, or do you want them to give you the source for testing code and test automation they’ve already completed for your starting point? There’s something to be said for an SLA, but there’s something to be said for having full access to the code, and inheriting patches and improvements made by other teams.

    There’s always going to be a balance between proprietary information, intellectual property, and transparency. You have to find a path for your organization, but keep in mind that open-source will generally enable your organization to be more trustworthy, secure, responsive, and deliver more feature-rich capabilities than trying to build from scratch. And you can leverage a support network of other developers to help keep you secure into the future. The more people who use the tools, the better they will all become for everyone.

    *All code, +/- 100% accuracy. Your team candefine workflows that work best for your organization. URL: