The Essence of Object Orientation
by Kwanghee Choi
Overview & Disclaimer
This is a summary of the book The Essence of Object-Orientation: Roles, Responsibilites, and Collaborations (객체지향의 사실과 오해: 역할, 책임, 협력 관점에서 본 객체지향). Views of this book are well-known to be both surprisingly deep and refreshing, and happily for me, quite kind for beginners like myself. Unfortunately, it was originally written in Korean, and there is seemingly no translation available in English. That is the reason why I’m trying to summarize this book in English, as clearly as possible, hoping a bigger audience can cherish this book and the ideas from it. But keep in mind that, as myself is far from being a professional to this subject, this summary may contain ambiguous, or potentially hazardous ideas and expressions. Special thanks to Jisoo Kim, who recommended me this book, and Dongho Jung, who reviewed and summarized this book together.
0. Foreword
- The concept of object-orientation brings a lot of controversy in software communities, despite the fact that the concept had been widely used for decades. This phenomena tells us that there is no unified definition, or realization of the concept.
- That said, few of the possible ideas:
- OO is object oriented, not class or inheritance oriented.
- Object is not an independent existence of its own, but a collaborative community to implement a function, that each object has an adequate amount of roles and responsibility.
- Contents for each chapters
- Chapter 1 argues that the essence of OO paradigm is, autonomous objects collaborating.
- Chapter 2 tries to answer the fundamental question of “What is an object?”.
- Chapter 3 covers abstraction, or more simply put, simplifying dynamic objects to static types.
- Chapter 4 explains fundamental materials of OO: roles, responsibilities, and collaborations. Each object have a specific role for collaborations, and take responsibilities of that role.
- Chapter 5 emphasizes that messages can assure the autonomy of an object and flexibility of design.
- Chapter 6 shows two aspects of OO: structure and function. Structure is more robust to changing circumstances than function.
- Chapter 7 encompasses the earlier chapters by looking through the implementation details written in code.
1. Collaborative Community of Objects
- OO is not about mimicking real-world objects, but more about creating a whole new world that can satisfy users.
- Humans are analogous to objects.
- Humans think and decide autonomously. Objects encapsulate states and behaviors to act autonomously.
- Humans make promises to collaborate for a common goal. Objects message each other to collaborate for a single functionality.
- Coffee shop analogy
- Customer orders coffee, cashier gets orders, barista brews coffee.
- Coffee is transported back from barista, cashier to customer.
- Collaborations are made with requests and responses.
- Requests are made from customer to cashier (order coffee), cashier to barista (brew coffee).
- Responses (coffee) are made, in the opposite direction to requests.
- People (objects) are granted with roles to collaborate. Roles implicitly involves responsibilities.
- Roles are not about each specific instance, hence substitutable. (Customer doesn’t care who gets the coffee.)
- How to take responsibility is autonomously selected. Object is able to make different choice of response on same request. (Barista brews coffee on his/her own terms.) State-dependent behavior difference, or polymorphism (Ex. overridden behavior).
- One object can have multiple roles. (Cashier could also brew coffee. May have multiple roles depending on collaborative situations.)
- Object should be…
- Open: Friendly enough to cooperate. Able to message (like an open port).
- Autonomous: with own principles and control.
- To ensure openness and autonomy, object has behavior (the way how object can collaborate with other objects) and state (data needed for behaviors inside the object).
- ex) Barista has to be friendly enough to give choices to customers (message-receivable), but customers doesn’t get to dictate how barista brews coffee (method is encapsulated).
- Open: Customer (sender) sends a message (make a request) to the barista (receiver). Barista receives a message from the customer (and prepare to make a response).
- Autonomous: Customer can know what barista is brewing, but does not have to know how.
- OO is not about classes. It is about autonomous objects messaging each other. It is about maintaining collaborations between roles with responsibilities. Classes are just tools to implement those.
2. Object in Wonderland
- OO takes advantage of innate human ability of seeing the world as a set of independent and perceivable objects.
- Alice in Wonderland analogy
- Alice changes her height by eating various magical food, to achieve something, like go through a small door, or eat a large cake.
- Everything is an object if it is…
- Perceivable (human-tractable) as a single independent (separable to other objects) unit
- Can determine the time of creation (instantiation)
- Object
- Definition: Identifiable stuff. Could be real or abstract.
- Object contains state, behavior, and identifier.
- Object has a state which is changeable. (The height of Alice is changeable.)
- How object behaves changes the state of itself. (Alice changes her height by doing something.)
- Result of the behavior is state-dependent, and can be explained with the state.
- Result of the behavior is dependent of the order of behaviors.
- No matter what state is in, Alice is uniquely identifiable. (No matter how tall Alice is, Alice is Alice.)
- State
- Definition: State is the total information that the object has at a specific time.
- Every aspect of a state in a specific object is the property of the object. Value of the property can be an attribute (value) or a link (instance of correlation between other object). Property is static, property value is dynamic.
- Linear algebra analogy: Property == Spanning set, Every possible state == Span, A specific state == A specific point in space, Each aspect of a state == Each projection of a point. Properties may not be orthogonal. Identifier is orthogonal to any other property.
- Values (number, string, datetime, …) are not objects, as they are not uniquely identifiable. But values provides ways to express the state of an object.
- State is an abstraction of all the previous behaviors to reduce the complexities of the real-world.
- Object has, and should be on full control unto its own state, hence the autonomy. State and behavior are bind to one unit: an object.
- Behavior
- Definition: Doing stuff to respond to incoming messages.
- Behavior changes state (side effect), and behavior depends on the state.
- Behavior has two kinds of side effect: own state change (changing the property value), and propagating side effect to other object (via message request to callee object by link, or via message response to caller object).
- Every meaningful statement has a side effect.
- Behavior is the only way for an object to participate in collaborations.
- State encapsulation
- Only behaviors are visible, states are invisible (from the outside). The only way to manipulate its states is via behaviors.
- As the object becomes more autonomous, it gets more intelligent. In other words, collaboration gets more flexible and concise.
- If states are visible, infinitely many behaviors that can manipulate states get exposed.
- If the behavior does not depend on its state (e.g. depends only on parameters, static methods), the behavior is bad.
- Identifier
- Object (reference object, entity) vs. Value (value object)
- Identifiability
- Object is uniquely identifiable. == Object has a specific property (identifier) that makes itself distinguishable to other objects.
- Value is not uniquely identifiable. == Value does not need an identifier.
- Mutability
- Unchanging amounts are modeled by a value. Its state never changes. (Immutable state) Therefore, equality depends on the state of each values.
- Changing states (depending on time) are included within an object. (Mutable state) Therefore, two objects are identical if identifier is the same.
- Object as a machine
- Query the state of the object (read, getter), and command to change the state of the object (write, setter). No other interface to interact with the object.
- Collaboration decides what behavior (in other words, role and responsibility while collaborating) is needed. What state to manage should be decided after the behavior is set, as it ensures encapsulation and reusability, and makes an object collaborator rather than an island.
- Real-world objects are passive. Software objects are active. They can do much more stuff than real-world objects. They acts as if they are live beings. (Anthropomorphism)
- Real-world objects are just metaphors for software objects, minimizing the representational gap.
3. Type and Abstraction
- London metro analogy
- If you think about the purpose of the subway map, you can easily rule out the geographical accuracy, and concentrate more on showing the connection between stations effectively.
- Use abstraction, or decomposition (to choose important stuff from this world) and simplification (to easily understand), to make this world easier and predictable, and hence, understandable.
- Abstraction is …
- Dimension 1: Generalization among specific objects: Commonness chosen, difference discarded.
- Dimension 2: Remove the unimportant details to emphasize the important parts.
- Levels, benefits, values of abstraction is purpose-dependent.
- Classification: Abstraction with grouping (by categories, concepts, or types)
- Each object has features that can be used to clearly differentiate between other objects.
- Use common features (a concept) to classify objects, hence reducing the complexity of perception: objects to groups.
- Object is an instance of a concept (when the concept is applicable to the object).
- Symbol: Name for a specific concept.
- Intension: Complete definition of a concept. Determines whether or not the object is of a concept.
- Classification of objects is essentially checking the applicability of specific concepts to each object.
- Extension: Set of all objects which satisfies the concept.
- Choosing the common features (Dimension 1) effectively remove the unimportant details (Dimension 2), hence the success of abstraction.
- Responsibility-driven: Abstraction by decoupling What and How (vs. Data-driven)
- Datatype
- Computer memory is typeless; every data is represented as a bit string.
- Type system: Classifying these bit strings to serve a specific purpose.
- Defining constraints of how to read and manipulate those bit strings.
- ex) Let’s define these consecutive 8 bits as int, and define various operations on it. Now, there is no need of knowing how int is stored in the memory.
- Datatype is a metadata to classify various bit strings, which implicitly defines what kind of operations are applicable to that bit string.
- Datatypes are analogous to types (of objects)
- Type of the object is chosen by object operations. (Polymorphism, Duck typing, What it does)
- ex) Operates the same == Same responsibility == Same message (but may have different response)
- Type of the object is regardless of internal implementations. (Encapsulation, How is it implemented)
- ex) Objects of the same type can handle same messages, regardless of implementation.
- Type of the object is chosen by object operations. (Polymorphism, Duck typing, What it does)
- Responsibility-driven Design (vs. Data-driven design)
- Choose responsibilities (operations) first, then decide the internal data to manage the responsibilities.
- Datatype
- Hierarchy of types: Responsibility(behavior), not data(state), decides the hierarchy.
- A is a generalization of B (Dimension 2: Remove features to define A), B is a specialization of A (Dimension 1: Commonness chosen to define B).
- Extension of A $\supset$ Extension of B
- Intension of A $\subset$ Intension of B
- A is a supertype of B, B is a subtype of A.
- A is a generalization of B (Dimension 2: Remove features to define A), B is a specialization of A (Dimension 1: Commonness chosen to define B).
- Classification and Type Hierarchy (Generalization & Specialization) are tools for Abstraction.
- Classification defines a filter, Generalization/Specialization adjusts strength of a filter.
- The result of classification on a superclass is a subclass.
- Type (which can display properties) is an abstraction for dynamic characteristics (dynamically changing property values) of objects.
- Dynamic model (Object diagram, shows multiple snapshots of objects) vs. Static model (Type diagram, shows every possible behaviors and states, which is an abstraction of multiple snapshots)
- Class is a way to implement a type.
4. Roles, Responsibilities, Collaborations
- Overall quality depends on collaborations between objects, not on each object. Therefore, it is meaningless to think about states and behaviors without the context of collaborations.
- Collaborations $\to$ Messages $\to$ Responsibilities
- Collaboration is a series of requests and responses from a single initial request, which is to achieve a common goal.
- Callee receives request from the caller, because callee has the ability and obligation to successfully respond. Therefore, requests and responses (messages) define a responsibility that each object has to undertake.
- Responsibilities are a list of services and information, which forms a public interface.
- Doing (service, command): doing for oneself, or initialize/control others.
- Knowing (information, query): knowing/deriving from oneself (innate info), or knowing about related others.
- Message, which the caller can send, and the callee can understand, is the only way to collaborate.
- Responsibility concentrates on what the object can undertake; message concentrates on the relationship between caller and callee.
- While implementing a single responsibility, it gets converted into one or more messages. (e.g. sequential messages, or various kinds of messages)
- Responsibilities $\to$ Behaviors
- A set of responsibilities that the object has to undertake implicitly defines a role inside a collaboration. (Role is an abstraction of objects having common responsibilities)
- Abstraction of collaborations can be made by replacing objects into roles, like a placeholder, therefore achieving simplicity (purpose of abstraction itself), flexibility (not propagating changes of the callee to the outside) and reusability (in another collaborative situation).
- Roles imply behavior compatibility, and hence substitutability among objects.
- Object may have more than one role, so type is usually a specialization of role.
- Let there be a set of objects. Object can be classified via roles (Intension: Does the object has the role or not?). Some objects can be inside the intersection (Objects who have multiple roles). Each partition of the set of the whole object can be defined as type.
- ex) Role: AbstractClass (Closed for modification), Type: ImplementedClass (Extended by openness of AbstractClass)
- OO is not about concentrating on relationship between classes, as classes are a mere tool to concentrate on collaboration between objects.
- OO is about assigning adequate responsibilities to adequate objects. Good OO practice is about thinking objects in a collaborative context.
- Design techniques for good OO practice
- Responsibility-Driven Design: a way to design
- Split a large responsibility of a system into small responsibilities of each objects.
- Each responsibility is assigned to an object.
- If some help is needed while taking the responsibility, find another object that can help.
- Now a large job is a collaboration between objects.
- Design Pattern: example designs
- Pre-distinguished collections of roles, responsibilities and collaborations that solves frequently occurring problems.
- Test-Driven Development
- Distinguishing roles, responsibilities and collaborations with specific tests and checking out conformity from those tests.
- Tests are an additional bonus, not the fundamental purpose for TDD.
- Writing a failing test (Red) $\to$ Write minimum code that passes (Green) $\to$ Refactor
- Writing a test == Implementing expectations for objects
- Expected responses on requests
- Verifying that the object has took the responsibility
- Expected collaboration of objects
- Verifying that the testing object has correctly collaborated with the other objects
- Needs stubs (inject indirect inputs, or responses from another object which affect the testing object) and mocks (handle indirect outputs, or requests done from the testing object to another object)
- Note. Controversy between Mockists vs. Classicists
- Expected responses on requests
- Responsibility-Driven Design: a way to design
5. Responsibility and Message
- Objects taking responsibility autonomously
- Responsibility: behaviors of objects responding to a message (which is the only way to trigger behaviors)
- Message triggers behavior == Message triggers responsibility
- Responsibility: behaviors of objects responding to a message (which is the only way to trigger behaviors)
- Level of responsibility that the object has to take has to be autonomous enough for the object to take the responsibility autonomously.
- Responsibilities should be abstract/comprehensive (to ensure autonomy of implementation, or, enough range of freedom for the callee to behave) and clear enough (for the intention of collaboration to be expressed clearly).
- If not, the callee has to depend on the orders of the caller, and hence not depending on own implementation, therefore impossible to take responsibility autonomously. (Callee behaves depending on incoming message, not the caller.)
- Amount of abstraction/comprehensiveness needed differs by context (trade-off between abstraction/comprehensiveness and clarity), which makes OO design hard but attractive.
- If an object encompasses too much functionality, (The result of maximum abstraction in a qualitative sense is doing, in a quantitative sense is too many responsibilities) the responsibility of the object becomes ambiguous, hence failing to collaborate.
- Not how, but what responsibility to take.
- Structure of message sending (how to trigger the callee object)
- { Callee object }.{ Message name }( { Message arguments } )
- ex) mad_hatter.testify(yesterday, kingdom)
- Message structure (Function signature) is an abstraction of all the possible messages using the message name
- ex) .testify(yesterday, kingdom) == { .testify(190101, here), .testify(190102, there), … }
- Message vs. Method
- The object is able to receive the message and respond successfully == The object should, and is able to take the responsibility of the message
- How responsibility is taken is hidden from the outside of the object. Messages are the boundary of the object. Internal methods (how) are chosen by the callee on runtime to handle messages (what) from the outside caller.
- Polymorphism is …
- Ability to send the same message (obligation to take the same responsibility) to different types of objects, hence different methods are chosen. (1:N relationship between messages and methods)
- Substitutability between objects who have the same responsibilities. (Encapsulation of the type of callee from the perspective of the caller)
- Achieved by autonomy of each object; not with enough autonomy, behavior depends not only on message, but also on outside of the object, hence jeopardizing polymorphism.
- Achieved by transforming strong coupling between types of objects into loose coupling with messages.
- Loose coupling of callee and caller based on messages makes the design …
- Flexible == Callee can change implementations without propagating changes to the caller, because caller doesn’t care about callee until it understands the message.
- Extensible == How objects collaborate (implementation of the caller on that specific collaborative situation) are easily extensible.
- Reusable == Collaborations are easily reused among different contexts by switching callees.
- Each object may be mediocre, but web of objects are more than a mere sum of them.
- Power of OO design comes not from classes or polymorphism, but from messages. OO app is made from classes, but defined by messages.
- Responsibility-Driven Development
- Object is defined by the needs of other objects. Therefore, definition == interface.
- Concentrating not on the collaboration (message, responsibility-driven) and on the object itself (abstract data type == data and its operations, data-driven) makes internal structure of the object as part of the definition of the object (== interface depends on the implementation), hence harming the autonomy.
- Functionality of an application $\to$ Responsibility of a system $\to$ Responsibility of the object which starts the collaboration $\to$ Messages toward others so that the object can take the responsibility $\to$ Choosing adequate callees that can take the part of the responsibility $\to$ Taking the required responsibility requested from the caller
- Message chooses the responsibility of the callee.
- What/Who Cycle: First, choose what to do (message, responsibility), regardless of the properties of each object. Then choose who does it (callee object), hence the responsibility is decided afterwards. == Interface Discovery @ TDD
- Callee object is chosen after the message is chosen, so caller cannot know the internals of the callee. Caller has no choice but to trust the callee to deal with the message.
- Message depending on the state of the callee is the proof for harming the autonomy. Delay the decision, and make the callee decide.
- Law of Demeter: Tell (what to do), Don’t Ask (how to do it)
- Concentrating on what, not how, makes the interface of the callee smaller $\to$ Dependencies needed by the caller decreases $\to$ Strength of the coupling between caller and callee loosens $\to$ Better flexibility and encapsulation (less propagating/effectively hiding callee modifications), Clear intentions (clear message for clear collaboration), Better Autonomy (making enough room for implementation)
- Trust the message. Autonomous responsibilities will follow.
- Characteristics of an interface
- If the user get used to the interface of an object, you don’t have to know the internals to do something with the object. (Abstraction of implementation by encapsulation) ex) Driving a car
- Changing the internals (implementation) does not affect the end user. (Flexibility by loose coupling) ex) Changing the engine of a car
- If the user is familiar to the interface, user can easily utilize other objects with the same interface. (Reusability by loose coupling) ex) Different car, same person.
- Interface is a list of digestible messages (function signatures).
- Only difference between private (internal) and public (external) interface is that the private interface is only accessible to its own. The object has to message at itself if it needs some help from itself, hence loosening coupling between its own methods.
- Result of using the interface: loose coupling & information gets hidden.
- Separation of public interface (externals) and implementation (internals) principle
- Implementation: Object’s internal structure and how it works (states and methods). Everything except the public interface.
- Behavior: Means of the callee (method) to handle the incoming message
- Separation of stuff that can be changed (implementation) and that cannot be changed (public interface)
- Because software always changes: grasping every side effects of every modifications (modification propagation) is near impossible.
- Because it makes the object autonomous: it gives the ability to choose the method without affecting outside.
- Caller and callee should be loosely coupled with the interface (coupling to a type), not strongly coupled with the implementation (coupling to a specific object).
- Two viewpoints of encapsulation
- Data encapsulation: Packaging of state and behavior
- Prerequisite for the separation of interface and implementation
- Prerequisite for the object autonomy
- Information hiding: Hiding private secrets and frequently changeable stuff
- To minimize interference from the outside / error propagation to the outside, hence guaranteeing autonomy.
- Data encapsulation: Packaging of state and behavior
- Object-oriented mindset: Autonomy (Callee not having to care about the caller) vs. Flexibility (Caller not having to care about the callee modification)
- More abstract interface (autonomous responsibility) guarantees autonomy of the callee object.
- Minimal interface (while complying with the message) exposes minimal amount of internals to the outside world, hence minimizing the effect of changing the implementation (flexibility).
- Awareness for the difference between interface and implementation (strict separation between inside and outside of the object) to guarantee both autonomy and flexibility.
- Some collaborations are superior to others, because it is more easily understandable, and robust to changes. Superiority between those is determined by autonomous responsibility (== adequate amount of responsibility spread between caller and callee by the means of abstraction/clarity), because…
- Responsibility gets adequately abstracted (it shows intentions without the details), hence collborations are made simple.
- Private stuff that the caller doesn’t need to know gets encapsulated, hence clear separation between interface and implementation.
- Modification gets encapsulated inside the object, hence loose coupling between caller and callee.
- Callee and caller are loosely coupled only with messages, hence flexibility and reusability of designs (collaboration situations) is achieved.
- High cohesion of the object (Object is bound with the responsibilities with the same purpose), hence the role of the object is easily understandable.
6. Object Map
- Analogy of pathfinding: two approaches for pathfinding from location A to B
- Functional, solution-directed approach (find the solution with function)
- ex) Go straight 100m, turn left, …
- Not able to generalize, not reusable.
- Structural, problem-directed approach (understand the problem with structure)
- ex) Use the map to find the specific path
- Map is an abstract model based on real-world locations (stable information). Hence it has enough context information to find the exact path on general occasions.
- Functional, solution-directed approach (find the solution with function)
- Subordinate function to structure:
- More easily understandable: benefit of abstraction
- It generalizes better: able to find a general way of finding the solution (abstraction of function)
- Robust to changing requirements: many solutions (functions) can be generated from a single problem (structure)
- Successful softwares offer not only great functionalities, but also the speed(easily understandable) and stability(robustness) when adding new functionalities.
- Requirements always change. Best way to prepare it is not to predict the future itself, but to make room for choices that can accept changes. Lowering the cost of modification is the primary reason for software design.
- Function is a service for users. Structure is a base to implement the function.
- Structure is expressed via domain model.
- Domain: Field of interest (set of knowledge, concepts and relations between concepts) that solves specific set of problems.
- Domain Model: Explanation of how something works. Abstraction of domain. A mental model for the people who cares about the problem (stakeholders).
- Conceptualization: ex) There are no folders inside the computer. Folders are an effective conceptualization of the part of the file system. File system is an effective conceptualization of physical storages. It makes them easier to use. [Norman 1988]
- User model: Domain model of users. Generated from the product (system).
- Design model: Designer’s conception of look, feel and operation of the product. [Norman 1988]
- System Image: How the system is perceived through the physical product and the peripheral information surrounding the product: documentations, reviews, …
- User and designer cannot directly interact with each other. They use product (system) as their medium. That is why the system image, which is formulated around the system, which is built upon the design model, has to reflect the user model.
- User model, design model and system image can be made similar to each other (minimize the representational/semantic gap between real world objects (concepts from the user model) and software objects using metaphor) with OO paradigm: Seamlessness of OO paradigm.
- User understands the essentials of the domain better than any other. Essentials are usually not volatile. Therefore, user model provides stable structure that can contain functions.
- Function is expressed via use case.
- Concentrate on the interaction between user (with a specific purpose) and system (does a series of procedures to serve that purpose) to find good functional requirements.
- Use case
- Flow of interactions between user and system to achieve purpose of the user
- Understanding contract between the system and its stakeholders while concentrating on actions
- Actor: A role that a particular person, people, or a computer system, is playing when they use the system under design. [Cockburn 1999]
- Primary Actor: A particular actor that is associated with a use case. The use case satisfies the need of the primary actor, who initially starts the interaction with the system. [Cockburn 1999]
- Stakeholder: A person with a vested interest in the behavior inside the use case. [Cockburn 1999]
- Scenario: Sequence of interactions that happens under certain conditions, with the intent to achieve the primary actor’s goal, and having a particular result with respect to that goal. [Cockburn 1999]
- A use case is a set of scenarios tied together by a common goal of the user. [Fowler 2003]
- Systematic relations between sporadic functions can be found by providing the intent to achieve the primary actor’s goal.
- Characteristics of use case
- It’s a story written in text, not a diagram. It should be about the flow of interaction Between user and system.
- Use case is a directed acyclic graph (interactions as nodes). Scenario is one of those paths. Scenario is also called use case instance.
- Use case is not a list of features (Feature is a list of functions). Stakeholders can easily communicate with the help of context, which is generated by grouping multiple features with a use case and including features in the flow of interaction.
- Use case should not include UI, which is volatile. (Essential use case)
- Use case only includes public interface of the system. Therefore, it is impossible to deduct the implementation of each objects from the use case. However, it may include hints about the terms that can be used in the domain model.
- Structure is expressed via domain model.
- System as a whole, is an object, which collaborates with the user via message to satisfy the goal of the user. Therefore, functional requirements of the system is now the responsibility of the system.
- Responsibility-driven development
- Use case identifies functional requirements. Functional requirements of the system $\to$ Responsibilities of the system (which is an object)
- Domain model supplies stable structure that can accept volatile functional requirements.
- RDD integrates those two above.
- Recursive Composition (of Smalltalk)
- Why split computers into data structure (state) and procedure (behavior)? Just accept computer as an object.
- Each Smalltalk object is a little computer (autonomous object).
- An object is able to split into little objects recursively.
- Symbol is borrowed from the concepts in the domain model, resulting narrow semantic gap, exploiting tacit knowledge that usually remains unchanged.
- Reversibility: Domain model modifications can be deducted from the modifications of the code itself.
7. Summing up
- Three correlated perspectives of OO design (Ex. If class is used while designing, class can be perceived with these three perspectives. It doesn’t mean that it is perceived sequentially throughout the process.)
- Conceptual Perspective: Relationship between concepts inside the domain model and the types (concepts). (Ex. Class expresses type metaphorically. Type reflects the domain model perspective.)
- Specification Perspective: “What objects can do” (interface), in a collaborative situation. Note. Separation between interface and implementation. (Ex. Public interface of class.)
- Implementation Perspective: “How objects can take responsibility”. (Ex. Implementation of methods and attributes of class.)
- Steps for implementing a coffee shop analogy
-
- Domain model
- There are five concepts in a coffee shop domain: customer, menu, menu item, barista, coffee.
- Classifying objects into types. Ex. americano, espresso, … $\to$ coffee
- Menu item and menu cannot be separated $\to$ Containment/Composition relationship between menu item and menu. (Menu item is included in menu.)
- Customer has to know the menu to order $\to$ Association relationship between customer and menu.
- Domain model
-
- Designing collaborations
- First message: .order_coffee(menu_name) $\to$ Coffee
- Customer has to take responsibility of ordering a coffee. $\to$ customer.order_coffee(menu_name)
- Customer doesn’t know about the menu items. $\to$ Customer has to ask another object for that responsibility: .find_menu_item(menu_name) $\to$ MenuItem
- Menu has to take responsibility of finding a menu item from a menu name, as menu items are included inside the menu. $\to$ menu.find_menu_item(menu_name)
- After customer finding out the menu item, it can request to make coffee: .make_coffee(menu_item) $\to$ Coffee
- Barista has to take responsibility of making coffee, as barista knows all the information about making coffee. (Barista’s knowledge == State, Barista’s techniques == Behavior) $\to$ barista.make_coffee(menu_item)
- Designing collaborations
-
- Coding
- Customer object has to know about the Menu object and the Barista object. This problem can be resolved by modifying the previously found interface of the customer: customer.order_coffee(String menu_name, Menu menu, Barista barista)
- Note that the interface has changed during implementation. Coding is more important than designing. Quickly start coding to get the feedback for better designs. - For the Menu object to take responsibility of finding the MenuItem object, the Menu object has to manage MenuItem objects internally: Menu(List
- Note that making list of MenuItem objects as an attribute of Menu object is determined while implementing, not while desigining: Seperation of interface and implementation. - MenuItem has to provide operations for comparison with the String menu_name: menu_item.equals(String menu_name)
- Note that the operation of the MenuItem is determined while implementing, as it is near impossible to predict the shape of the interface before really collaborating. Quickly dive into implementing functions to sketch the whole collaboration. Ex. TDD
- Coding
- Three perspectives of coffee shop implementation
- Conceptual perspective: Classes successfully reflect domain model’s concepts and relationship between concepts. Ex. Modify Barista code to modify how coffee is made.
- Specification perspective: Public interface of each classes.
- Implementation perspective: Methods and attributes of each classes. Modifications made to those secrets should not propagate to other outside objects.
-
- Make your code to easily show those three perspectives. It is the quickest way to deal with modifications flexibly.
- Refer to the domain model to clearly show the conceptual perspective.
- Clear line between specification and implementation perspective.
Appendix: Abstraction Techniques
- Abstraction hides specific parts of an object to lower the complexity.
- The biggest advantage of OOP: Able to apply same abstraction techniques to each steps of analyzing, designing, and implementing a program.
- Technique 1: Classification & Instantiation
- Classification is forming a category based on common features and removing the details between different objects, or in other words, applying a common concept to objects. Instantiation is generating an object from a category.
- Single vs. Multiple classification
- Single classification: Every object has a single type.
- Multiple classification: Some object may exist as an instance of multiple types.
- vs. Multiple inheritance: Type may inherit multiple types, but object must be an instance of a single type.
- Dynamic vs. Static classification
- Dynamic classification: Object may change its type throughout its lifespan.
- Static classification: Object is bound to a single type throughout its lifespan.
- Using multiple classification and dynamic classification makes analyzing the domain in a conceptual perspective easy. But majority of OO languages prohibit those two, so it is realistic only to make a sketch out of those, and then recalibrating categories to follow the single classification and static classification before the implementation.
- Class-based OO languages are based on Aristotle’s philosophy: there is a universal way to classify objects, as you can extract the essense of the object, and accidental attributes remains after the extraction. It concentrates on where that object is located in the taxonomy.
- Other OO languages doesn’t believe in that philosophy. It concentrates on what the object can do. Ex. Prototype-based OO language: Classification and Instantiation is made by copying a prototype object.
- Technique 2: Generalization & Specialization
- Generaliation hides differences between categories, and concentrates on the common feature among categories. Specialization is the exact opposite.
- Is-a & 100% Rule [Larman 2004]
- Is-a Rule: Rule about extension - every instance of a subtype has to be included in a supertype.
- 100% Rule: Rule about intension - every definition of a supertype has to be 100% applicable to a subtype. Subtype has to conform to a supertype.
- Structural conformance vs. Behavioral conformance
- Structural conformance: State that the instance of the subtype has conforms to the state that the instance of the supertype has.
- Behavioral conformance (Liskov Substitution Principle): Behavior that the instance of the subtype has conforms to the behavior that the instance of the supertype has.
- Inheritance using class: Interface inheritance vs. Implementation inheritance
- Interface inheritance (Subtyping): Instance of a subclass can substitute instance of a superclass. Subclass and superclass has the structural or behavioral conformance relationship.
- Implementation inheritance (Subclassing): Instance of a subclass cannot substitute instance of a superclass. Avoiding this makes code more flexible and reusable.
- Delegation is a way of understanding messages in an inheritance hierarchy. By delegation, subtype can understand every message that supertype can understand.
- Delegation in Class-based OO: Delegation to a superclass
- Delegation in Prototype-based OO: Delegation to a parent object
- Technique 3: Composition & Decomposition
- Composition forms a whole by hiding specifics related to parts. Decomposition splits a whole to multiple parts.
- Clockmaker analogy
- Making from scratch is far more harder than making from components. (Recursive design between the whole and the parts)
- Time it takes to make complex objects from simpler objects depends on the amount of interim stable structures.
- Composition hides the unnecessary details of parts, so it is both abstraction technique and encapsulation technique.
- Human instinct helps drawing a boundary dividing each objects on ambiguous situations.
- Composition encapsulates parts inside a whole, so it prevents cognitive overload.
- Composition vs. Association: Generally, there is no constraints between lifecycles of associated objects. But, as composition is a whole-to-parts relationship, every parts have to be removed with the whole.
- Gather highly cohesive classes into a module or a package to make a software easily understandable.
References
- Note that cited sentences may be summarized, paraphrased or rewritten. But due to limitations of myself, modifications may changed the original intention of the writer.
- Norman 1988: Donald A. Norman, The Psychology of Everyday Things
- Cockburn 1999: Alistair Cockburn, Writing Effective Use Cases
- Fowler 2003: UML Distilled: A Brief Guide to the Standard Object Modeling Language
- Larman 2004: Applying UML and Patterns: An introduction to Object-Oriented Analysis and Design and the Unified Process
Subscribe via RSS