Threads of harmony

The cosmic dance of Chinese and software design
Python
Programming
Opinion
Author

Johnny Breen

Published

June 29, 2023

Unbeknownst to many, I’ve been on a decade-long journey of learning Mandarin Chinese.

What began as a seemingly random decision1 has evolved into an enduring commitment, often shrouded in mystery: I have frequently found myself wondering what precisely captivated me about this intricate and abstract language.

And then, as if by fate - or perhaps the more profound eastern notion of 緣份 - it finally clicked.

Engrossed in the process of writing a Python program for a side-project, the answer struck me like lightning. Suddenly, the connection became crystal clear.

You see, it all begins with inheritance.

Inheritance

If you have never learned Chinese before then this might seem like a tricky task for you to undertake but stick with me - it’s easier than it sounds.

I want you to have a look at the following characters and tell me what is common to all of them,

All of these characters have one thing in common. Can you spot it?

If you haven’t noticed it yet, look at the left-hand side of each character: every single character possesses one uniform component! It’s this one,

This is a distorted version (but a replica, nonetheless) of the character for ‘water’,

So, the four characters that I listed above all contain a reference to this character.

Cool. But so what?

Well, if I unveil the meaning of each character then perhaps this will become clearer,

河 = ‘river’

湖 = ‘lake’

海 = ‘ocean’

波 = ‘wave’

In other words, as you might have guessed, they all have something to do with the concept of ‘water’. The formal name for the component which is situated on the left-hand side of each character (in this case a reference to the concept of ‘water’) is a radical.

A radical can be thought of as the ‘base’ component of a character. It sets the stage for the reader and acts as a semantic indicator for the character in question.

But here’s the cool part: if we think of each character as inheriting the properties and behaviours of water, then this is no different to the inheritance mechanism of object-oriented programming.

For instance, we can sketch each of the aforementioned characters into broad Python classes like so,

# Our base class (radical): 'water'
class Water():
  
  def __init__(self, volume: float, ...):
    self.volume = volume
    ...
  
  def flow(self):
    ...
  
  def freeze(self):
    ...
  
# A river subclass: inherits properties and behaviours of the superclass 'water'
class River(Water):
  
  def __init__(self, length: float, entry: list[float], exit: list[float], ...):
    self.length
    self.entry
    self.exit
    
  ...

# A lake subclass: inherits the properties and behaviours of the superclass 'lake'
class Lake(Water):
  
  def __init__(self, ...):
    ...
  
  ...
  
# Further classes below
...

I’ve left out the more significant details but you can see the fundamental structure of this hierarchy.

Here is a visualisation of what we have embedded in the code snippet shown above:

flowchart 
  A[Water] --> B(River)
  A[Water] --> C(Lake)

The Water class has certain properties (such as a volume metric) and it can ‘do’ certain things - water can flow, it can freeze and more.

But a River - which is ultimately composed of water - can do the same things: it can freeze over during bouts of cold but it can also flow majestically.

Inheritance can be useful in software design because it allows you to create a hierarchy of classes where ‘child’ classes inherit attributes and methods from their ‘parent’ classes. This promotes code reuse and modularity.

But, as you can also see from the examples listed above, inheritance also permits a program to override and extend (where applicable) the attributes and methods of its parent: for example, a River has an entry point and an exit point (which ultimately determines its length). This is not a feature of Water in general but this design pattern allows us to ignore this complication: we can just inherit what is common from Water and then append or extend any other required behaviours.

It is utterly striking to me just how explicit the Chinese language is about this design pattern: in the same way that we are tagging River as a subclass of Water with the syntax River(Water) the radical system is doing the same thing by conjoining 氵and 可 with the syntax 河.

Composition

We have just seen that characters themselves are composed of different building blocks. In the previous example, the water radical 水 was bundled into each of the characters to indicate to the reader that this character has something to do with water.

But there’s more: different characters can be combined to generate meaning.

When I was studying Chinese in Beijing, I remember doing a reading test and encountering an interesting word2 that I didn’t understand,

亲密

Whilst I didn’t know the precise meaning of this word, I knew what each individual character meant,

亲 = something to do with family or parentage

密 = something ‘secretive’ (I knew this because the word for secret is 秘密)

And with this, I was able to effectively guess the meaning of the combined character set. It arose as an adjective in the context of the word ‘friend’ ( 朋友 ).

Hmm, so a friend with the traits of being ‘like family’ and ‘secretive’: perhaps it could mean ‘an intimate and close friend’?

