Some software developers adhere to prevailing philosophies in books or code, some invent a unique worldview, while others are unsuspecting adopters.

My philosophical influences come from Lean Domain-Driven Design (DDD), Test-Driven Development (TDD), The Agile Software Development Life Cycle (SDLC), Developer Operations (DevOps), and many more.

Here’s my software development philosophy. I’d love to see yours!

People First

People are the purpose of software development. I create a positive environment for people to do their best work.

I create solutions that help everyone.

I positively impact the world.

The field of dreams is a myth; I build software for you, not for myself.

People First

Invest Lightly

I keep it simple when using technology. Technology changes constantly; light and strategic investments provide higher value.

I limit my keystrokes and produce thoughtful architecture to maintain less code.

Invest Lightly

Stay Liquid

I avoid technical debt like COVID.

It’s frighteningly common to witness multi-million-dollar software projects scrapped and rebuilt for millions again.

A mountain of technical debt is no laughing matter; it threatens the longevity of your business. I recommend paying your technical debt now. It’s more often cheaper to pay technical debt than to rewrite software.

Invest Lightly

Everything Changes

When building code, I assume change is coming sooner than expected. I craft easy-to-adjust solutions that economically address new business requirements.

Everything Changes

Simple Security

Simple security is often an oxymoron, but there are solutions.

I create layers to protect data rather than software configuration files and leave configuration files permissive while mostly unchanged to reduce access rule confusion.

I require clients to identify themselves before calling my services. Legacy deprecation is hard enough without a game of whack-a-mole or resorting to scream tests during migration activities.

I often remind myself that the only secure computer is a dead computer, and you better be sure it’s demolished, in the ocean, encased in cement, and buried.


Use the Right Tool

Languages are programming tools that help us craft solutions. I contemplate the appropriate tool for a job and am acutely aware of The Law of Instrument.

In software development, many people use one tool and master it. Specialization is lucrative; some developers will profit from this approach. However, I prefer to follow the 80-20 rule. I learn several tools to unlock full-stack development proficiency.

I’m pragmatic, yet I apply contextual principles.

Be Pragmatic

The Mythical Man-Month

Most believe adding more people will speed up a project. I don’t blame them; it seems like the logical outcome; however, it’s never true on a short timeline.

I’m acutely aware of Brook’s Law. Adding new people to a team will initially slow it down.

I simplify onboarding activities to lower the impact of adding new team members.

Be Pragmatic

Cut With The Grain

I build solutions with an eye for opportunity. If hosting software is cheap with the cloud, do it; otherwise, seek other less expensive solutions.

I skip dogma when allocating resources and dislike inefficient resource allocations.

Build With The Grain Of Opportunity

Measure Then Commit

I loved woodworking as a teenager.

Sacrificing quality at the altar of speed is expected in the software industry.

Scratch that; it’s common everywhere.

Let’s do better.

I don’t mean to build perfect solutions. Measure twice and then commit.

I know everyone makes mistakes, but limiting human errors is critical. When building software, I focus on critical decisions, then fire tracer bullets to determine options. Once documented, I pass a proposal by my team to eliminate blind spots.

I love resolving high-impact problems. I live for this.

Quality Matters

All The Logs In The Forest

If there’s a log, I’ll surface it. When I’m stuck debugging a problem, I never know what log sources might uncover, so I collect them all.

While information is essential, too much information drives me crazy. I appropriately classify logs with DEBUG, INFO, WARN, ERROR, and FATAL.

I implement general-purpose logging with aspect-oriented programming or control planes and move most logging concerns away from the application layer.

All The Logs In The Forest

A Fresh Start

When I dust off a software development tool, I approach it as a newbie. I search for a modern tool and remind myself that my tools may soon be obsolete.

I use principles to guide me rather than knowledge of a tool.

A Fresh Start

Solutions Looking For a Problem

I ask myself a couple of simple questions before building anything.

  • Is this feature valuable?
  • Does this feature solve a significant problem?

If a feature isn’t valuable, I postpone its development.

A Solution Looking For A Problem

Reframe The Problem

I can’t eat a garden with one bite.

When I solve a complex problem, I break it into bite-sized bits. I work methodically to create discrete solutions to simple problems.

I reframe complex problems into cheap educational solutions. Later, I apply bronze, silver, or gold-plated solutions depending on failure impacts.

Use Cases

It’s vital to limit software use cases. A command-line utility’s use cases are easy to restrict, while user interfaces are not. I limit use cases to reduce bugs.

A clear definition of use cases defines a contract between myself and users. I document a use case when people use my software in novel ways.

I create extendable features when developing general-purpose software.

Use Cases

Constraints

If it’s flapping around, I nail it down. I identify and document constraints before writing any code. Defining constraints limits choices and narrows a solution path.

I obsess over resource constraints and costs. Before deploying a software architecture, I review technical limitations and business rules to discover blockers or quality impediments.

I simplify business problems. I regularly validate previously defined constraints. If something changes in my favor, I’ll forge a shorter path.

Software Constraints

Versioning

I version most things. I version software, hardware, and workflows.

I pin package versions and apply the principle: if it’s not broken, don’t fix it.

I update insecure packages proactively.

Major Minor Patch

Naming Things

When naming variables, I name them in ways that make them easy to rename. I call things exactly and avoid overloading or overusing the same variable name.

Two Hard Things In Computer Science

Tracer Bullets

I use tracer bullets to punch a hole in the walls between myself and a solution. I’ll use scattershot shotgun methods to prove use cases, theories, and the viability of a solution before investing time and money in building robust solutions. I’ll pick a requirement far from the final solution and meet it head-on.

Tracer Bullets

