Day 12: Death To The Monolith

How many times have we seen it, where an application does HR, payroll, shipping, billing, makes coffee, sweeps the floors, etc.? Too many times to count for me. The truth is that applications like this, these monoliths, are too large for their own good. Development becomes difficult or impossible, and understanding them is usually relegated to the most experienced developers on the team. This leads us to our twelfth and final principle: modern applications are laser-focused on their specific business case.

The title of this post might lead some to conclude that I am directly endorsing microservices as a solution to problems with application development. That would be an inaccurate reading of my intent. Microservices are great in certain situations, but they don’t apply in each and every one. Let’s explore this a bit.

Microservices are narrowly tailored applications that serve a singular purpose. Think authentication, or sending out an invoice, or adding a person to a directory.

By contrast, the applications I am endorsing are compact monoliths: they do more than one function, and they are as large or small as they need to be to accomplish that specific function. They may or may not talk to other applications via an API (I recommend that they do), and they may or may not allow incoming API requests (again, I recommend that they do). Rather than simply handling authentication an application might authenticate a user, allow adding that user to the company directory, and permit storing information about that user. This is more tasks than a typical microservice.

What I am advocating we avoid is the large monolith, an application so big that it bloats and becomes unwieldy. An application that large is often unmaintainable. It’s often untested. If it is tested the tests are bogged down with extensive functional and acceptance tests that require more time to run than the developers are willing to wait. The experts on the application are usually the people who have been there the longest, and I don’t have enough fingers to count how many times that has been a single person. What happens if that person is sick, or wins the lottery and never comes back into the office?

Monoliths present deployment challenges, too. They’re difficult to build automatically (see lack of testing, above). And they’re difficult to deploy, meaning the deployment cycle is often very slow. Developers are often scared to deploy a monolith so they don’t; this only delays the inevitable, and the longer you go between deploys, the greater chance of bit rot. Bit rot happens because things left unattended always unravel, memories become spotty, and developers lose sight of what they learned in the past and must relearn it. All of this leads to poor business outcomes.

If your platform is customer facing and you have a huge monolith, this presents an incredible challenge, too. First, you’re unlikely to deliver the latest in features and benefits to your customers, and they may go elsewhere. Second, when you do deploy you’re more likely to ship bugs along with the new features, and these bugs may not be corrected for many days or weeks if your deployment process is slow. You may find yourself faced with challenging decisions to roll back or fix in place, which is a decision no CTO wants to make.

Smaller applications, even if they are monolithic in nature, typically don’t suffer from these problems. The reason why is that they are easier to test, simpler to deploy, faster to fix, smaller to understand and quicker to be fixed in place if problems are discovered. APIs allow the applications to communicate across clearly defined boundaries, ensuring that you get the benefits of microservices without the hassle of deploying dozens of services just to achieve one task.

So embrace the compact monolith. Shun the large monolith. Your applications will be better for it, and so will your application development process.

Thursday, January 7th, 2021 @ 9:48 am | Comments (0) | Categories: Business, Development

Day 11: Your Development Environment Matters

We’ve all been there: staring down a new project with 14 steps to set up the development environment, and step 2 breaks. We spend hours debugging, only to be told by a senior engineer, “oh, yeah, the docs are out of date, here’s new instructions”. You try the new instructions, which are also broken, and are finally told “oh, there’s a trick, see…” This frustration brings us to our eleventh principle: modern applications must be easy to develop.

Modern applications should have simple, straightforward development environments in order to facilitate easy developer access and onboarding. A complex setup for a development environment, or one that takes days to master, leads to frustration and disgust before a developer has even written a single line of code.

By having an easy-to-use development environment, companies can ensure their developers are always working on the most modern instance of the code base, and make certain that developers are focused on developing, not maintaining an ancient and fragile development architecture.

Containerization, Vagrant and others have made this process easy and simple. Taking the time to invest in these tools might seem like a waste, but will speed developer productivity, make testing simpler, and reduce the number of bugs making it into production. It requires a hard look at the actual architecture of the application and, often, a simplification of that architecture.

Development environments aren’t sexy topics, but they are critically important for developing and deploying code that runs, and runs well. Invest in them. Make them simple. Make them easy to use.

Tuesday, January 5th, 2021 @ 9:31 am | Comments (0) | Categories: Development

Day 10: Balancing Business And Development Priorities

