Conscious Software Design

Jakob Jenkov
Last update: 2024-01-11

Conscious Software Design is my personal software design philosophy that guides both how I approach software development - both in practice and in theory. The main idea of conscious software design is that we who work with software, and thus software design, should focus on being more conscious about what design decisions we make - and especially why we make them.

There are many valid ways to design a given system. Making a choice between these different designs is what "making a design decision" means. Different requirements and different project contexts may warrant different design decisions. We need to be conscious of that.

Conscious Software Design consists of three core principles - meaning three core aspects of software design that I believe should be more conscious about:

  1. Understanding
  2. Pragmatism
  3. Trade-offs

I will explore each of these themes in more detail in the following sections - but first I will dive a bit more into what I mean by being conscious.

By the way, if you prefer video, I have a video explanation of Conscious Software Design here:

Conscious Software Design - Video Tutorial

Four Levels of Design Consciousness

As I see it there are four levels of consciousness we can have about software design. These levels are:

  1. Oblivious
  2. Unconscious
  3. Subconscious
  4. Conscious

The oblivious level means that we do not even think about why we do what we do. We just kind of stumble forward until we arrive at some solution to our problem. This is the consciousness level that many people will have when they first start programming. They just put various program statements together until the program does what they want it to, without giving any thought to the design of that program.

The unconscious level means that we are making design decisions - but not based on our own reasoning. Instead, we make decisions based on what we have read in books, articles etc., or heard about presentations or from senior colleagues etc. This corresponds to mindless following doctrine or dogma without ever questioning whether the doctrine or dogma is appropriate for the given situation.

The subconscious level is when we start to make design decisions based on your own intuition rather than the doctrines you have learned elsewhere. We are not completely aware of why we make the decisions we make. We just know that what we did unconsciously did not always work out well, so we follow our hunches towards designs that might be more appropriate for our current situation.

The conscious level is when you are fully conscious about what your design goals are, fully conscious about what the contextual restrictions on your design are - and fully conscious that when making design decisions you are making trade-offs between contextually conflicting design goals.

It is easy to believe that each individual operates fully within one of these consciousness levels. However, in practice we probably operate within multiple of these levels, depending on the situation. Sometimes we know what we are doing, and sometimes not. However, now that you are aware of these levels, perhaps you will start thinking actively about what level you are operating under, and whether you could do something to increase the level of your consciousness.

Software design consciousness levels

Now let's dive deeper into what to be conscious about - meaning the core principles of conscious software design.


The first principle of conscious software design is understanding.

First of all, you must have a good understanding of your primary (root) design goals. Whatever design technique you decide to use - you will do so because you are trying to achieve one of your primary design goals. See my tutorial about software design goals for more information.

Second, you must understand exactly why you make the software design decisions you make. It is not enough to just tell yourself that it is considered "good style" or "best practice". You must understand why it is considered good style or best practice. Also, you must understand if those techniques are also helpful in your concrete situation - meaning if the techniques help you achieve your primary design goals in your concrete situation. This is not always the case!

Ideally, for every line of code you write you would know exactly why you wrote that line the way you did. In reality however, your consciousness level may not be that extreme.

When doing conscious design you are relying on your own design thinking - your own reasoning - meaning you are able to explain yourself exactly why you design the code the way you do - without having to have anyone else instructing you. In other words, you are relying on your understanding to drive your design thinking.

Unconscious Design

The opposite of conscious design is unconscious design. You are doing unconscious design when either do not think about the design at all, or when you rely on someone else's design thinking. You are relying on someone else's design thinking when you blindly follow guidelines set forth by others without understanding why they work - and thus without understanding if they will work in your current situation / case.

Favor Understanding

In general - you should favor understanding over anything that is unconscious design. For instance favor:

  • Understanding over process
  • Understanding over recipe
  • Understanding over best practices
  • Understanding over doctrine


The second principle of conscious software design is pragmatism .

By pragmatism I mean that you focus on solving real problems - not theoretical problems - nor abiding by dogma or doctrine. Whatever design decisions you make must be traceable to solving a real problem - or attempting to achieve a real design goal.

Understanding is a prerequisite for pragmatism. If you do not understand your primary design goals, nor understand the technology you work with, nor understand the design technique you intend to apply, it is really hard to be pragmatic. Most likely you will end up being dogmatic rather than pragmatic instead.

Being pragmatic means that achieving your primary design goals - or solving real problems - is your primary reasoning for the design decisions you make. That means, that you do not use a given design technique because you swear by that technique. Rather, you use that technique because you determined it to be the best in the given situation to achieve what you want to achieve.

In other words, you think like a mixed martial artist - using whatever technique from whatever martial arts style that seems appropriate for the situation. Not like a single-style martial artist, that just blindly follows the rules of that school or style.


The third principle is trade-offs.

Every design decision you make is a trade-off. Often, you will have different design options to choose between, and each option has its own set of pros and cons. It is up to you to weigh those pros and cons against your current situation, and choose which design makes the most sense right now.

Trade-offs are temporal - meaning sometimes the calculation of which design pros and cons gives you most benefit may change over time. Performance might not matter in the beginning of a product's lifetime, but might matter later on when you have more users, more traffic or larger amounts of data. You might go for a faster implementation early on - at the cost of a lower performance.

Pragmatism is a prerequisite for making trade-offs. Pragmatism makes you focus on solving your real problems, not following doctrines. Making trade-offs weighed against how you best solve your real problems is how you act pragmatically in practice.

Jakob Jenkov

Featured Videos

Java ForkJoinPool

P2P Networks Introduction


Java Persistence
Close TOC
All Tutorial Trails
All Trails
Table of contents (TOC) for this tutorial trail
Trail TOC
Table of contents (TOC) for this tutorial
Page TOC
Previous tutorial in this tutorial trail
Next tutorial in this tutorial trail