Abstraction Can Make Your Code Worse
Summary
TLDRThe video script discusses the trade-offs between code abstraction and coupling in software design. It illustrates how abstraction can simplify code by reducing repetition but may inadvertently increase coupling, complicating future modifications. The speaker uses examples from game development and data saving to highlight when abstraction is beneficial, such as when multiple save options are needed or when deferring the decision of which method to save. The key takeaway is to apply abstraction judiciously, prioritizing the value it adds over the potential for increased coupling.
Takeaways
- ๐ฎ In game development, creating a 'Game Object' class can help manage position and rendering for characters and obstacles, reducing code repetition.
- ๐ Abstraction is a powerful tool in software design, but it should be used judiciously to avoid unnecessary coupling.
- ๐ Coupling is the interdependence between components of a system; increased abstraction can inadvertently increase coupling.
- ๐ When migrating from XML to JSON, consider creating separate classes to avoid entangling the new format with the old, making future changes easier.
- ๐ซ Avoid creating a 'file saver' superclass that forces subclasses to accept a file input, as it can limit future flexibility and break abstraction.
- ๐ Code repetition is sometimes preferable to over-abstraction, as it can be less painful when making changes to the system.
- ๐ Before abstracting, consider the benefits it brings, such as simplifying the program or enabling new features.
- ๐ Use interfaces sparingly; they can increase coupling and only provide value when multiple classes share a common method.
- ๐ Abstraction is most valuable when it allows for deferred or repeated actions, such as interval-based saving.
- ๐ Evaluate the trade-offs between abstraction and coupling on a case-by-case basis, considering the specific needs of the project.
- ๐ Prioritize maintaining a balance between abstraction and coupling to ensure the system remains maintainable and flexible.
Q & A
What is the main purpose of creating a 'Game Object' class in the given game development scenario?
-The 'Game Object' class is created to handle the common functionality of tracking position and rendering images for the main character, enemy characters, and obstacles, avoiding code repetition across these classes.
What is the tradeoff associated with abstraction in software design?
-The tradeoff associated with abstraction is coupling. For every abstraction added, there is an increase in coupling, which can make the system more interdependent and potentially harder to modify.
Why might it be a bad idea to create a 'FileSaver' class that both XML and JSON writers inherit from?
-Creating a 'FileSaver' class would couple both XML and JSON writers to the same input (file name), which would make it difficult to adapt to new saving methods like a database or cloud connection without breaking the abstraction.
What are the two cases where abstraction might be considered valuable in the context of the script?
-Abstraction might be valuable when there are multiple save options with different parameters, or when the program needs to defer or repeat saving at different points in time, such as with an 'IntervalSaver' class.
What is the 'IntervalSaver' class mentioned in the script?
-The 'IntervalSaver' class is a hypothetical class that would handle the task of saving data at regular intervals, without needing to know which specific saver (like XML or JSON) it is calling.
Why is it sometimes better to have code repetition rather than over-abstraction?
-Code repetition might be better than over-abstraction because it can lead to less pain when changing code, as it avoids the complexities and dependencies that come with high coupling.
How does the script suggest deciding when to apply abstraction?
-Abstraction should be applied when the value it brings, such as easier maintenance or flexibility, outweighs the increased coupling it introduces.
What is the significance of the 'save' method in the context of the script?
-The 'save' method is significant because it represents a potential point of abstraction. However, the script suggests that creating a common interface for it might not simplify the program meaningfully and could increase coupling.
What is the role of the 'save' logic configuration in the script's example?
-The 'save' logic configuration is mentioned as a potential way to support both XML and JSON formats. However, it is criticized for complicating the removal of XML support, as it intertwines the logic of the two formats.
How does the script relate the concepts of abstraction and coupling to the practice of software design?
-The script illustrates that while abstraction can help manage complexity and reduce code repetition, it also introduces coupling, which can make systems more difficult to modify. It encourages developers to consider the balance between these two aspects when designing software.
Outlines
๐ฎ Abstracting Game Code
The paragraph discusses the concept of abstraction in game development. It starts with a scenario where a game has main characters, enemies, and obstacles, each requiring code for position tracking and rendering. To avoid repetition, a 'Game Object' class is created to handle these tasks, allowing subclasses to specify the image. The speaker then introduces the trade-off between abstraction and coupling, suggesting that abstraction can lead to increased coupling. An example is given where changing the data format from XML to JSON involves creating a separate JSON writer class, which simplifies the process of removing XML support. However, the speaker argues against creating a 'file saver' class to avoid coupling and breaking the abstraction if the need for a non-file-based saver arises. The paragraph concludes by questioning the value of abstraction when it doesn't provide significant benefits and suggests that sometimes, a little code repetition is preferable to over-coupling.
๐ Balancing Abstraction and Coupling
This paragraph continues the discussion on abstraction and coupling, emphasizing that while code repetition is often seen as bad, it can sometimes be less problematic than over-coupling. The speaker suggests that it's better to have distinct classes with no connection rather than creating an interface that increases coupling. Two scenarios are presented where abstraction might be beneficial: when there are multiple save options or when the decision of which saver to use needs to be separated from the actual saving process. The speaker concludes that abstraction should only be applied when its benefits outweigh the coupling it introduces, even if it means some code repetition.
Mindmap
Keywords
๐กGame Object
๐กAbstraction
๐กCoupling
๐กXML
๐กJSON
๐กFile Saver
๐กInterface
๐กCode Repetition
๐กDatabase
๐กCloud Connection
๐กInterval Saver
Highlights
Creating a 'Game Object' class to handle position tracking and rendering for main characters, enemies, and obstacles.
The importance of avoiding code repetition by using abstraction.
The concept of coupling as an equal and opposite reaction to abstraction.
The tradeoff between abstraction and coupling in software design.
The example of migrating from XML to JSON data format and the implications for abstraction.
The potential complications of mixing XML and JSON save logic.
The decision to separate JSON writing into a distinct class for easier maintenance.
The pitfalls of creating a 'File Saver' class due to increased coupling.
The argument against unnecessary abstraction that doesn't provide significant benefits.
The suggestion to keep classes distinct when abstraction does not add value.
The potential benefits of abstraction when dealing with multiple save options or deferred saving.
The 'Interval Saver' class as an example of a situation where abstraction is beneficial.
The principle of applying abstraction only when its value outweighs the coupling.
The acceptance of some code repetition as a lesser evil compared to over coupling.
The importance of balancing abstraction and coupling for effective software design.
Transcripts
You have a game where you have a main character, enemy characters and obstacles.
For each of these objects we need to have code that keeps track
of its position in the world and code for rendering the image for each object.
We could write the same code in all three classes,
but you recognize that this is all similar.
So instead you make a third class called Game Object that handles this for you.
You now have a general implementation that tracks and renders out the object.
The code is mostly identical, but you allow the subclass to specify
which image is shown.
You just created an abstraction.
Architects have gotten really good at this game
of identifying repetition and extracting it out.
We get into the mode of code repetition bad, more abstraction good.
But there's a hidden tradeoff that doesn't get considered: Coupling.
Most engineers conceptually understand what coupling is,
and they definitely feel its web when trying to modify an over coupled system.
But when designing software, you don't feel
the impacts of coupling.
I consider coupling to be an equal and opposite reaction of abstraction.
For every bit of abstraction you add, you've added more coupling.
Let's explore an example.
We have a program that saves out data to XML, but that's the old format.
So we want to move to JSON.
We could do this by adding a configuration to the save logic
to support both modes.
But this will make the removal
of XML complicated and dangerous
because they're all intermingled.
So instead we'll make the JSON writer a separate class.
Then we can just chop off the XML support by deleting the whole file,
not needing to unweave the program logic.
All right, so now we've written our fancy new JSON writing class.
We might notice that both take in a file name during construction.
Our little repetition detectors go off and realize that maybe.
Maybe we could extract this out.
So our instinct is to create a common class called file saver
that just takes the file name, and our subclasses can grab it
from this protected variable.
But this is a bad idea.
We've now coupled both of these classes to the same input.
They must take a file input.
So if there ever became a need to create something that didn't use a file
like a database or cloud connection, this would break the abstraction.
And on the flip side, this abstraction brings us no value.
What does this abstraction save us?
Well, I guess we don't need to assign the variable twice.
But this isn't any complicated logic.
It's simply assigning a variable.
So for me, this squarely fits into the not worth it camp.
Okay, now what about the save functionality?
We could consider creating an interface that represents the โsaveโ method,
but we do know that this would increase coupling because now
both of these classes are constrained to the same save method.
So what benefits does this abstraction bring us?
Well, let's look at the usage.
We have an if statement that decides which class
to create and calls save on one of them.
So if we add a common interface,
we only get to remove this one duplicate save line.
That doesn't simplify the program in any meaningful way.
So I'd also put this into the it's not worth it camp.
At this point it's better to keep these as two distinct classes
with no connection at all.
There are two cases where it would make me decide it was worth it.
One would be if we added more save options.
If we had three or more we might want to extract the construction
of these save objects into a separate piece of code, especially
if the different savers had different parameters, like a database configuration.
The other case would be if we needed our program to defer
or repeat saving at a different point in the program.
For example, if we wanted to save every 5 minutes
automatically, weโd create a class called โIntervalSaverโ,
and it would make sense for this Interval Saver class
to be unaware which saver it's calling.
In both cases, it becomes worth it when we want to separate the decision
of which saver we want from the time we actually want to save.
Overall, it's good to only apply abstraction
when the value it brings overweighs the coupling.
This does mean that you might have a little bit of code repetition.
But I think that a little code repetition
brings less pain when changing code than over coupling.
What do you think?
5.0 / 5 (0 votes)