If you asked a development team about an application, specifically asking how that application should be developed, they would probably tell you that the application should be developed to be as easily maintainable as possible. If you asked the business analysts the same question, they’d probably say that an application must serve the business needs exclusively, and that features should be packed on as fast as possible in order to meet those business needs. Who is right?

Turns out they’re both wrong. This leads us to our tenth principle: modern applications must be oriented to the developer, but focused on the business.

You’re probably thinking, “well that makes no sense.” Let’s break this down a bit.

What does it mean to be oriented to the developer? It means giving developers time to make the project easy to maintain and build. It means ensuring that developers have the ability to make changes and improvements independently of the feature cadence, so that the project doesn’t die from technical debt or abuse. It means giving developers the time they need to experiment with new technologies that might make the project run better or more efficiently.

Focusing on the business means giving the business what it needs to do business, and be effective. It means prioritizing features to a degree, and ensuring that necessary or critical features are not backlogged by bureaucracy or red tape. It means ensuring that the business needs are met, as a high or the highest priority.

How do you balance these things?

To orient to developers while focusing on the business, you must leave space for both needs and allow both needs to be accomplished. For example, most businesses love to maximize their story points in a given week; they want to make sure feature development moves ahead at full speed. But a forward-thinking business will leave 25% to 50% of a developer’s schedule unfilled. This number might seem really high at first but consider: bugs are not considered stories but must be fixed. And for any enhancements or improvements to be made outside the system of story points, user stories and feature requests, developers need time.

For their part, businesses would do well to ensure developers understand the business needs –  not just from a “here’s what the business needs” perspective but from a strategic, big picture perspective. Developers like to be involved, and they can assist much more effectively if they have the big picture.

This is really a long way of saying that business and development need to balance each other’s needs, prioritizing one thing some of the time, and another thing other times. This careful balancing act never ends, and both teams should meet regularly to ensure the balance is correct and that the business (and application) are moving forward at the right pace. This balance will achieve great results for your team, but only if you let it.

Monday, January 4th, 2021 @ 8:45 am | Comments (0) | Categories: Business, Development

Day 9: The Business Of Application Development

So far we have focused on the technical elements of application development, and the development processes needed to effectively manage a modern application. But what about the business side? After all, all of us are employed to write applications professionally (or such is the goal, anyway). Open source is one thing, but application development for a business is quite another. This brings us to our ninth principle: modern applications must be easily changeable to meet current business needs.

It might seem that this goes without saying, but there is very real risk here. Application development that is done for the sake of application development is dangerous to a business, because it doesn’t take into account the needs of the business. Applications that are constructed in rigid, inflexible ways are dangerous, too, because business needs change and the application must change with them.

Building applications capable of changing is hard. Most applications are built against a specific set of specifications, and changing the application is difficult. No one expects an application to go from a piece of accounting software to an inventory management system; that would be unreasonable. But applications should be capable of changing to meet the changing needs of a business within their scope. For example, accounting software should be capable of tracking specific payees for reporting purposes; adding this functionality should neither be difficult nor time-consuming.

This is not to say you should future-proof your application so much so that it becomes unwieldy or unusable. For example, asserting that the company might switch from MySQL to Postgres is a silly proposition; if such a switch is demanded, this would typically be out of the normal scope of understanding and the business would need to recognize that significant investments would be required. But as a developer, you have both a responsibility and an obligation to know up front what the next six months to a year of initiatives will be in your business, and to be prepared to embrace and support them. If you don’t know what the next six to twelve months will bring, ask.

Applications that are inflexible or difficult to modify eventually get worked around, and then discarded. Businesses often take the path of least resistance to solving particular problems, and if an application stands in the way, it will be discarded.

When developing your application, consider whether or not the application can be easily modified to meet the changing and expected business needs of the future. You should not engage in mind-reading, but you should have a reasonable understanding of what the business needs are, and what is coming from the future. Embrace the future changes that will be required, and ask yourself if your application can support those changes. Solving for the future will ultimately help you in the long run.

Saturday, January 2nd, 2021 @ 9:00 am | Comments (0) | Categories: Business

Day 8: Development Culture Matters, Too

What does culture have to do with modern applications? Plenty. Developers under stress produce worse applications, and those applications go on to be legacy applications. That’s why principle seven is modern applications must engage in cultural best practices.

Culture matters. Developers in environments that are welcoming and inclusive fare far better than developers who are worked to the bone in spartan environments. Developers who are under stress produce far worse code than developers who can take their time. This isn’t a pronouncement without fact: the reality is that everybody works better when stress is absent from the environment.

