design better software abstractions using bipartite composition
Abstract
Use bipartite graph of instance methods and member variables so you can split larger problems into smaller ones, which is easier to visualize and to understand.
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 a 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 spaceship
Assume you’re designing a video game with a spaceship. spaceships are circles that have some amount of health they can also heal (if they aren’t dead already). spaceships also have some location and you need to know if two spaceships intersect.
Let’s created a bipartite graph of instance methods and member variables to see if we can simplify this abstraction.
Bipartite graph of methods and members
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.
Complex objects are difficult to reason about. Smaller objects are easier to fit into our mental space.
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