6

Software development techniques exist to solve problems. I think a key problem we face is conquering complexity. Also, software developers must often classify and understand complex systems, separating accidental complexity from essential complexity. I believe that sufficiently useful definitions of these terms all exist on Wikipedia.

My question is: What techniques are most valuable in conquering complexity, as a professional software developer, and/or software architect?

Answer examplar; a blog post on conquering complexity that seems to be coming at things from a java/c++/OOP centric perspective.

5 Answers 5

7

YAGNI. The best way to avoid accidental complexity is to stop making stuff more generic and flexible than they have to be.

For instance, don't start looking for frameworks and libraries until you actually know that you need them. Instead of solving todays problems, we spend time thinking up potential problems that might arise in the future. Don't do that. Focus on today.

2
  • 2
    I've bee thinking about this for about a week, and I really think this is the most obvious, and correct answer. A lot of accidental complexity gets in BECAUSE WE PUT IT IN THERE. So, sometimes, ya gotta just stop doing that. :-)
    – Warren P
    May 2, 2011 at 19:36
  • I think this comes with experience. After you've written your own failed framework and used other frameworks eventually you realise you can just use some off the shelf components. The key indicator you're adding complexity is if you find yourself writing a lot of code in preparation for solving the actual business problem (assuming it's business stuff you're writing..)
    – John Hunt
    Oct 11, 2018 at 16:14
4

I find Event Driven Architecture and Command-Query Responsibility Segregation to be the most common techniques I use to conquer complexity.

In a nutshell:

  • UI Controllers submit granular Commands on behalf of the user
  • Command Handlers mutate application state through subsystems (like a domain model, or simply transaction scripts)
  • Changes in application state raise events
  • Event handlers react by submitting more commands and/or interacting with application services (updating auxiliary data for display, sending emails, etc., etc. - a lot happens here and this is the main method of decoupling auxiliary logic from that logic that modifies the application state)

On a large scale, I try to stick somewhat rigidly to the send a command, handle the command, raise events, handle events pattern - it can lend large scale organization to a variety of project types.

Then, I allow handlers to achieve their function through whatever mechanism seems appropriate. These mechanisms form sub-components of the application like a domain model with persistence, loggers, email helpers, etc.

Allowing flexibility in the implementation of these sub-components enables agility (write it to get it done, if need be), code reuse (whether linked library or copy and paste), refactoring (let's base off of this previously written component but improve/change it as so).

But sticking to EDA & CQRS gives us some architectural consistency across projects, which makes navigating a foreign code base much easier. It also provides nice points to implement functionality with AOP - like authorizing & recording commands, persisting events, distributing workload, etc.

1
  • It should also allow components to be written in the language that suits them best. Apr 25, 2011 at 23:08
3

I found the following helpful to reduce complexity:

1
  • Especially think "Bottum Up design" is powerful, and using an expressive language (perhaps that means, high level).
    – Warren P
    Apr 26, 2011 at 1:31
3

Hands-in the Pocket Explanations.

(The phrase comes from this: http://portal.acm.org/citation.cfm?id=70024

If you can't explain it with your hands in your pockets, it's too complex. Simplify until you can explain it.

It helps to summarize use cases, architectures, design patterns, programming idioms and the like as short, easy-to-grasp stories.

This usually means that you have to create meaningful chunks or abstractions tht have to be isolated and explained separately.

These chunks are not programming language monstrosities, but are actual useful simplifications. More like the "class" vs. "instance" nature of abstraction than the "abstract superclass" vs. "concrete superclass" problem where the OO mavens have gone crazy.

3

Make your system flat instead of deep: big objects that don't talk to each much at all, not a boatload of teeny ones talking to each other. One type of data can often be modified in one central place in a loopy fashion, like PhysicsSystem.

You don't need to disperse that logic across 50 different classes that have to talk to each other and mutate their own little localized state. Doing so will lead to each one being individually simpler, but to reason about what they do physics-wise, will be, as a whole, far more complex due to the spiderweb of interactions that introduces. Just stop and think about breaking that physics system down into 50 different classes and abstract interfaces, however individually simple. Think about what that really does to your ability to comprehend what the physics engine will do, and realize how retarded we can be with OOP, making things exponentially more complicated as a whole in an effort to make each individual one simple.

Look at how game engines do it. They have the right idea.

enter image description here

The notion of a Car entity contributes barely any complexity to the system, as it is merely a collection of components and contributes no functionality to the system. And the components barely contribute any complexity to the system, since they are just data. The system breaks down into a straightforward flat pipeline of heavyweight, largely independent systems containing the functionality, not a deep spiderweb of interactions between abstract interfaces representing the most granular ideas far divorced from the business requirements. Not only will it substantially reduce the code required for the software, it will also make it easy to break down its design into a handful of systems you need while allowing you to talk to managers and customers about the system organization (which is literally just the organization of these systems) in a way that they can actually comprehend to a far greater degree, like PhysicsSystem, RenderSystem, etc.

And it's extensible and maintainable AF, allowing you to tackle whole new unanticipated design ideas of a kind that would break the most carefully designed abstractions, while still only requiring you to change one place in the code without cascading changes.

Not the answer you're looking for? Browse other questions tagged or ask your own question.