CSC/ECE 517 Fall 2012/ch1b 1w44 as: Difference between revisions
Line 147: | Line 147: | ||
[http://en.wikipedia.org/wiki/Code_smell Code Smells]or Bad smells are used to identify problematic classes in object-oriented design[20]. They can also be used to measure the evolvability of software [21]. code smells are broadly classified into 5 categories [21]. | [http://en.wikipedia.org/wiki/Code_smell Code Smells]or Bad smells are used to identify problematic classes in object-oriented design[20]. They can also be used to measure the evolvability of software [21]. code smells are broadly classified into 5 categories [21]. | ||
[[File:bad-code-smells.jpg|center|border|600px|An image showing classification of code smells]] | [[File:bad-code-smells.jpg|center|border|600px|An image showing classification of code smells]] | ||
<center>Figure 1: An image showing classification of code smells</center> | <center>Figure 1: An image showing classification of code smells</center><br><br> | ||
{| border="1" cellpadding="2" | {| border="1" cellpadding="2" | ||
! scope="col" width="100px" | Group Name | ! scope="col" width="100px" | Group Name | ||
Line 163: | Line 163: | ||
|- | |- | ||
| <b>The Couplers</b> || -Feature Envy<br>-Inappropriate Intimacy<br>-Message Chains<br>-Middle Man<br> || This group has four coupling-related smells.<br><br>One design principle that has been around for decades is low coupling (Stevens et al. 1974) . This group has 3 smells that represent high coupling. Middle Man smell on the other hand represent a problem that might be created when trying to avoid high coupling with constant delegation. Middle Man is a class that is doing too much simple delegation instead of really contributing to the application.<br><br>The Feature Envy smell means a case where one method is too interested in other classes, and the Inappropriate Intimacy smell means that two classes are coupled tightly to each other. Message Chains is a smell where class A needs data from class D. To access this data, class A needs to retrieve object C from object B (A and B have a direct reference). When class A gets object C it then asks C to get object D. When class A finally has a reference to class D, A asks D for the data it needs. The problem here is that A becomes unnecessarily coupled to classes B, C, and D, when it only needs some piece of data from class D. The following example illustrates the message chain smell: A.getB().getC().getD().getTheNeededData()<br><br>Of course, I could make an argument that these smells should belong to the Object-Orientation abusers group, but since they all focus strictly on coupling, I think it makes the taxonomy more understandable if they are introduced in a group of their own. | | <b>The Couplers</b> || -Feature Envy<br>-Inappropriate Intimacy<br>-Message Chains<br>-Middle Man<br> || This group has four coupling-related smells.<br><br>One design principle that has been around for decades is low coupling (Stevens et al. 1974) . This group has 3 smells that represent high coupling. Middle Man smell on the other hand represent a problem that might be created when trying to avoid high coupling with constant delegation. Middle Man is a class that is doing too much simple delegation instead of really contributing to the application.<br><br>The Feature Envy smell means a case where one method is too interested in other classes, and the Inappropriate Intimacy smell means that two classes are coupled tightly to each other. Message Chains is a smell where class A needs data from class D. To access this data, class A needs to retrieve object C from object B (A and B have a direct reference). When class A gets object C it then asks C to get object D. When class A finally has a reference to class D, A asks D for the data it needs. The problem here is that A becomes unnecessarily coupled to classes B, C, and D, when it only needs some piece of data from class D. The following example illustrates the message chain smell: A.getB().getC().getD().getTheNeededData()<br><br>Of course, I could make an argument that these smells should belong to the Object-Orientation abusers group, but since they all focus strictly on coupling, I think it makes the taxonomy more understandable if they are introduced in a group of their own. | ||
|}< | |} | ||
<center>Table 1: Code Smells Clasification</center><br><br> | |||
==Tips for a good OOD== | ==Tips for a good OOD== |
Revision as of 05:22, 27 September 2012
Introduction
Object-Oriented design is a methodology to develop a solution by creating structured objects which interact with each other through well defined interfaces. The object interaction involves invocation of required services and exchange of corresponding data. An object contains data and set of methods or procedires which act on that data. Access to data can be controlled based on access specifiers.
In this wiki page, we will introduce the factors that relevant to software project success and failure. And we will focus on analyzing how Object Oriented Design (OOD) affects the success of software. In the later part of this wiki page, we will demonstrate and analysis some examples of software failures which due to poor OOD.
Software success and failure
What is software success
The general definition of software project success is - projects delivered on time, in scope (software quality is satisfied) and within planned costs. [1] It is just a most simplistic definition of software project success because it merely relies on the schedule and budget. In fact, it is hard to tell whether software is a success or failure one, because business success, at sometime, is more essential than technical success. [2] This means that the software which is being implemented must create value that business needed, such as making profit, rather than simply achieve the software goal and requirement.
In The Strategic Project Office, written by J. Kent Crawford, [3] we can find some more specific success criteria mentioned to address alignment between project goals, business requirements, and outcomes:
The organization’s strategies are executed according to plan. The organization’s shareholders are satisfied. The organization is financially successful. Projects are completed on schedule and on budget. Project customers are satisfied. Project resources are allocated optimally. Projects are aligned to the organization’s business strategy. The organization works on the right projects.
What is software failure
Compared with software success, it is relative easier to define software failure. It can be definite as “(1) being over-scheduled by more than 30% and/or, (2) being over-budget by more than 30% and/or, (3) the end product did not meet user requirements. These three criteria cover the schedule, budget, and requirement, all surrounded by quality that should comprise all projects.”[5].
Factors leading to software failure
Most software project can be considered partial failures since only few of them meet the schedule, cost and requirement objective. According to many studies, failure rate of software projects is between 50% - 80%. [6] In most of the cases, the software projects fail because we do not recognize that good engineering principles should be applied to software projects similar to building office buildings. Below are some factors that may lead to the software failure in no particular order:
Poor user input
It is possible that a titanic project which meets all the requirements ultimately may fail because the system did not meet the user's needs.
Vague requirement
People cannot design a process that assumes the requirement is stable. Projects can be headed for trouble if architectures and processes are not change-friendly, or if there are poorly established guidelines that determine how and when requirements can be added, removed, and implemented—and who will shoulder the cost of the changes.
Poor cost and schedule estimation
Although it is unfair to call software project a failure when it cannot meet the budget and scheduled goals that were inherently unattainable, every software project has a minimum achievable cost and schedule.
Skills that doesn't match the job
This is an obvious reason; Example: Managers can perform poorly if they lead projects that do not match their strengths.
Communication breakdown
Communication breakdown may lead to low efficiency and even the project failure. Especially large software project which is done by different groups in various sites, same code may be tested two times because no one knows the other exist.
Poor architecture
This is because people never think ahead about what is likely to change. Once the software is developed in an inflexible way, it may be outdate quickly after it is released and may cause problems because it cannot deal with the continue change incomes. For this reason, we come to realize why OOD is so important in software development.
What is Object Oriented Design (OOD)
Object Oriented Design (OOD) is the concept that forces programmers to plan out their code in order to have a better flowing program [7]. Simply speaking, OOD is all about objects. An object can be considered as a “black box” which receives and sends messages. Code (sequence of computer instructions) and data (information that instructions operates on) are included in this “black box”. [8] Interface is used in the object and everything an object can do is represented by its message interface. OOD mechanisms such as inheritance, polymorphism, information hiding and coupling, can influence quality characteristics like reliability or maintainability [19].
Simple example of OOD
Here we give a simple example of coding used in both non-object-oriented-design and object-oriented-design.
If we want to add two names together in non-object-oriented language such C. We first define a data type as list which will be defined as structure in C:
structure list { <definition of list structure data here> }; list a, b, c; a = “Adam”; b = “Eva”; c = a + b;
We expect to get the result as “Adam Eva” but it doesn’t work actually in C. C complier will generate error when adding a and b because it only know how to add number while “Adam” and “Eva” are not.
Let try this example again in Object-oriented language such as Ruby, we write the code as below:
a = “Adam” b =”Eva” c = a + b puts c
The object a is created with string “Adam” and object b is created with string “Eva”. After entering the code, we can get the result “AdamEva”. Ruby complier knows how to manipulate the message “+” and that’s why object c gets new value.
Tools help for OOD
Object Oriented Design is defined as a programming language that has 5 conceptual tools to aid the programmer. These programs are often more readable than non-object oriented programs, and debugging becomes easier with locality.[9]
Language Concepts
The 5 Basic Concepts of Object Oriented Design are the implementation level features that are built into the programming language. These features are often referred to by these common names:
Encapsulation:Encapsulation refers to a tight coupling or association of data structures with the methods or functions that act on the data. This is called a class, or object (an object is often the implementation of a class).
Data Protection:Data Protection is the ability to protect some components of the object from external entities. This is realized by language keywords to enable a variable to be declared as private or protected to the owning class.
Inheritance:Inheritance defines the ability for a class to extend or override functionality of another class. The so called child class has a whole section that is the parent class and then it has its own set of functions and data.
Interface:Interface is a definition of functions or methods, and their signatures that are available for use to manipulate a given instance of an object.
Polymorphism:Polymorphism refers to the ability to define different functions or classes as having the same name but taking different data types.
Programming Concepts
There are several concepts that were derived from the new languages once they became popular. The new standards that came around pushed on three major things:
Re-usability:The ability to reuse code for multiple applications. If a programmer has already written a power function, then it should be written that any program can make a call to that function and it should work exactly the same.
Privacy:This is important for large programs and preventing loss of data.
Documentation:The commenting of a program in mark up that will not be converted to machine code. This mark up can be as long as the programmer wants, and allows for comprehensive information to be passed on to new programmers. This is important for both the re-usability and the maintainability of programs.
How to achieve a good OOD
“Good design and programming is not learned by generalities, but by seeing how significant programs can be made clean, easy to read, easy to maintain and modify human-engineered, efficient, and reliable, by the application of good and programming practices. Careful study and imitation of good designs and programs significantly improves development skills.”--Kernighan & Plauger
At the heart of great design are a set of principles and patterns. Design principles form the foundation of good object-oriented design and design patterns provide general repeatable solutions for common software problems. [10]
Design principles
Design principles are guidelines and heuristics for a good object oriented designs. There are many different design principles of Object-Oriented Design. Here are 4 major principles of them:
Encapsulation
In a nutshell, Encapsulation is the hiding of data implementation by restricting access to accessors and mutators. An accessor, usually in the form of properties in OOP, is a method that is used to ask an object about itself. Accessor has a get method, which is an accessor method. Mutator is used to modify the state of an object. It is a public method, and hides the implementation of exactly how the data gets modified.
Abstraction
Abstraction is the development of a software object. It denotes a model, a view, or some other focused-representations for an object we can actually find in the real world. It can be used to decompose complex systems into smaller by software developers.
Inheritance
Objects can relate to each other with either a “has a”, “uses a” or an “is a” relationship. “Is a” is the inheritance way of object relationship.[11]
Polymorphism
Meaning one name, many forms, polymorphism manifests itself by having multiple methods all with the same name, but slightly different functionality. There are two basic types of polymorphism: overriding, also called run-time polymorphism, and overloading, which is referred to as compile-time polymorphism.
Design patterns
Design pattern is a general reusable solution to a commonly occurring problem within a given context. It is a template describing how to solve a problem, which cannot be transformed directly into code. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Many patterns imply object-orientation or more generally mutable state, and so may not be as applicable in functional programming languages, in which data is immutable or treated as such. [12]
There are many types of design patterns, like
Creator
As one of the most common activities in an object-oriented system, creator pattern maintains a fundamental property of the relationship between objects of particular classes: class is responsible for creating objects. That is to say, creator pattern is responsible for creating an object of class.
Controller
The Controller pattern assigns the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. A Controller object is a non-user interface object responsible for receiving or handling a system event. [13]
High Cohesion
High cohesion means that the responsibilities of a given element are strongly related and highly focused. It is an evaluative pattern generally used in support of Low Coupling, which can keep objects appropriately focused, manageable and understandable.
Indirection
By assigning the responsibility of mediation between two elements to an intermediate object, the Indirection pattern supports low coupling and reuse potential between them. An example of this is the introduction of a controller component for mediation between data (model) and its representation (view) in the Model-view-controller pattern. [13]
Protected Variations
By wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface, the Protected Variations pattern protects elements from the variations on other elements, like objects, systems and subsystems.
Identifying Code Smells
Code Smellsor Bad smells are used to identify problematic classes in object-oriented design[20]. They can also be used to measure the evolvability of software [21]. code smells are broadly classified into 5 categories [21].
Group Name | Smells in Group | Discussion |
---|---|---|
The Bloaters | -Long Method -Large Class -Primitive Obsession -Long Parameter List -DataClumps |
Bloater smells represents something that has grown so large that it cannot be effectively handled. It seems likely that these smells grow a little bit at a time. Hopefully nobody designs, e.g., Long Methods. Primitive Obsession is actually more of a symptom that causes bloats than a bloat itself. The same holds for Data Clumps. When a Primitive Obsession exists, there are no small classes for small entities (e.g. phone numbers). Thus, the functionality is added to some other class, which increases the class and method size in the software. With Data Clumps there exists a set of primitives that always appear together (e.g. 3 integers for RGB colors). Since these data items are not encapsulated in a class this increases the sizes of methods and classes. |
The Object-Orientation Abusers | -Switch Statements -Temporary Field -Refused Bequest -Alternative Classes with Different Interfaces |
The common denominator for the smells in the Object-Orientation Abuser category is that they represent cases where the solution does not fully exploit the possibilities of object-oriented design. For example, a Switch Statement might be considered acceptable or even good design in procedural programming, but is something that should be avoided in object-oriented programming. The situation where switch statements or type codes are needed should be handled by creating subclasses. Parallel Inheritance Hierarchies and Refused Bequest smells lack proper inheritance design, which is one of the key elements in object-oriented programming. The Alternative Classes with Different Interfaces smell lacks a common interface for closely related classes, so it can also be considered a certain type of inheritance misuse. The Temporary Field smell means a case in which a variable is in the class scope, when it should be in method scope. This violates the information hiding principle. |
The Change Preventers | -Divergent Change -Shotgun Surgery -Parallel Inheritance Hierarchies |
Change Preventers are smells is that hinder changing or further developing the software These smells violate the rule suggested by Fowler and Beck which says that classes and possible changes should have a one-to-one relationship. For example, changes to the database only affect one class, while changes to calculation formulas only affect the other class. The Divergent Change smell means that we have a single class that needs to be modified by many different types of changes. With the Shotgun Surgery smell the situation is the opposite, we need to modify many classes when making a single change to a system (change several classes when changing database from one vendor to another) Parallel Inheritance Hierarchies, which means a duplicated class hierarchy, was originally placed in OO-abusers. One could also place it inside of The Dispensables since there is redundant logic that should be replaced. |
The Dispensables | -Lazy class -Data class -Duplicate Code -Dead Code -Speculative Generality |
The common thing for the Dispensable smells is that they all represent something unnecessary that should be removed from the source code. This group contains two types of smells (dispensable classes and dispensable code), but since they violate the same principle, we will look at them together. If a class is not doing enough it needs to be removed or its responsibility needs to be increased. This is the case with the Lazy class and the Data class smells. Code that is not used or is redundant needs to be removed. This is the case with Duplicate Code, Speculative Generality and Dead Code smells. |
The Couplers | -Feature Envy -Inappropriate Intimacy -Message Chains -Middle Man |
This group has four coupling-related smells. One design principle that has been around for decades is low coupling (Stevens et al. 1974) . This group has 3 smells that represent high coupling. Middle Man smell on the other hand represent a problem that might be created when trying to avoid high coupling with constant delegation. Middle Man is a class that is doing too much simple delegation instead of really contributing to the application. The Feature Envy smell means a case where one method is too interested in other classes, and the Inappropriate Intimacy smell means that two classes are coupled tightly to each other. Message Chains is a smell where class A needs data from class D. To access this data, class A needs to retrieve object C from object B (A and B have a direct reference). When class A gets object C it then asks C to get object D. When class A finally has a reference to class D, A asks D for the data it needs. The problem here is that A becomes unnecessarily coupled to classes B, C, and D, when it only needs some piece of data from class D. The following example illustrates the message chain smell: A.getB().getC().getD().getTheNeededData() Of course, I could make an argument that these smells should belong to the Object-Orientation abusers group, but since they all focus strictly on coupling, I think it makes the taxonomy more understandable if they are introduced in a group of their own. |
Tips for a good OOD
There are some tips that can be used in designing to enhance and improve the object-oriented projects.
Use Lots of Objects
By adding lots of objects, it is easy to make each object has and only has one job. Once you understand the architecture, it helps to avoid changing massive amounts of code when we modify the code.
Use Interfaces to Make APIs Predictable
Interfaces allow for strict type hinting, and by type hinting you can ensure that certain methods are always available for your use. [14]Each interface will provide the model to utilize. The utilization of a particular interface will cause the implementations of a few methods.
Use Dependency Injection
Using dependency injection can make testing and feature addition easier. While, it makes testing impossible by instantiating objects directly in the code, or grabbing objects out of singletons.
Create Loosely Coupled Classes
When a developer gives each object only one responsibility, they tightly couple objects together. Objects will often request information from other objects, and while this is not avoidable in all situations, these tightly coupled classes that rely on one another’s functionality makes pulling those objects apart impossible.[14]
Poor OOD Leads to Software Failures
In technical term, software failure is possibly due to software bugs or the poor software design, such as bad OOD. In the figure 1, we can see the cyclic behavior of failure. A fault or bug will cause errors. And errors in the system lead to the subsequent failure. In most of the cases, the software system comprises multiple components in which one failure may result in bugs or errors in another component.
Figure 1 cyclic Fault behavior
Factors may lead to Poor OOD
Bad practice in code will always lead to the poor OOD. Here are some common ones[15]:
- Classes that break the Single Responsibility Principle (SRP) and perform too many actions
- Favor Composition over Inheritance: too much inheritance instead of composition, i.e. Classes that derive from a sub-type purely so they get functionality for free
- Repeated use of switch/case statements on the same enumerated member (sign of sub-classes needing extraction)
- Lots of member variables that are used for processing, not to capture state (might indicate need to extract a method object)
- Long chains of member access
- Use of too many design patterns in a small space
- Some repeated pattern of action, process or structure that initially appears to be beneficial, but ultimately produces more bad consequences than beneficial results
- A base class down-casting itself to a derived class. Like, excessive use of switch statements, or derived classes that override everything
- Duplicate code, code that does the same thing
Software design anti-patterns
In software engineering, an anti-pattern (or anti-pattern) is a pattern that may be commonly used but is ineffective and/or counterproductive in practice[16].Many anti-pattern ideas amount to little more than mistakes, rants, unsolvable problems, or bad practices to be avoided if possible.
Anti-patterns, like their design pattern counterparts, define an industry vocabulary for the common defective processes and implementations within organizations.[17] In OOP, the anti-patterns of software design and object-oriented design are dangerous. They will result in bugs and errors in practice, and then finally lead to the failures of software. Here are the examples:[18]
- Abstraction inversion: Not exposing implemented functionality required by users, so that they re-implement it using higher level functions
- Ambiguous viewpoint: Presenting a model (usually Object-oriented analysis and design (OOAD)) without specifying its viewpoint
- Big ball of mud: A system with no recognizable structure
- Database-as-IPC: Using a database as the message queue for routine interprocess communication where a much more lightweight mechanism would be suitable
- Gold plating: Continuing to work on a task or project well past the point at which extra effort is adding value
- Inner-platform effect: A system so customizable as to become a poor replica of the software development platform
- Input kludge: Failing to specify and implement the handling of possibly invalid input
- Interface bloat: Making an interface so powerful that it is extremely difficult to implement
- Magic pushbutton: Coding implementation logic directly within interface code, without using abstraction
- Race hazard: Failing to see the consequence of different orders of events
- Stovepipe system: A barely maintainable assemblage of ill-related components
Object oriented design anti-patterns
- Anemic Domain Model: The use of domain model without any business logic. The domain model's objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places).
- BaseBean: Inheriting functionality from a utility class rather than delegating to it
- Call super: Requiring subclasses to call a superclass's overridden method
- Circle-ellipse problem: Subtyping variable-types on the basis of value-subtypes
- Circular dependency: Introducing unnecessary direct or indirect mutual dependencies between objects or software modules
- Constant interface: Using interfaces to define constants
- God object: Concentrating too many functions in a single part of the design (class)
- Object cesspool: Reusing objects whose state does not conform to the (possibly implicit) contract for re-use
- Object orgy: Failing to properly encapsulate objects permitting unrestricted access to their internals
- Poltergeists: Objects whose sole purpose is to pass information to another object
- Sequential coupling: A class that requires its methods to be called in a particular order
- Yo-yo problem: A structure (e.g., of inheritance) that is hard to understand due to excessive fragmentation
References
[1]http://www.zdnet.com/blog/projectfailures/cio-analysis-defining-it-project-success-and-failure/12524
[2] http://www.42spikes.com/post/What-is-Software-Success.aspx
[3] http://www.crcpress.com/product/isbn/9781439838129
[4] J. C. Laprie (Ed.). Dependability: Basic Concepts and Terminology. Springer-Verlag, Wein, New York, 1992.
[5] http://ac-support.europe.umuc.edu/~meinkej/inss690/wilson.htm
[6] http://www.it-cortex.com/Stat_Failure_Rate.htm
[7] http://www.selectbs.com/process-maturity/what-is-object-oriented-design
[8] http://softwaredesign.com/objects.html
[9] http://www.selectbs.com/process-maturity/what-is-object-oriented-design
[10] http://www.objectmentor.com/omSolutions/oops_what.html
[11]http://codebetter.com/raymondlewallen/2005/07/19/4-major-principles-of-object-oriented-programming/
[12]http://webcache.googleusercontent.com/search?q=cache:TwYgDNxgxUMJ:en.wikipedia.org/wiki/Design_pattern_%28computer_science%29+object+oriented+design+patterns&cd=3&hl=en&ct=clnk&gl=us
[13] http://en.wikipedia.org/wiki/GRASP_%28object-oriented_design%29
[14] http://www.brandonsavage.net/five-tips-to-make-good-object-oriented-code-better/
[15]http://stackoverflow.com/questions/345698/what-are-the-tell-tale-signs-of-bad-object-oriented-design
[16]Budgen, D. (2003). Software design. Harlow, Eng.: Addison-Wesley. "As described in Long (2001), design anti-patterns are 'obvious, but wrong, solutions to recurring problems'"p. 225. ISBN 0-201-72219-4.
[17]http://sourcemaking.com/antipatterns
[18]http://en.wikipedia.org/wiki/Anti-pattern
[19]Evaluating the Impact of Object-Oriented Design on Software Quality. Fernando Brito e Abreu, WalcClio Melo. 0-8186-7364-8196 1996 IEEE, Proceedings of METRICS ’96
[20]An Investigation of Bad Smells in Object-Oriented Design, Raed Shatnawi and Wei Li, Proceedings of the Third International Conference on Information Technology: New Generations (ITNG'06) 0-7695-2497-4/06 © 2006 IEEE
[21]Subjective evaluation of software evolvability using code smells: An empirical study, Mika V. Mantyla & Casper Lassenius Published online: 27 May 2006