How to Write Soft Software

And keep it soft in the long run

Liu Tao
The Startup
5 min readJul 8, 2019

--

Software is Hard

Peoples generally think that software is pretty soft and easy to change. It’s right in some sense, if we don’t need to guarantee the software we changed still work. Any experienced programmer will tell you that software is hard to change, and will only get harder and harder over time.

What soft means

Let’s go to the dictionary and find out what soft means. Below is the first definition from dictionary.com:

yielding readily to touch or pressure; easily penetrated, divided, or changed in shape; not hard or stiff:

So peoples are right. Whenever we call something soft, it’s reasonable to expect we can change it easily.

Software is hard to change

The reason that software is hard to change is the coupling. Software is not something physical. It’s just made up of 0 and 1. There are unlimited ways to create coupling in software, and each one of them could make the software harder and harder.

Writing Software is Hard

Writing software is easy if no change required in the future. Human has the many-thousands-years experience to build something that doesn’t have to be evolvable. Writing software is the first time in human history that we try to build a continuously evolvable system. It’s the evolving requirement that makes writing software so hard.

Mismatched Linear, Sequential Methodology

For other industries, the process of designing and building something has the following steps:

  • Define the target system
  • Decompose target into components and build each one separately
  • Assemble parts back to the complete system

This process is iteration by iteration. Once one iteration is done, any improvement can only be implemented in the next iteration.

With this insight, we thought we could build software in the same fashion, aka waterfall model. But after practicing waterfall for many years, we realized there is a fundamental mismatch between this methodology and the inherent nature of software development. It misses the continuous evolvement part.

Evolvement make software hard

For software, the target definition and decomposition are quite similar to other industries. But to support continuous evolvability, the assembling methodology needs to be very different. We don’t want the assembling to be hardwired. Instead, we want to tie each piece together to make them work as one complete system. But still, each piece must be individually evolvable. This assembling is the primary source of complexity in software development, and we are still trying to find the best way to do it.

Software evolution over time

Overtimes, each piece could evolve at a different speed and in a different direction, the assembling mechanism must be flexible enough to support this type of evolvement.

Misleading software architect title

The evolvement requirement also makes the title of software architect totally misleading. Their job is not to draw the blueprint of software and claim it’s done. The actual job should be overseeing the evolvement of the software system and make sure it’s continuously evolvable over time. As pointed out in this book, the city planner is a much more suitable title, and their responsibilities are to make sure that all the boundaries are well respected.

How to Write Soft Software

We understand that software is not that soft and writing software is hard. Below I will give a list of principles we can use to develop soft software. Please note software development will never be easy. If its too easy, maybe it doesn’t worth the effort to build it at all. Following the list below can only make the complexity more manageable.

Decompose vertically

Traditionally, we use 3-tier architecture to decompose the system horizontally — presentation layer, business logic layer, and persistence layer. With system complexity increases, each layer itself could become unmanageable. Vertical is a more scalable approach for decomposition, which means we decompose the system into sub-domains, and then, as you have guessed, into microservices.

Use unified communication

After the system is decomposed, how we can tie them together becomes the key. Comparing the following two types of systems.

With mesh topology, each component needs to know the location of its dependency component. With bus topology, each component pushes data to the bus and doesn’t need to worry about where it will go and how it can get there. The infrastructure is responsible for routing the data to the interested components. With the bus topology approach, we shift the responsibility like data routing to message bus, and each component is only responsible for its own core business logic.

Embrace asynchronous

We want communication to be asynchronous most of the time. Synchronicity is an extra overhead we like to avoid. Email and phone calls are two examples of asynchronous and synchronous communication. We know the email is a much more efficient and high throughput way for daily communication need. Most of the time, we don’t need the communication to be synchronous. We only need to guarantee that the other party will get the message at the end.

Construct self-contained component

Cloud and container technology changed the way how software is developed and deployed. It provides the perfect balance between efficiency and isolation. The output of the development team is a self-contained image, which is immutable and is guaranteed to work in production. Each image is a vertical slice of the whole system and is the only place for the business logic of its subdomain. To communicate with the outside world, each component should be talkative by itself. Whenever it did something meaningful, it should publish it to the message bus.

Embrace immutability

In the early days of the computer industry, memory and storage are scarce resources. A lot of efforts were put into the language and compiler to generate the most memory-efficient machine code.

Two advancements in computer hardware, abundant memory and multiple-core CPU, make immutability more and more relevant. But the whole industry is still trying to find a way to embrace immutability in our daily practice.

When the mutation is unavoidable, we should be at least very clear about the scope of each modification. All side-effect should be explicit, and no hidden side-effect is allowed.

Conclusion

The ideal conformation for software should be antifragile. Each component can grow and shrink as needed. Messaging is one of the loosest forms of coupling we ever know. Our software will be evolvable enough if we can build it using only message-based coupling. We are still at the early stage of exploring message-driven system design. But the result so far looks very promising.

--

--