Developers also need access to certain tools to do their job. Shops that want to develop good culture should also develop best practices around use of a bug tracker, version control, change management processes, scoping, design, and business analysis. Developers should be involved in the creative aspects of the development process as well as the technical elements. Businesses should track bugs, use version control and offer reasonable practices like Agile to ensure developers can perform at peak efficiency while still having input into the day-to-day.

What do you do if you find your culture is lacking when it comes to developing terrific applications? Start small. Implement a small process change, like a bug tracker, and get everyone on board. Sweeping changes won’t stick when you come down to the wire, so make sure any change you make is small and focused; it has the best chance of sticking around.

Culture matters for modern application development, and goes far beyond free sodas and foosball tables. It focuses on how developers and others work, the environment they work in, and the attitude and behavior of those they work with. A great culture will improve the odds of producing a great application.

Friday, January 1st, 2021 @ 9:00 am | Comments (0) | Categories: Culture

Day 7: Run Your Tests Early And Often

In the first principle, we discussed the importance of having tests in order to validate your code and prevent bugs. In this principle, we explore how to apply those tests on a regular basis through continuous integration. Principle seven is modern applications must use continuous integration.

It might seem obvious and self-explanatory that modern applications use continuous integration. After all, building your project after each commit is the simplest way to run the tests and verify the application. But there are thousands of development shops that lack tests, continuous integration, or both. Why? Most of the time because it’s “too hard to set up” or “too expensive to run.” Neither is a good excuse, and both can be debunked.

Continuous integration can be relatively simple to set up. With GitHub releasing GitHub Actions, continuous integration and running your tests on every commit has never been easier. If you’re not using GitHub but using something like GitLab, you can use their built-in tools as well. And if you’re old school, Jenkins is a better-than-nothing solution you can set up and host on premises for your own purposes.

In terms of cost, there is often a cost associated with running continuous integration. However, this cost is minimal compared to the cost of releasing bugs into production or a broken component making it past QA because nobody ran the tests. It’s best to consider it part of the cost of doing business and accept the cost.

I want to make an important distinction here: continuous integration is not the same thing as continuous deployment. A successful application build does not need to be deployed to production to follow this principle; in fact, you can still have any release cycle you like. Some companies choose to release every build. Others choose to release one a week or every other day. Our sixth principle (yesterday) stated that applications should be deployed often, but deployment cadence is entirely up to you. What’s important is that you consistently build your application so that the tests are run and bugs are discovered early, and often.

Thursday, December 31st, 2020 @ 9:00 am | Comments (0) | Categories: Deployment, Testing

Day 6: It’s Friday Afternoon; Is Your Code Deployed Yet?

It might seem insane for a team to deploy on a Friday afternoon, at least if they want to enjoy their weekend. But for teams that deploy modern applications, Friday is just another day of the week. This brings us to our sixth principle: modern applications must deploy often and easily.

Ask ten dev shops what their deployment process is, and you’ll get ten different answers. In eight of them, the deployment process will be somewhat to very manual. This means that in those shops, deploying code requires human intervention, often direct human intervention. This presents a problem: the deployment process is only as solid as the person doing the deployment.

To make matters worse, if you asked those shops, 75% of them would tell you that one or two people do the deployment every single time, meaning there’s a high “bus factor” in the event that one of those people is sick or wins the lottery and decides never to return to their job. When only one or two people know how to do a deployment, the business runs the risk of having to reinvent the wheel if those people leave.

What about the other two shops I mentioned, the ones who didn’t say their process involved manual steps? They’ve taken steps to automate the deployment process and make it automatic, so that any developer can kick it off, no questions asked. Maybe it’s a Big Red Button. Maybe it’s a simple bash script. Maybe it’s driven by the continuous integration server (more on that tomorrow). Whatever the process, those shops have taken time to automate the process.

What happens when you automate the process? Two things: first, you reduce the “bus factor” by allowing anyone to do the deployment. Second, you dramatically simplify the deployment process, because complexity and automation are antithetical to each other. What results is a simplified, straightforward process that can be run by anyone from management to junior developer.

Modern applications embrace this kind of setup because the developers know it produces higher quality applications that can be deployed faster and with greater ease. But to get to this point requires application of all the techniques mentioned up to this point: dependency and language version management, testing, static analysis to find bugs, and more. Once these tools are in place, developing an automated system for deploying, and having the ability to safely deploy any time becomes possible. This is the holy grail: the ability to deploy any time, anywhere, without fear.

