제이온

[Object] Chapter 1. Object, Design

Created: 2024-04-28

Created: 2024-04-28 13:45

Introduction

Robert L. Glass argued that practice precedes theory. Software development, in particular, is a prime example where practice is ahead of theory, and developers gain the most when they get their hands dirty with concrete code. Therefore, we're going to set aside theory and concepts for now and take a look at a simple program.


Implementing a Ticket Sales Application

  • We're planning a small event to promote a small theater.
    • Event details: Send invitations to selected audience members who can watch the performance for free through a lottery.
  • We need to separate the audience members who won the event from those who didn't.
    • Event winners: Exchange invitation for a ticket.
    • Event losers: Purchase a ticket with money.



What's the Problem?

Robert Martin explains the three functions that a software module (any element that constitutes a program, regardless of size, such as a class, package, or library) should have.


  • It works properly during execution.
  • It exists for modification.
    • Modifications should be possible with minimal effort.
  • It communicates with the person reading the code.
    • Developers should be able to easily read and understand it.


The aforementioned ticket sales application satisfies the first constraint of proper execution, but it fails to meet the goals of modifiability and communication.


Unexpected Code

Let's examine the reasons why it fails to meet the communication goal.


  • What the Theater class's enter() method does
    • The theater opens the audience member's bag to check if there's an invitation inside.
    • If there's an invitation in the bag, it tells the ticket seller to move the ticket stored in the ticket booth into the audience member's bag.
    • If there's no invitation in the bag, it takes out the amount of cash equal to the ticket price from the audience member's bag, purchases a ticket, and puts the ticket in the bag.
  • From the audience member's perspective, they have to watch a third party, the theater, rummage through their bag, take their money, and put a ticket in it.
  • From the ticket seller's perspective, they have to watch a third party, the theater, manipulate the tickets and cash in the ticket booth without permission.
  • Understandable code means code whose operation doesn't deviate significantly from our expectations, and this theater deviates from our expectations.
    • The audience member should take out the money from their bag and pay the ticket seller to receive the ticket.
    • The ticket seller should take out the ticket from the ticket booth and hand it to the audience member, receiving money from the audience member and storing it in the ticket booth.
  • Also, to understand the enter() method, you need to remember all the details.
    • Audience has a Bag.
    • The Bag contains cash and a ticket.
    • TiketSellet sells tickets from the TicketOffice, and the TicketOffice stores money and tickets.


Code Vulnerable to Change

The enter() method assumes two conditions.

  • Audience members always carry a bag to store cash and invitations.
  • The ticket seller only sells tickets from the ticket booth.


What about the following situations?

  • Audience members might not have a bag.
  • Audience members may use a credit card instead of cash.
  • The ticket seller can sell tickets outside the ticket booth.


For example, to satisfy the first requirement, you need to remove the Audience's Bag object and modify the Theater class's enter() method accordingly. This is because the Theater class relies too heavily on the specific details that audience members have bags and ticket sellers only sell tickets from the ticket booth. If any of these details change, you need to modify both the relevant class and the dependent classes (e.g., Theater).


This is a problem related to dependencies between objects, and dependencies imply the impact of changes. However, since object-oriented design aims to build a community of objects that cooperate while depending on each other, we shouldn't eliminate dependencies indiscriminately, but rather maintain only the " minimum necessary dependencies" and remove unnecessary dependencies.


When the dependencies between objects are excessive, it is referred to as high coupling– the higher the coupling between two objects, the higher the probability that they will change together. Therefore, the goal of design is to reduce coupling between objects to create a design that is easy to modify.


Improving the Design

Theater doesn't need to know that audience members have bags and that ticket sellers sell tickets from the ticket booth. Theater simply wants audience members to enter the theater. Therefore, we need to make the audience members and ticket sellers autonomous entities that handle the cash and invitations in their bags and the tickets and sales fees in the ticket booths themselves.


Increase Autonomy

Objects that perform only closely related tasks and delegate unrelated tasks to other objects are said to have high cohesion. Creating autonomous objects that handle their own data reduces coupling and increases cohesion.


Procedural vs. Object-Oriented

  • Procedural
    • Theater's enter() method is a process, and Audience, TicketSeller, Bag, and TicketOffice are data.
    • The approach of placing processes and data in separate modules is called procedural programming.
    • There is a lot of code that violates our intuition. (e.g., Audience members manage their own money and invitations.)
    • It's difficult to narrow down the impact of data changes.
    • Responsibilities are managed in a centralized manner. (Theater manages everything)
  • Object-Oriented
    • The approach of placing data and processes within the same module is called object-oriented programming.
    • We can write code that aligns with our intuition.
    • We can effectively narrow down the impact of data changes through encapsulation.
    • Each object is responsible for itself.


It Can Be Improved Further

  • The Bag class within the Audience class is still a passive entity dragged around by the Audience class, so we need to make the Bag class an autonomous object.
  • Similarly, TicketOffice within the TicketSeller class is also managed at will by TicketSeller. We need to make TicketOffice an autonomous object.
    • However, after the change, TicketOffice has an additional coupling with Audience.
    • As such, design requires careful consideration of trade-offs. In this case, we could agree to make TicketOffice a somewhat passive object to reduce coupling with Audience.



That's a Lie!

  • In reality, even if something is passive, once it enters the world of object-oriented programming, it becomes an active and autonomous entity.
  • It's a good idea to use personification and think of passive objects as entities that laugh, talk, and get angry.


Object-Oriented Design

Why is Design Necessary?

  • Design is about arranging code.
  • Good design is about fully performing today's required functions while smoothly accommodating tomorrow's changes.


Object-Oriented Design

  • Modifiable code is understandable code.
  • The object-oriented paradigm helps us write code in the way we see the world.
  • Objects are autonomous entities that are responsible for their own data.
  • Excellent object-oriented design is a design that appropriately manages dependencies between cooperating objects.


References

  • Objects

Comments0