Abstraction Can Make Your Code Worse

CodeAesthetic
20 Nov 202205:13

Summary

TLDRThe script discusses the tradeoffs between abstraction and coupling in software design. It illustrates how abstraction can reduce code repetition but increase coupling, using examples like transitioning from XML to JSON and creating a 'FileSaver' class. The speaker argues that abstraction is beneficial only when its value outweighs the coupling it introduces, suggesting that sometimes a bit of code repetition is preferable to over-coupling.

Takeaways

  • 🔄 **Abstraction vs Coupling**: Abstraction is good for reducing code repetition, but it can also increase coupling.
  • 🎮 **Game Object Class**: In game development, a 'Game Object' class can handle position tracking and rendering to reduce duplication.
  • 🔗 **Coupling Impact**: Coupling can make systems hard to modify, and its effects are often not felt until changes are needed.
  • 📄 **XML to JSON Example**: Moving from XML to JSON for data storage can illustrate the trade-offs between abstraction and coupling.
  • 📑 **Separation of Concerns**: Keeping XML and JSON writers as separate classes simplifies the removal of one without affecting the other.
  • 🚫 **Avoid Premature Abstraction**: Creating a 'File Saver' class just to avoid assigning file names twice is an example of unnecessary abstraction.
  • 🔄 **Interface for Save Method**: Introducing a common interface for saving can increase coupling without providing significant benefits.
  • 🔑 **Conditional Logic**: Using an if statement to decide which class to instantiate and save with can be cleaner than forcing an interface.
  • 🔍 **Value of Abstraction**: Abstraction is only beneficial when its value outweighs the increased coupling it introduces.
  • 🔄 **When to Abstract**: Abstraction is justified when it simplifies adding more options or when the decision of what to save is separated from when to save.

Q & A

  • What is the purpose of creating the 'Game Object' class in the example?

    -The 'Game Object' class is created to handle shared functionality, such as tracking position and rendering images, for multiple types of game objects like the main character, enemy characters, and obstacles. This avoids code repetition by allowing subclasses to only specify which image to show.

  • What is the hidden tradeoff of abstraction according to the script?

    -The hidden tradeoff of abstraction is coupling. When adding abstraction to remove repetition, you increase coupling, which can make systems harder to modify because different parts of the code become more interdependent.

  • How does coupling manifest in software design?

    -Coupling manifests when different parts of a system become interdependent due to abstraction. This makes it difficult to modify or remove parts of the system without affecting other connected components.

  • Why is coupling considered an 'opposite reaction' to abstraction?

    -Coupling is considered an 'opposite reaction' to abstraction because for every bit of abstraction added to simplify code, there is an increase in interdependence between parts of the system, making it harder to isolate or change individual components.

  • What is the downside of adding a 'file saver' class in the second example?

    -The downside is that both the XML and JSON saving classes would become coupled to the idea of taking a file as input. This creates a limitation that would break the abstraction if a non-file input, like a database or cloud connection, was needed in the future.

  • Why does the speaker consider the 'file saver' abstraction unnecessary?

    -The abstraction is considered unnecessary because it saves very little—just the reassignment of a file variable—while introducing coupling that limits future flexibility. The value of this abstraction does not outweigh the potential downsides.

  • When would creating a common save interface be useful, according to the speaker?

    -A common save interface would be useful if there were more save options, such as three or more, or if the save process needed to happen at different points, such as saving every 5 minutes. In these cases, the abstraction would simplify the decision-making process around saving.

  • Why does the speaker argue that some code repetition is acceptable?

    -The speaker argues that some code repetition is acceptable because it causes less pain when modifying code compared to dealing with over-coupled systems. Repetition is often easier to manage than the unintended complexity of unnecessary abstractions.

  • What is the advantage of keeping the XML and JSON savers as distinct classes?

    -Keeping them as distinct classes avoids unnecessary coupling and allows for easier modification or removal of one class without affecting the other. This approach also avoids the limitations imposed by a forced abstraction.

  • What are the two cases where abstraction becomes worthwhile according to the speaker?

    -Abstraction becomes worthwhile when (1) there are multiple save options with different parameters, such as database configuration, and (2) there is a need to defer or repeat saving, like in an 'IntervalSaver' class that doesn't need to know which saver it's using.

Outlines

00:00

🔧 Abstraction and Coupling in Software Design

This paragraph discusses the concept of abstraction in software development, where the speaker explains how creating a 'Game Object' class can handle tracking and rendering for different objects in a game, thus avoiding code repetition. The speaker then introduces the idea that abstraction can lead to increased coupling, which is the interdependence between software components. Using the example of switching from XML to JSON data saving, the speaker illustrates how abstraction can sometimes complicate the removal of old features. The speaker argues against creating unnecessary abstractions, such as a 'FileSaver' class, which would couple different classes to the same input method and limit future flexibility. The paragraph concludes by suggesting that abstraction should only be used when its benefits clearly outweigh the increased coupling it introduces.

