Showing posts with label OOP Design Principles. Show all posts
Showing posts with label OOP Design Principles. Show all posts

Saturday, 17 May 2014

Three Flaws in Software Design

In below Google Tech Talk series - "Jeremy Walker" & "Max Kanat-Alexander" discussed the three Flaws of Software Design, from Max’s book Code Simplicity: The Fundamentals of Software.
I enjoyed to attend their 40 minutes of talk and below are notes taken for quick reference, but I would strongly suggest to attend this tech talk series for better understand by examples.

Overall software design can benefit incredibly, if such fundamental flaws are avoided.

  • Sounds like "YAGNI" but it's more.
  • It's not about whether you're going to need it in the future.
    • It's about good design.
    • Maybe the only way to do good design is to need the code. (Software solves real problems)
  • Problem
    • Bit rot
    • Will need to be redesigned
    • Trying to handle "every possible thing"
    • Not really saving you time
    • Adding complexity
  • Can be whole classes or functions that you don't need, but sometimes just lines of code you don't need.
  • RULE
    • Don't write code until you actually need it, and remove any code that isn't being used.
    • During code review, check that do you really need this code now for given requirement?
    • Avoid… avoid… avoid… DEAD CODE.
    • Don't assume requirements and write unnecessary code. Ask lots of questions to clarify requirements and write simpler code.
Flaw 2:Not Making the Code Easy to Change (12 minutes video)
  • Also called Rigid design. Two ways to accomplish this,
    • Design in too many assumptions about the future
    • Writing code without enough design
  • Too many assumptions
    • For futures with waterfall model - Essentially a failure to understand that requirements will change.
    • Code can be done in small ways too - For example (i) using magic numbers instead of constants (ii) if you don't need to support international users in current requirements, then you may just consider adding support of it in design as a future requirement but don't implement across the whole framework.
  • Code without enough design (Spaghetti)
    • May be even say to some degree - the more you assume things won't change, the more your code becomes spaghetti.
    • Spaghetti is hard to change because of - Duplication, Complexity, Safety, Could possibly also inversely define spaghetti by these traits
  • RULE
    • Don't assume too much for future requirements. Code should be designed based on what you know now (based on factual requirements), not on what you think will happen in the future!
    • The quality level of your design should be proportional to the length of future time in which your system will continue to help people.
Flaw 3:Being Too Generic (10 minutes video)
  • Often called over-engineering.
  • You cannot accommodate every future requirement now.
  • Too much effort for too little value.
  • Developers do this all the time by trying to be "good" when they don't need to be:
    • Catching exceptions that don't need to be caught
    • Expecting input that you never get
    • Handling situations you're never in (like multi-threading)
    • Injecting dependencies when there's only one choice
    • "One day we might need to…"
  • RULE
    • Be only as generic as you know you need to be right now. Never duplicate code. Have a stable and simple design.

Also Refer

Sunday, 6 April 2014

OOP Design - Part 2 - Class principles - SOLID

I hope, you have already read "Preface" of this post.  Also  don't miss to refer corresponding example java code (not for production, illustrative purposes only) to understand theory of each principle.

SOLID Principles

The principles of SOLID are guidelines that can be applied while working on software to remove code smells by causing the programmer to refactor the software's source code until it is both legible and extensible. It is typically used with test-driven development, and is part of an overall strategy of agile and adaptive programming.
  • S = SRP = Single responsibility principle
  • O = OCP = Open/closed principle
  • L = LSP = Liskov substitution principle
  • I = ISP = Interface segregation principle
  • D = DIP = Dependency inversion principle

Single responsibility principle
  • Definition of SRP?
    • Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. (Wikipedia)
    • There should never be more than one reason for a class to change. (Robert C. "Uncle Bob" Martin)
  • Rules of Thumb?
    • If you cannot come up with meaningful name for your class focused to single responsibility, then it's probably doing too much.
    • Ensure you don't design and implement God class (a class that knows too much or does too much, which is example of an anti-pattern).
    • Remember more classes != more complexity
  • Don't mix-up many different responsibilities in a single class (known as God class), instead come up different classes and each should be focused to single responsibility. Example of responsibilities?
    • Validation (PasswordValidation, EmailValidation…)
    • Notification (EmailNotification, SMSNotification…)
    • Parsing (XMLParser, CSVParser...)
    • Formatting
    • Error Handling
    • Persistence
  • Understand theory from Example java code snippet

