The only reason we write complex code is because the real life is complex and our job is modeling it. Understand how “entities” (the vague definition is used on purpose, because it could be literally anything) interact with each other on the real world and translate it to code on the proper abstraction level is the heart and soul of a good software engineer.
Our job is mostly turn real world systems into software systems.
For instance, if you are modeling a calculator app you have some entities:
- Digits ex: 1,2,3,4
- Operators ex: +, - , * , /
- Aggregators ex: ( , [ , ) , ]
And you can think how they interact with each other:
- Digits are the core values of your system, they are the inputs and the output it self
- Operators have semantic value on your domain, it means that are business rules (Math rules) that this operators applies, operators only make sense when used with digits 2 + 2
- Each operator have a relation with other operators, like * and / must be solved first and + and - last
- Aggregators applies business rules, that change the the default priority of operators
With this you can start modeling this calculator system in a software system:
- If you use a OO language, create a class for your Digit entitiy, which could hold information about the digit, beyond the digit value it self, or a struct could represent it in Elixir.
- Each operator could be defined as functions that expect digits as entries
sum(digit1, digit2) inside their own modules
- Aggregators must be analyzed before hand on the calulation, and you will find out that use a classic data structure called stack to do it will help you a lot.
This is a very simple example that I could talk a lot more… but the point is just to show that for modeling a complex system you have to understand the domain/business it is related to and try the best you can implement this relations as code.
I’ll probally be hated on this, but I think an Object Oriented language can teach you a lot about this, it is the most popular programming paradigm for a reason. (:
That said, to “enter a complex system and make changes” you have to understand what the system is about and how it models the reality. Knowing how and when entities interact with each other.
Entities are usually represented as a well defined document inside a project, in elixir we call them modules on OO classes, but the fact is that stuffs relates to each other.
A usefull technique is trying to identify:
- What is the input?
- What is the output?
The output must be related to the input, so as you read the code, you will identify how it transform or use the input to generate the output.
Input: Client Identifier
Output: Client Name
Predict: Reading this code you probally will find a database call using the identifier and retrive it’s name
Use this techinique of thinking about inputs and outputs, and predict an expected behaviour has helped me a lot when trying to understand new systems. Because I knew exact what I was looking for and more important why I was looking for it.
With this I can ask the right questions even when I predicted wrongly.
Real world example:
I was trying to understand a function that updates the user table, but the input of the function was not the user id, instead it was the user document.
I knew that another table has this information, linking document numbers with users ids.
But I did not found this on the code.
After this I could ask for help with the exact question: “How this functions knows which user must be updated?”
The answer was: “The user id is a hash of the document”
With this I could learn and understand the system easily, because I knew what the function should do and predicted (wrongly) how.
This technique will improve on time, because your prediction power will improve with time and knowledge! And It forces you to always think: “How I would do this?”
I’m already writing a lot, but to wrap up.
- Understand the context the software you are working with was built.
- Think about inputs and outputs, and how you would built this
- Great books to read:
- Clean Architecture (General concepts)
- Refactoring - Improving Design of Existing Code (General concepts)
- Desiging Elixir Systems With OTP (Elixir oriented)
- Elixir in Action (Introdutory book to elixir lang, but the practical advices about reasoning about elixir systems are gold)