05:01

🤔 The Trade-off Between Abstraction and Coupling

In this paragraph, the speaker continues the discussion on abstraction and coupling, focusing on the potential drawbacks of over-abstracting. The speaker suggests that creating an interface for the 'save' functionality might not be beneficial because it would increase coupling without providing significant advantages. The speaker also points out that having distinct classes with no connection can be preferable to having a common interface that doesn't simplify the program meaningfully. The speaker then outlines two scenarios where abstraction might be justified: when there are multiple save options or when the program needs to defer or repeat saving at different points. The paragraph concludes by emphasizing that code repetition is less problematic than over-coupling when it comes to making changes to the code.

Mindmap

Keywords

💡Abstraction

Abstraction refers to the process of identifying common patterns and behaviors in the code, then extracting them into reusable components, such as classes or methods. In the video, the speaker explains how creating a Game Object class to manage common functionality for game elements like characters and obstacles is an example of abstraction. However, the speaker also highlights the tradeoff between abstraction and coupling, where too much abstraction can lead to unintended dependencies.

💡Coupling

Coupling describes the degree of interdependency between different parts of the software system. The speaker argues that increasing abstraction often increases coupling, as components become more intertwined. An example given is how adding a shared 'file saver' class introduces unnecessary coupling between two saving mechanisms, restricting their flexibility.

💡Repetition

Repetition refers to the occurrence of duplicate or similar code across different parts of a program. Engineers are trained to avoid repetition by using abstraction, but the speaker notes that some repetition may be acceptable if it reduces unnecessary coupling. For instance, keeping two separate save methods with repeated logic might be better than coupling them under one abstraction.

💡Game Object

The Game Object is an example used to illustrate abstraction. It is a class designed to handle common tasks like tracking position and rendering for game elements such as the main character, enemies, and obstacles. This encapsulation of shared functionality avoids code duplication, while still allowing each subclass to specify its unique image rendering.

💡File Saver

The File Saver example is used to demonstrate when abstraction can lead to over-coupling. By creating a class that handles file input for both XML and JSON savers, the system becomes constrained to file-based saving. The speaker explains that this abstraction brings little benefit and could prevent future extensions, such as saving to a database or cloud.

💡Save Method

The Save Method is part of the abstraction discussion, where the speaker evaluates whether creating a common interface for the save functionality (e.g., saving in XML or JSON formats) is worth it. The conclusion is that creating a shared interface increases coupling without significant benefit, as the only gain would be removing a duplicate save line, which doesn't simplify the program meaningfully.

💡XML

XML (Extensible Markup Language) is the old format used for saving data in the video’s example. The transition to JSON (JavaScript Object Notation) illustrates how tightly coupled systems can make it harder to remove outdated functionality like XML support. By keeping XML and JSON savers as separate classes, it becomes easier to remove XML without affecting the rest of the program.

💡JSON

JSON is the modern data format that the speaker wants to transition to, replacing XML. In the context of the video, JSON is used as a case study in how a separate class for each saving method (XML or JSON) makes it easier to evolve the system and remove old functionality. JSON represents the new format in the evolution of the software.

💡Interface

An interface is a contract that defines methods or behaviors a class should implement. In the video, the speaker considers whether creating a common interface for saving in different formats (XML and JSON) is worth it. However, this would introduce coupling by forcing all save methods to adhere to the same structure, even if they don't need to. The video suggests that interfaces should only be added if they bring clear benefits.

💡Interval Saver

The Interval Saver is a hypothetical example that justifies abstraction. If the program needs to save data automatically at regular intervals (e.g., every 5 minutes), an Interval Saver class would abstract away the details of which save method to call (XML, JSON, etc.). This separation of decision-making from execution is one of the few cases where abstraction is considered beneficial in the video.

Highlights

Creating a 'Game Object' class to handle position tracking and rendering for main characters, enemies, and obstacles avoids code repetition.

Subclasses can specify their own images while using the general implementation of the 'Game Object' class.

Architects excel at identifying repetition and extracting it, promoting abstraction.

Coupling is considered the equal and opposite reaction to abstraction.

Every abstraction adds coupling, which can complicate system modifications.

Example given: Moving from XML to JSON for data saving while maintaining system integrity.

Creating a separate class for JSON writing simplifies the removal of XML support.

The idea of creating a 'File Saver' class is critiqued for increasing coupling.

Coupling both XML and JSON classes to file input limits future flexibility.

Assigning a file name variable is not complex enough to justify an abstraction.

Creating an interface for the 'save' method would increase coupling without significant benefit.

Maintaining distinct classes without a connection can be preferable to avoid coupling.

Abstraction is only beneficial when its value outweighs the coupling it introduces.