Open/closed principle
  • Definition of OCP?
    • Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. That is, such an entity can allow its behavior to be modified without altering its source code. This is especially valuable in a production environment, where changes to source code may necessitate code reviews, unit tests, and other such procedures to qualify it for use in a product: code obeying the principle doesn't change when it is extended, and therefore needs no such effort. (Wikipedia)
  • Rules of Thumb?
    • Open to extension =  you should design your classes so that new functionality can be added as new requirements are generated.
    • Closed for modification = Once you have developed a class you should never modify it, except to correct bugs.
    • Design and code should be done in a way that new functionality should be added with minimum or no changes in the existing code
    • When needs to extend functionality - avoid tight coupling, don't use if-else/switch-case logic, do code refactoring as required...
    • Techniques to achieve - Inheritance, Polymorphism, Generics
    • Pattern to apply – Strategy Pattern, Template Method
  • Example
    • File Parser  with initially supported Text and XML parsing functionality. Now extend it to support new functionality of CSV parsing and then support even more types of parting...
  • Understand theory from Example java code snippet

    Liskov substitution principle
    • Definition of LSP?
      • Derived classes must be substitutable for their base classes. That means, functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. (Robert C. "Uncle Bob" Martin)
    • Rules of Thumb?
      • This principle applies to inheritance hierarchies and is just an extension of the Open Close Principle.
      • It means that we must make sure that new derived classes are extending the base classes without changing their original behavior. Basically, derived classes should never do less than their base class.
      • If a subtype of the supertype does something that the client of the supertype does not expect, then this is in violation of LSP. Imagine a derived class throwing an exception that the superclass does not throw, or if a derived class has some unexpected side effects. One has to consider that how the client programs are using the class hierarchy. Sometimes code refactoring is required to fix identified LSP violations.
    • Example
      • Media Player is super class having ability of playing audio and video both. Now VLC and DIV Media Players are the subtypes of Media Player and inheriting the original behavior of Media player; and are substitutable for their base class Media player in the client program code. Now there is need of launching new Winamp Media Player, but with  audio support only. So one could extend Media Player class and override original behavior of Media Player's playVideo() method  for doing nothing or may be throw UnSupportedException (in short Winamp media player is doing less that its super class Media player). So this can be considered as LSP violation, as it may cause unpredictable behavior when Media Player is substituted with Winamp Media Player in client code.
    • Understand theory from Example java code snippet
    Interface segregation principle
    • Definition of ISP?
      • Make fine grained interfaces that are client specific.  That means, clients should not be forced to depend upon interfaces that they do not use. (Robert C. "Uncle Bob" Martin)
    • Rules of Thumb?
      • Don’t depend on things you don’t need. Interfaces containing methods that are not specific to it are called polluted or fat interfaces. We should avoid them.
      • Many client-specific interfaces are better than one general-purpose interface. When we have non-cohesive interfaces, the ISP guides us to create multiple, smaller, cohesive interfaces.
    • Example
      • Consider Order Service interface having responsibilities like createOrder, amendOrder, submitOrder and processOrder. Now there are two clients end users and backend order processor job, who depend on Order Service interface. But processOrder() is not of use for end user client, still client is forced to depend as per design. Similarly backend order process job is only interested in processOrder() service, still forced to depend on other services too. So ISP is violated.
    • Understand theory from Example java code snippet

    Dependency inversion principle
    • Definition of DIP?
      • Depend on abstractions, not on concretions.  (A) High-level modules should not depend on low-level modules. Both should depend on abstractions. (B) Abstractions should not depend on details. Details should depend on abstractions. (Robert C. "Uncle Bob" Martin)
    • Rules of Thumb?
      • Design by contract.
      • Every dependency in the design should target an interface, or an abstract class. No dependency should target a concrete class.
      • Factories and Abstract Factories can be used as dependency frameworks, but there are specialized frameworks for that such as Spring IOC (Inversion of Control Container).
    • Example
      • LoginManager depends on implementation class SimpleAuthenticator to authenticate user from database. In future to change it to authenticate by LDAPAuthenticator, LoginManager and its test case would change. This can be avoided by following Dependency Inversion Principle.
      • The refactored code can be - LoginManager depends on Authenticator interface only. Authenticator interface will be implemented by SimpleAuthenticator and LDAPAuthenticator implementation classes. The client of LoginManager may inject dependency on implementation class or dependency frameworks may be used for it.
    • Understand theory from Example java code snippet


    Also Refer

    Sunday, 26 January 2014

    OOP Design - Part 1 - Fundamentals

    I hope, you have already read "Preface" of this post.  Also don't miss to refer corresponding example java code (not for production, illustrative purposes only) to understand each fundamental topic.

    About Building Object Oriented System

    • Its all about Objects - Instantiating, Communicating, Managing, Extending, Monitoring…
    • In most of the cases, Everything is done by Developer.
    • What developers end up without knowledge of object oriented design principles and patterns? --- Answer is "Complex Code" – which is hard to maintain, extend and reuse. Because of,
      • Writing to much boilerplate
      • Duplication
      • Entangled interfaces
      • Complicated dependencies
      • Rigid, Fragile and Immobile code
    ABC of Object Oriented Design and Responsibilities
    • OO Design
      • Identify classes and objects
      • Decide methods belong to what class/object and how they interact
    • Responsibilities
      • Assigned to classes/methods during design
      • Translation of responsibilities into classes/methods is influenced by the granularity of responsibility
      • Responsibilities are not same as methods, but methods fulfill responsibilities
      • Two Types of responsibilities - Doing & Knowing

    Goal of a Object Oriented Design

    • Reusability, Flexibility, Extendibility, Maintainability...

    Characteristics of Bad Design / Design Smell

    Yes, designs or code can smell. They point to problems with the structure of code: class organization, relationships, collaborations/dependencies, responsibilities etc. Software OOP fundamentals and design principles represent a set of guidelines that helps us to avoid having a bad design.

    Some of key characteristics of bad design are,
    • Rigidity = It is hard to change because every change affects too many other parts of the system. That means, difficult to add new features.
    • Fragility = When you make a change, unexpected parts of the system break. That means, unable to identify impact of the change.
    • Immobility = Code is hard to reuse in another application because it cannot be disentangled from the current application. That means, no reusability.
    • Viscosity = Going with the flow of bad practices already being present in the code.
    • Needless Complexity = the design adds additional structure that provides no direct benefit.
    • Opacity = It is hard to read and understand.  The code does not express its intent well.

    OOP Fundamentals

    Abstraction = Looking only at the information that is relevant at the time.
    • Abstraction is the process or result of generalization by reducing the information content of a concept or an observable phenomenon, typically in order to retain only information which is relevant for a particular purpose.
    • Functional abstraction - means that a function can be used without taking into account how the function is implemented.
    • Data Abstraction - means that data can be used without taking into account how the data are stored.

    Encapsulation = Data hiding mechanism. (example code snippet)
    • The process of binding or wrapping the data and the codes that operates on the data into a single entity. This keeps the data safe from outside interface and misuse. One way to think about encapsulation is as a protective wrapper that prevents code and data from being arbitrarily accessed by other code defined outside the wrapper.
    • For example, if a field is declared private, it cannot be accessed by anyone outside the class, thereby hiding the fields within the class.

    Inheritance = IS-A relationship between a superclass and its subclasses. (example code snippet)
    • The process where one object acquires the members of another; plus can have its own.
    • For example, Dog (subclass) is-a of type Animal (superclass). So Dog can inherit (reuse) members of Animal class;  plus it can have its own new behavior and properties.

    Polymorphism = single interface multiple implementations. (example code snippet)
    • How Polymorphism is supported in Java? - In terms of interface, inheritance, method overloading and method overriding. (Method overloading and method overriding uses concept of Polymorphism in Java where method name remains same in two classes but actual method called by JVM depends upon object at run time and done by dynamic binding in Java. In case of overloading method signature changes while in case of overriding method signature remains same and binding and invocation of method is decided on runtime based on actual object. This facility allows Java programmer to write very flexibly and maintainable code using interfaces without worrying about concrete implementation. One disadvantage of using Polymorphism in code is that while reading code you don't know the actual type which annoys while you are looking to find bugs or trying to debug program. But if you do Java debugging in IDE you will definitely be able to see the actual object and the method call and variable associated with it.)
    • Where to use Polymorphism in code? - You should use super type in method argument, variable name and return type of method.
    • Parameteric Polymorphism in Java - Java started to support parametric polymorphism with introduction of Generic in JDK1.5. Collection classes in JDK 1.5 are written using Generic Type which allows Collections to hold any type of object in run time without any change in code and this has been achieved by passing actual Type as parameter. 

    Delegation = hand over the responsibility for a particular task to another class or method. (example code snippet)
    • If you need to use functionality in another class but you do not want to change that functionality then use delegation instead of inheritance.
    • Classical example of delegation design principle is equals() and hashCode() method in Java. In order to compare two object for equality we ask class itself to do comparison instead of Client class doing that check. Benefit of this design principle is no duplication of code and pretty easy to modify behavior.

    Aggregation = HAS-A relationship. (example code snippet)
    • Aggregation is an association represents a part of a whole relationship where a part can exist without a whole. It has a weaker relationship.
    • For example, If line-item HAS-A product, then a line item is a whole and product is a part. If a line item is deleted, then corresponding product needs not to be deleted.

    Composition = HAS-A relationship, but restricted form of Aggregation. (example code snippet)
    • Composition is an association represents a part of a whole relationship where a part cannot exist without a whole. If a whole is deleted then all parts are deleted. It has a stronger relationship.
    • Favor Composition over Inheritance.
    • For example, if order HAS-A line-items, then an order is a whole and line items are parts. If an order is deleted then all corresponding line items for that order should be deleted.

    Loose Coupling = Low dependencies between “artifacts” (classes, modules, components). (example code snippet)
    • There shouldn’t be too much of dependency between the modules, even if there is a dependency it should be via the interfaces and should be minimal.
    • Avoid tight-coupling for collaboration between two classes (if one class wants to call the logic of a second class, then they first class needs an object of second class it means the first class creates an object of second class).
    • Strive for loosely coupled design between objects that interact.
    • Inversion Of Control (IoC) / Dependency Injection (DI) - With DI objects are given their dependencies at creation time by some third party (i.e. Java EE CDI, Spring DI…) that coordinates each object in the system. Objects aren’t expected to create or obtain their dependencies—dependencies are injected into the objects that need them. The key benefit of DI—loose coupling.

    High Cohesion = The code has to be very specific in its operations. (example code snippet)
    • The responsibilities/methods are highly related to class/module.
    • The term cohesion is used to indicate the degree to which a class has a single, well-focused responsibilities. Cohesion is a measure of how the methods of a class or a module are meaningfully and strongly related and how focused they are in providing a well-defined purpose to the system.  The more focused a class is, the higher its cohesiveness - a good thing.
    • A class is identified as a low cohesive class, when it contains many unrelated functions within it. And that what we need to avoid, because big classes with unrelated functions hamper their maintaining. Always make your class small and with precise purpose and highly related functions.


    Few principles, every developer should always keep in mind and apply when writing code.

    Interface based design = Coding to an interface, not to an implementation
    • One of the best practices that object oriented programmers should try to strive for is to write java classes to interfaces instead of concrete classes.
    • Writing to interfaces reduces coupling and gives a great flexibility in running the unit and integration tests without having to modify the client code whenever the implementation of a service component is changed.
    • It can achieve code reuse with the help of object composition.

    DRY principle = Don't repeat yourself
    • Software development principle to reduce repetition of information of all kinds.
    • Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
    • Avoid copy-paste of code. Otherwise change in the code would have to be made in all the places where its been copied.
    • Don't write duplicate code for "application logic", instead abstract common things in one place.
    • For example - If you use a hardcoded value more than one time consider making it public final constant. If you have block of code in more than two place consider making it a separate method.

    KISS principle = Keep it simple, stupid / keep it simple and straightforward
    • Simplicity should be the a goal of design and unnecessary complexity should be avoided.
    • For example - If there is a need of grate manipulations on collections, then don't write your own complex custom implementation. If you like the "Function" style, maybe make use of the proven Guava library (which has the Function interface and many helper methods that work with them on collections). That is DRY (because you don't repeat yourself, and re-use code that already exists), and still KISS (because those are well understood patterns).

    YAGNI principle = You aren't gonna need it
    • A principle of extreme programming (XP) that states a programmer should not add functionality until deemed necessary.
    • Don't be tempted to write code that is not necessary at the moment, but might be in the future.
    • Recommended to be used in combination with several other practices, such as continuous refactoring, continuous automated unit testing and continuous integration.
    • See also - Over-engineering

    AOP = Aspect Oriented Programming
    • A programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns (e.g. logging, exceptional handling, caching…). Identify the aspects of your application that vary and separate them from what stays same.
    • AOP is a concept and as such it is not bound to a certain programming language or programming paradigm. The Java implementation of AOP is called AspectJ. Or Spring AOP can be used.


    Also Refer:

    Sunday, 12 January 2014

    OOP Design - Fundamentals and Principles - Preface

    How to achieve effective design?
    1. Follow OOP (object oriented programming) fundamentals
    2. Avoid bad design characteristics (code smell)
    3. Embrace Design Principles
      • Class Design - SOLID & GRASP
      • Package Design
    4. Consider Design Patterns and Anti-patterns
    In next series of articles,

    I would explain below topics along with example java code.
    • OOP Fundamentals [Part-1]
    • Class design principles - SOLID [Part-2] & GRASP [Part-3 - coming soon]
    • Package design principles [Part-4 - coming soon]
        Note: This series is focused to cover OOP fundamentals and design principles. Design patterns and anti-patterns are not included as part of this series; instead I shall cover those separately

        A bird's-eye view of OOP fundamentals and design principles


        Design Principles vs. Design Patterns?

        • Design Principle – A set of guidelines that helps us to avoid having a bad design.
        • Design Pattern
          • Emphasize on principles to assign responsibilities.
          • General reusable solution for a problem.
          • Shows relationships and interactions between classes or object.
        • Example
          • Principle – Dependency Inversion Principle
          • Pattern – Factory, Abstract Factory (Object Creational)
          • Popular frameworks – Spring IoC, Guice, JavaEE CDI, etc.