Design better software abstractions using bipartite composition
Problem
You’ve written an object or class. It’s somewhat complex and you want to iterate ways to better abstract your code but are unsure how to start. There exists documentation about what good abstraction looks like, but no concrete iterative steps.
Being deep inside your own code can make you blind to obvious alternatives.
Solution
Create a bipartite graph of instance methods and member variables. Draw edges between methods and the variables they use. Then move isolated components into separate classes.
Concrete, Simple Example
A space ship
Assume you’re designing a video game with a space ship. Space ships are circles that have some amount of health they can also heal (if they aren’t dead already). Space ships also have some location and you need to know if two space ships intersect.
Let’s created a bipartite graph of instance methods and member variables to see if we can simplify this abstraction.
Notice how we have two disconnected subgraphs. One connecting health with heal or harm, and another connecting intersects with location and size. This is a sign we are probably dealing with two separate game concepts: one about killing actors of the game and another about objects with physical locations. We can use composition to break our ship object into two concepts.
Notice how Ship2
still does the same amount of things, but we can now reason about those things as smaller units. As a bonus, we have discovered the concepts of physical objects and killable objects. You could imagine making smaller interfaces or packages around these atomic units, spreading this abstraction to other places of your game.
Conclusion
It’s not necessary to literally draw out a bipartite graph to simplify software, but knowing the process is something you can often do in your head to create smaller abstractions.
When hunting for simplified abstractions, consider the interactions between member variables and member functions