A little code repetition can be less painful than over-coupling when changing code.

Two cases where abstraction might be worth it: multiple save options or deferred/repeated saving.

Separating the decision of which saver to use from the time of saving can justify abstraction.

Practical advice on balancing abstraction and coupling in software design.

Transcripts

play00:00

You have a game where you have a main character, enemy characters and obstacles.

play00:05

For each of these objects we need to have code that keeps track

play00:09

of its position in the world and code for rendering the image for each object.

play00:15

We could write the same code in all three classes,

play00:18

but you recognize that this is all similar.

play00:21

So instead you make a third class called Game Object that handles this for you.

play00:26

You now have a general implementation that tracks and renders out the object.

play00:31

The code is mostly identical, but you allow the subclass to specify

play00:36

which image is shown.

play00:39

You just created an abstraction.

play00:46

Architects have gotten really good at this game

play00:50

of identifying repetition and extracting it out.

play00:53

We get into the mode of code repetition bad, more abstraction good.

play00:58

But there's a hidden tradeoff that doesn't get considered: Coupling.

play01:02

Most engineers conceptually understand what coupling is,

play01:06

and they definitely feel its web when trying to modify an over coupled system.

play01:10

But when designing software, you don't feel

play01:13

the impacts of coupling.

play01:17

I consider coupling to be an equal and opposite reaction of abstraction.

play01:21

For every bit of abstraction you add, you've added more coupling.

play01:26

Let's explore an example.

play01:28

We have a program that saves out data to XML, but that's the old format.

play01:33

So we want to move to JSON.

play01:38

We could do this by adding a configuration to the save logic

play01:41

to support both modes.

play01:48

But this will make the removal

play01:49

of XML complicated and dangerous

play01:52

because they're all intermingled.

play01:57

So instead we'll make the JSON writer a separate class.

play02:00

Then we can just chop off the XML support by deleting the whole file,

play02:04

not needing to unweave the program logic.

play02:08

All right, so now we've written our fancy new JSON writing class.

play02:12

We might notice that both take in a file name during construction.

play02:16

Our little repetition detectors go off and realize that maybe.

play02:21

Maybe we could extract this out.

play02:24

So our instinct is to create a common class called file saver

play02:28

that just takes the file name, and our subclasses can grab it

play02:31

from this protected variable.

play02:38

But this is a bad idea.

play02:40

We've now coupled both of these classes to the same input.

play02:44

They must take a file input.

play02:46

So if there ever became a need to create something that didn't use a file

play02:51

like a database or cloud connection, this would break the abstraction.

play02:55

And on the flip side, this abstraction brings us no value.

play02:59

What does this abstraction save us?

play03:01

Well, I guess we don't need to assign the variable twice.

play03:05

But this isn't any complicated logic.

play03:07

It's simply assigning a variable.

play03:09

So for me, this squarely fits into the not worth it camp.

play03:14

Okay, now what about the save functionality?

play03:18

We could consider creating an interface that represents the “save” method,

play03:21

but we do know that this would increase coupling because now

play03:24

both of these classes are constrained to the same save method.

play03:29

So what benefits does this abstraction bring us?

play03:32

Well, let's look at the usage.

play03:35

We have an if statement that decides which class

play03:37

to create and calls save on one of them.

play03:40

So if we add a common interface,

play03:42

we only get to remove this one duplicate save line.

play03:46

That doesn't simplify the program in any meaningful way.

play03:50

So I'd also put this into the it's not worth it camp.

play03:53

At this point it's better to keep these as two distinct classes

play03:57

with no connection at all.

play04:01

There are two cases where it would make me decide it was worth it.

play04:05

One would be if we added more save options.

play04:08

If we had three or more we might want to extract the construction

play04:11

of these save objects into a separate piece of code, especially

play04:17

if the different savers had different parameters, like a database configuration.

play04:23

The other case would be if we needed our program to defer

play04:27

or repeat saving at a different point in the program.

play04:30

For example, if we wanted to save every 5 minutes

play04:33

automatically, we’d create a class called “IntervalSaver”,

play04:37

and it would make sense for this Interval Saver class

play04:40

to be unaware which saver it's calling.

play04:43

In both cases, it becomes worth it when we want to separate the decision

play04:46

of which saver we want from the time we actually want to save.

play04:52

Overall, it's good to only apply abstraction

play04:55

when the value it brings overweighs the coupling.

play04:58

This does mean that you might have a little bit of code repetition.

play05:01

But I think that a little code repetition

play05:03

brings less pain when changing code than over coupling.

play05:07

What do you think?

Rate This

5.0 / 5 (0 votes)

Etiquetas Relacionadas
Software DesignAbstractionCouplingCode RepetitionClass InheritanceXML ConversionJSON WritingInterface DesignCode OptimizationProgramming Best Practices
¿Necesitas un resumen en inglés?