There Are No Big Problems

As Henry Ford once said, there are just a lot of minor problems. Breaking down what looks like big problems into manageable problems makes software developers look like wizards. 🧙‍♂️

If I face a complex problem, I solve a minor problem and work from there.

I like to say, “You can’t eat a garden with one bite!”

No Big Problems

Driving Business Value

Everything I build has the end-user requirements placed front and center in my mind. A fancy contract won’t sell more products than a simple one. If I can’t rationalize why a feature provides the highest value at a given time, I’ll raise my hand or change course.

REJ Process Flow

Single Responsibility

I keep software components isolated with a single responsibility and create single-responsibility user interfaces to reduce complexity. I divide tools logically for users and software developers and follow SOLID principles when creating object-oriented software solutions. Many software problems are caused by failing to follow these principles.

SOLID Principles

Take Responsibility

Development Operations (DevOps) has transformed software development. Modern software development practices have greatly benefited from DevOps.

DevOps requires software development teams to take full responsibility for their creations. The DevOps maturity model increases the quality of products and increases the speed of delivery to the market.

I guide team members towards continuous improvement of build pipelines, testing methodologies, and other DevOps best practices.

DevOps Maturity Model

There’s Always A Design

Designing a maintainable, malleable, and easy-to-understand system is of paramount importance. A design always exists. An unplanned design is terrible, but it is still a design. A poor design becomes a massive liability for a company and will slow a development team to a crawl.

I insist on a good design upfront. My primary goals include making a system sufficiently flexible, understandable, and affordable.

Ball Of Mud

Be Empathetic

Empathy for people is a cornerstone of a robust software development philosophy.

I work diligently to understand what people need. I ask why five times to understand the real problems while keeping the big picture in mind.

Be Empathetic

Step Slowly

When solving complex problems, I step slowly through code. I make manageable changes. Slowly stepping through code helps isolate errors and correct them individually.

I don’t cut corners when a path is clear. Quality is more important than speed; speed emerges through grade.

Slow is smooth, smooth is fast. — Bob Martin

Step slowly

Automate Everything

I automate tasks religiously. I consider a different approach if it’s expensive to automate a solution.

Automate Everything

Test For Life

I like focusing on solving problems. Without robust integration tests, unit tests, and other tests, we spend time creating problems for ourselves.

I write tests because manually running an app after every change is tedious.

An automated test suite helps me sleep at night. Time spent coding without testing increases the time spent working on bugs, investigating production issues, and troubleshooting broken builds. I prevent future pain by testing; therefore, I test for life.

Test For Life

Exceptions Are The Exception

I write code to avoid mistakes. Instead of throwing exceptions in the name of defensive programming, I change software designs to prevent thrown exceptions. After all, users depend on software to work and simplify their life; let’s keep it simple.

However, I bubble up exceptions with maximum traceability when required.

I implement messaging patterns, isolate control of resources, and identify other creative ways to avoid errors before throwing exceptions.

Exceptions Are The Exception

Decouple Everything

I refactor tightly coupled code to reduce complexity and prepare it for change. When tight couplings exist for no good reason, I decouple them.

I summarily dismiss software libraries that aren’t dependency injection-ready.

I ask myself five times why I’m coupling code before committing to tight coupling.

Decouple Everything

No Perfect Solutions

Picking the best solution, at the moment, with all the facts laid out, is the way to avoid analysis paralysis.

I don’t believe in the Nirvana fallacy and make the best decision possible at The Last Responsible Moment, yet at the same time, I take big architectural choices very seriously.

Solutions can’t be fast, cheap, and good simultaneously, yet I strive for the right balance based on functional requirements.

Fast Cheap Good

Conway’s Law Is True

Conway’s Law states that the organization’s communication structure influences a system design.

Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.

— Melvin E. Conway

If communication flows are complex, so are systems.

I inspect organizational information flow to understand its procedures. If the flow could be more efficient, I propose a better solution.

Open Source is Life

I make use of open-source software whenever possible. I ensure the open-source software I use is well maintained and make safe bets on a project’s longevity. I’ll contribute to a project if it aligns with my development needs and enjoy the synergies that open-source software development models provide to businesses and developers.

Open Source

Can != Should

The software development world has many tools, methods, design patterns, and best practices. Frequently choice overload leads software developers to believe one tool can rule them all. 💍

Picking the wrong tools to solve your problem leads to technical debt and wasted time. Before tackling a problem, I will research the standard methods and choose the best tools for a specific situation.

Can Not Equal To Should

Confusion Is Painful

Software development is overly complicated as-is. I follow the principle of least astonishment.

If I forge an unconventional path, I prepare a steelman argument, keep it simple, and document why.

I keep my variables consistent, methods clear, and configuration files clean, and I make sound choices to eliminate inconsistencies.

Inconsistency is an enemy of excellent software design.

Confusion Is Painful

Pair Programming FTW

I enjoy a productive pair programming session. I love sharing my hard-earned wisdom. Programming in the modern age is a self-induced chaos test meant to push my ability to understand EVERYTHING to the limit. When I help someone avoid the pain I’ve experienced, it brings me joy.

Another pair of eyes will make code easier to maintain and lower the total cost of ownership. Pair programming, when done right, will level up your team while turning it into a high-performing powerhouse.

Pair Programming FTW

A Software Development Philosophy Evolves

My software development philosophy is evergreen. It changes after learning new things. This list contains a small fraction of my overall development philosophy. As always, a great magician only reveals some of their tricks.

Gandalf

I refine my software development philosophy regularly in the spirit of continuous improvement.

Develop your philosophy

Here are a few books to help you develop your software development philosophy.