Lo and behold, I was right.

And so, whilst I had no idea what this term meant beforehand, through some guesstimation, I was able to work it out. But this only works because Chinese is a composable language.

In software development we strive to design software which is composable. For example, suppose you are writing a data pipeline which is required to ‘prepare’ some data for modelling purposes.

Is it best to write one function which ‘prepares’ the data from source?

No, it isn’t. In this scenario it is preferable to define separate ingestion, transformation and cleansing functions and then stitch these together to create a new function which is dedicated to data ‘preparation’,

import pandas as pd

def ingest(data: pd.DataFrame):
  ...
  
def transform(data: pd.DataFrame):
  ...
  
def cleanse(data: pd.DataFrame):
  ...
  
def prepare(data: pd.DataFrame):
  
  ingested = ingest(data)
  transformed = transform(data)
  cleansed = cleanse(data)
  
  return cleansed

This is composition in action. Here we are creating a separation of concerns: the transform() function does not care about ingest() or cleanse(); it just does its own, relatively simple job.

This means that each function can be tested effectively with unit tests. It also means that prepare() is now, in effect, only responsible for orchestrating the data preparation process - it is just arranging the other units in a sequential order and delegating the work to those units. This is effective design.

Consistency

One thing I love about Chinese is the numbering system.

To illustrate how much more logical this system is than our western counterpart(s) consider how we say the numbers 1 to 20 (inclusive).

In English (and French and other languages) you have to know many distinct words and terms for each of these numbers.

In Chinese? You only need to know the characters for 1 ( 一 ) to 10 ( 十 ) which is half of that. In addition to this, the method of constructing numbers between 11 and 20 is extremely consistent.

Here’s the formula for constructing a number between 11 and 20 in Chinese. Suppose we are looking at constructing the number 13,

Step 1: take the second digit of the number - in this case the second digit of 13 is 3 ( 三 )

Step 2: append this number to 10 ( 十 ) - in this case, we would have 十三

And that’s it. You do the exact same thing for any other number you want to construct. It will always start with a 十 and end with the number of choice. It’s consistent.

Contrast this with English where kids have to learn ‘eleven’, ‘twelve’, ‘thirteen’ (which so far have hardly anything in common with ‘one’, ‘two’ or ‘three’) and so on.. you can see why it’s a lot easier for Chinese kids to understand numbers than it is for western kids to do the same!

What about the number 30? Easy, just take a 3 and place it in front of a 10: 三十

The point of all this is that good programmers are also consistent. They form habits and write code that is consistent and comprehensible.

For example here’s some bad, inconsistent code,

def SquareArea(sideLength):
  return sideLength **2

def calc_circle(rad):
  return 3.1459 * radius**2

And here’s a better, more consistent version,

from math import pi

def compute_area_square(len_side: float):
  return len_side ** 2

def compute_area_circle(len_radius: float):
  return pi * radius ** 2

I think we can all agree on which of these implementations is preferable!

Consistency is what makes something reliable and easy to understand. Remarkably, Chinese has managed to leverage this feature at its core.

Languages are difficult (but there is hope)

If we were to look at the typical trajectory for learning Chinese it would look something like this,

Graph showing how, if you persist with Chinese, eventually the learning pays off

Apologies for the terrible formatting. I just couldn’t be bothered to graph this in a professional visualisation library so I resorted to plain old paint.

So let’s presume that you aren’t an MBA who thinks that learning Chinese is good for them because the Chinese economy is the ‘next big thing’ (like the fad it was in the early 2010s!).

The brutal truth is that yes, at first, it is going to be very difficult. You have to be prepared for some incredibly slow progress during the initial ‘grind period’. This is what I have represented as everything before the ‘threshold’ value: progress is slow and, unfortunately, you’re on par with the business grads.

However, as you start to learn more and more, and you breach that all-important critical threshold, you’ll find that your progress will start to accelerate dramatically.

And if you’ve been reading this article attentively, you’ll now understand why that is: Chinese respects design principles. And whilst these principles can seem like a hindrance or an obstacle at first, if you respect them in turn, you will be rewarded and your hard work will pay off.

Footnotes

  1. I had previously studied French in high school and thoroughly hated it. Thus, I figured I wanted to move as far away from Europe as I could: it was between Chinese and Arabic.↩︎

  2. I use the term ‘word’ even though this is not strictly accurate. But, in general, most ‘words’ or ‘ideas’ in Chinese are composed of two or more characters.↩︎