Showing posts with label Clean Code. Show all posts
Showing posts with label Clean Code. Show all posts

Replace Conditional with Polymorphism

  • 0
Trying to convince my team to give up on if/then/else & case...

Let's play with some code!

First the the non Object Oriented / procedural version:

/*
 * non_oop.cpp
 *
 *  Created on: Sep 4, 2015
 *      Author: ferrazlealrm@ornl.gov
 *
 *  Non OOP example of URL:
 *  scheme:[//domain[:port]][/]path
 */

#include <iostream>
#include <string>

std::string domain = "ornl.gov";
std::string http_port = "80";
std::string https_port = "443";
std::string ftp_port = "20";

std::string build_url(const std::string &scheme,
  const std::string &domain,
  const std::string &port) {
 return scheme + "://" + domain + ":" + port;
}

int main(int argc, char* argv[]) {
 if (argc != 2) {
  std::cerr << "Use " + std::string(argv[0]) + " [http, https, ftp]"<<std::endl;
  exit(-1);
 }
 std::string scheme = argv[1];

 if (scheme == "http"){
  std::cout << build_url(scheme,domain,http_port) <<std::endl;
 }
 else if (scheme == "https"){
  std::cout << build_url(scheme,domain,https_port) <<std::endl;
 }
 else if (scheme == "ftp"){
  std::cout << build_url(scheme,domain,ftp_port) <<std::endl;
 }
 else {
  std::cerr << "Scheme not valid. Use of these: http, https, ftp"<<std::endl;
 }
 return 0;
}

And the finally the Object Oriented version:

/*
 * oop.cpp
 *
 *  Created on: Sep 4, 2015
 *      Author: ferrazlealrm@ornl.gov
 *
 *  OOP example of URL:
 *  scheme:[//domain[:port]][/]path
 */

#include <iostream>
#include <string>
#include <map>

// Abstract class: cannot be instantiated
class URL {
protected:
 std::string domain = "ornl.gov";
 std::string port;
 std::string scheme;
 std::string build_url(const std::string &scheme,
   const std::string &port) const {
  return scheme + "://" + domain + ":" + port;
 }
public:
 // Pure virtual function: i.e. must be overridden by a derived class
 virtual std::string build_url() const = 0;
 ~URL() {};
};

class Http: public URL {
public:
 Http() {port = "80"; scheme = "http";}
 std::string build_url() const {
  return URL::build_url(scheme, port);
 }
};

class Https: public URL {
public:
 Https() {port = "443"; scheme = "https";}
 std::string build_url() const {
  return URL::build_url(scheme, port);
 }
};

class Ftp: public URL {
public:
 Ftp() {port = "20"; scheme = "ftp";}
 std::string build_url() const {
  return URL::build_url(scheme, port);
 }
};

/**
 * Main function
 */
std::string build_url(const URL &url) {
 return url.build_url();
}

int main(int argc, char* argv[]) {
 if (argc != 2) {
  std::cerr << "Use " + std::string(argv[0]) + " [http, https, ftp]"
    << std::endl;
  exit(-1);
 }
 std::string scheme = argv[1];

 // UGLY!!!
 // In real world I would have here some sort of Dependency Injection (e.g. factory)
 // This just shows that we can get an object given a string
 Http http;
 Https https;
 Ftp ftp;
 std::map<std::string, URL*> choices;
 choices.insert(std::make_pair("http", &http));
 choices.insert(std::make_pair("https", &https));
 choices.insert(std::make_pair("ftp", &ftp));

 if (scheme == "http" or scheme == "https" or scheme == "ftp") {
  std::cout <<  build_url(*choices[scheme]) << std::endl;
 } else {
  std::cerr << "Scheme not valid. Use of these: http, https, ftp"
    << std::endl;
 }
 return 0;
}

I know it looks complicated, but imagine you want to add a new functionality. Let for example add a path to the HTTP url:

/**
 * Let's imagine that I want to add a path to the URL: http://ornl.gov:80/
 * I don't need to modify the code! Open/closed principle.
 * Just extend it, i.e., add new code.
 */

class HttpWithPath: public Http {
protected:
 std::string path;
public:
 HttpWithPath(std::string path) : Http(), path(path) {}
 std::string build_url() const {
  std::string default_url = URL::build_url(scheme, port);
  return default_url + "/" + path;
 }
};


It does not violate the open/closed principle, which states:
"software entities should be open for extension, but closed for modification".


Object-Oriented Design

  • 0
Quoting Uncle Bob Martin's :

You know the software is rotting when it starts to exhibit any of the following odors:

Rigidity – The system is hard to change because every change forces many other changes to other parts of the system.
Fragility – Changes cause the system to break in places that have no conceptual relationship to the part that was changed.
Immobility – It is hard to disentangle the system into components that can be reused in the other systems.
Viscosity – Doing things right is harder than doing things wrong. Needless Complexity – The design contains infrastructure that adds no direct benefit.
Needless Repetition – The design contains repeating structures that could be unified under a single abstraction.
Opacity – It is hard to read and understand. It does not express its intent well

Simple Design

Extreme Programming's principle of Simple Design, in order of importance:

  1. Runs all the tests
  2. Contains no duplication
  3. Expresses the intent of the programmer
  4. Minimizes the number of classes and methods

Truly agile teams don't allow the software to rot:

  • Keeping the design clean and simple at all times is the only way to go fast. It makes the design flexible and easy to change.
  • Making a mess will always slow you down the next time that you need to read or change the same code.

Architecture

"Architecture is about the important stuff. Whatever that is."
"Architecture is the decisions that you wish you could get right early in a project."

Why do people feel the need to get some things right early in the project?

The answer, of course, is because they perceive those things as hard to change. So you might end up defining architecture as “things that people perceive as hard to change”.
  • Big Design Up Front (BDUF), i.e. spinning system designs based on untested hypotheses for many months, is harmful. 
    • BDUF inhibits adapting to change.
  • Little/Enough Design Up Front (LDUF/EDUF) is good. 
    • With a big project spending a week or even a month thinking about the important things is nothing wrong.
  • Agile was a response to BDUF, but not DUF. 
    • Far from “design nothing,” the XP strategy is “design always.”
  • Whatever designs have been done up front, they should always be open for change.
    • Let the tests drive the system architecture.

Principles of Modular Design

Cohesion – higher is better

  • Cohesion is a measure of how strongly-related or focused the responsibilities of a single module are.

Coupling – lower is better

  • Coupling or dependency is the degree to which each program module relies on each one of the other modules.

SOLID Principles

  • SRP: Single Responsibility Principle
  • OCP: Open Closed Principle
  • LSP: Liskov Substitution Principle
  • ISP: Interface Segregation Principle
  • DIP: Dependency Inversion Principle
(to be continued...)


Clean Code Talks

  • 0
Have been watching (mainly listening...) this playlist all morning. Nothing new, but a few concepts that sometimes we "forget"...