Even on Friday.

Wednesday, December 30th, 2020 @ 9:00 am | Comments (0) | Categories: Deployment

Day 5: Debug Code Without Running It

In the old days, PHP applications were written in a loop: make a change, hit refresh in the browser, manually test, find a bug, fix the bug, and repeat. Thankfully, there’s been a tremendous evolution in PHP over the past decade, and we have quality assurance tools like PHPUnit. But in the last few years we’ve gained quality tooling that some thought would never be possible: static analysis. Which brings us to our fifth point: modern applications should use tools like static analysis for quality assurance.

PHP 7 brought about a component in PHP known as the abstract syntax tree (AST). The AST is basically a tree of all the commands in your code, that PHP uses to tokenize and execute your application. When exposed to the outside world, it can be examined, and evaluated, for errors in the code. This is effectively what static code analyzers like Psalm and PHPStan do – evaluate the code for errors.

The types of errors that can be detected are numerous, but are mainly focused on type errors, logic errors and other similar types of errors. The benefits are numerous: you can quickly identify potential and actual bugs in your code, no matter how old or legacy the code base, in an instant.

The first time you run one of these tools against your code you’re liable to receive a significant amount of feedback. Don’t fret; this is normal. Especially if your project is legacy, there’s a good chance there are plenty of bugs that haven’t been found yet, especially if you lack tests. But knowledge is power; once you know, you can go about fixing the bugs you encounter.

You can check out PHPStan at https://phpstan.org/ and Psalm at https://psalm.dev/

Tuesday, December 29th, 2020 @ 9:00 am | Comments (0) | Categories: Testing

Day 4: Continuous Improvement

It might seem strange to constantly improve an application you spent a ton of time improving, but the reality is that modern apps require constant revision and improvement. This brings us to our fourth principle: modern applications must be consistently refactored.

Let’s talk a bit about what refactoring is. Refactoring is the process of restructuring the code without changing the behavior or functionality. Essentially it’s improvement, without functional change. This is important, because sometimes people confuse refactoring with rewriting. Rewriting is different: you change the behavior or functionality when you rewrite. Refactoring simply restructures the code so it’s cleaner, more efficient, or better in some way.

Why would you want to refactor code that you spent painstaking hours perfecting in the first place? The simplest answer is this: because you get better at programming every day you practice it. Code “perfected” six months or a year ago may be out of date with current best practices, and certainly can benefit from the experience you gained over that period of time. You may also discover through trial and error that code you thought was “perfect” is a performance bottleneck, or is challenging to maintain, and should be refactored for ease of maintenance.

This constant practice of refactoring and maintaining code means building in time with your estimates and constantly working to make the project better. If you have a boss that doesn’t permit time for refactoring (I’ve had several) don’t fret: simply build the time into your next estimate and execute your plan without mentioning it. This isn’t nefarious: your job is to make the code better and to meet the needs of the business, and refactoring is part of that responsibility.

Modern applications are undergoing constant revision, from refactoring and improvement.

Monday, December 28th, 2020 @ 9:25 am | Comments (0) | Categories: Refactoring

Day 3: Upgrade That Language!

Along with package upgrades, it’s crucial that developers have plans in place for upgrading the languages they use. This is the third principle: modern applications must have an upgrade plan for the underlying language(s) used.

 For PHP developers, this often means upgrading your PHP language when a new version comes out. This is not just a theoretical argument; PHP regularly takes old versions out of support around the time of new releases. To receive bug and security fixes, developers must upgrade to a newer version of PHP, often within three years of the last upgrade.

This can be incredibly painful for large or cumbersome applications, especially those without tests (which is why modern applications must have tests). I have had the opportunity to migrate tens of thousands of lines of PHP code from one version to another, and I can personally tell you the struggles and uncertainty that come with this process. This makes having a plan essential: without a plan, the migration never happens, and becomes that much harder in future versions.

Having tests significantly helps in this area, because tests can often tell you what is broken before you discover it yourself. But if your application lacks tests, and you have to do manual testing, expect the upgrade from one version of PHP to another to take 1/3rd of your time doing the upgrade, and 2/3rds manually testing the changes.

But whatever you do, make sure you upgrade. Being on a supported version of PHP is so much easier and better for your application, not to mention your security and performance.

Sunday, December 27th, 2020 @ 9:00 am | Comment (1) | Categories: PHP

« Older Entries

Copyright © 2022 by Brandon Savage. All rights reserved.