DRY principle that may be misunderstood by you

Posted by Phoenixheart on Wed, 05 Jan 2022 21:08:32 +0100

Maybe you've heard of the DRY principle, but I bet there must be a deviation in your understanding; Maybe you've never heard of it. That's great. This article will benefit you a lot, guide your coding, and even inspire your work life.

1 Introduction

DRY,Don't Repeat Yourself

1.1 what is Repeat Yourself

Repeat Yourself: multiple places express the same meaning.

Disadvantages of Repeat Yourself:

  • If you change one of them, you must remember to change the others. The maintenance burden is very heavy.
  • Personally, it will be corrected sooner or later. If you change personal maintenance, don't count on it.

1.2 how to understand DRY principle

  • DRY aims at the replication of knowledge and intention, emphasizing that the things expressed in multiple places are actually the same, but in different ways.

Q: Knowledge and intention are abstract. If they are specific to coding, what do they refer to?

Misunderstanding:

  • Some people solidify DRY as a coding specification, which is narrow.
  • At least, don't understand it as "don't copy and paste code". It's really different from what you think.
  • In fact, the DRY principle also plays a guiding role in problems in work and life. For example, since I wrote this article to act on blogs, ppt s and other scenes, I created multiple copies. Imagine that if I want to modify a chapter, do I have to change it everywhere? I might go crazy then.

2 what repetition does dry principle describe

2.1 code duplication

Copy and paste code is just a special case of code duplication. In many cases, it is not what you think.

# Define account class
class MyAccount(object):
    __slots__ = ['fee', 'balance']
    def __init__(self, fee, balance):
        self.fee = fee
        self.balance = balance

# Define print function
def printAccount(account):
    if account.fee < 0:
        print('fee:%10.2f' % -account.fee)
    else:
        print('fee:%10.2f' % account.fee)

    if account.balance < 0:
        print('balance:%10.2f' % -account.balance)
    else:
        print('balance:%10.2f' % account.balance)

# function call
myAccount = MyAccount(100, -300)
printAccount(myAccount)

The above code is not copied and pasted, but there are still two duplicates.

Q: Are all code repetitions knowledge repetitions?

2.2 document duplication

The documents here are in a broad sense, including comments, etc.

For example, the annotation of a method describes all the logical branches in the method, and the intention of the function is described twice (once for the annotation and once for the code). After only two requirements changes, the code and comments will become inconsistent.

private static boolean isAllTicketsStatusOk(FlightOrder order, BigOrder bigOrder) {
  /*
    * You can apply for mailing in all three cases:
    * 1. The ticket has been refunded
    * 2. Post flight && checked in (only applies to new orders. After a new order is checked in, it will be processed by recursion of the original order)
    * 3. Send & & tickets issued, changed and checked in immediately (since the task of printing itinerary may delay time, the checked in is added)
    */
  Predicate<FlightOrderTicket> isTicketStatusOk = item -> item.getStatus() == Returned
      || bigOrder.getDistInfo().getDistMode() == DistMode.DistAfterRide && item.getStatus() == Ride
      // Changed expresses the original order
      || bigOrder.getDistInfo().getDistMode() == DistMode.DistImmediately && item.getStatus().in(Changed, TicketSuccess, Ride);

  boolean isAllTicketsStatusOk = order.getOrderTickets().stream()
      .allMatch(isTicketStatusOk);

  LOG.debug("isAllTicketsStatusOk: {}", isAllTicketsStatusOk);

  return isAllTicketsStatusOk;
}

It is a good habit to write comments. This is definitely not for you to delete all comments in order to avoid the DRY principle.

However, comments can't hide bad code.

If it is to cover up bad or obscure code in the method, the code should be refactored at this time.

recommend:

  • The method name accurately describes what the method should do. Each line of code in the method is written as clear and understandable as comments, and the comments can be removed.
  • For scenarios with many if else branches, don't try to explain the complex logic clearly with comments. Learn more from design patterns to optimize the code structure, such as policy patterns, template method patterns, etc. [external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-nipzmwyw-16394071231)( https://github.com/viper140/viper140.github.io/blob/master/_posts/2020/11/imgs/if-else.png )]

2.3 data duplication

In fact, it is often referred to as data redundancy.

class Line {
  Point x;
  Point y;
  double length;
}

x. The length of the connection can be determined by two points y. The length field is obviously repeated and should be changed to the method:

double length() {

}

Even if they are not in the same class, they may constitute duplication.

For example, suppose a route contains multiple segments. There are distances on the route and on the segment.

class Route {
  List<Segment> segments;
  int distance;
}

class Segment {
  int distance;
}

The distance on the route is the sum of the distances of all segment s under it. If it is defined as a field, it will be repeated and changed to a method.

class Route {
  List<Segment> segments;

  int getDistance() {
    return this.segments.stream()
          .map(item -> item.getDistance())
          .sum();
  }
}

class Segment {
  int distance;
}

Database entity classes are special. Sometimes performance factors should be considered and redundancy measures are taken.

For example, the amount field in the following example.

@Table
class FlightOrder {
  BigDecimal amount;
  List<FlightOrderPassenger> passengers;
}

@Table
class FlightOrderPassenger {
  BigDecimal amount;
  List<FlightOrderPassengerTicket> tickets;
  FlightOrder belongedOrder;
}

@Table
class FlightOrderPassengerTicket {
  BigDecimal amount;
  FlightOrderPassenger belongedPassenger;
}

The logic of updating redundant fields is encapsulated in the class for centralized processing.

@Table
class FlightOrderPassengerTicket {
  BigDecimal amount;
  FlightOrderPassenger belongedPassenger;

  void setAmount(BigDecimal amount) {
    this.amount = amount;
    this.resetOrderAmout();
  }

  void addAmount (BigDecimal amount) {
    this.amount = this.amount + amount;
    this.resetOrderAmout();
  }

  private resetOrderAmout() {
    var passenger = this.belongedPassenger;
    passenger.amount = passenger.getTickets().stream()
      .reduce(BigDecimal.ZERO, BigDecimal::add);

    var order = this.belongedPassenger.belongedOrder;
    order.amount = order.getPassengers().stream()
      .reduce(BigDecimal.ZERO, BigDecimal::add);
  }
}

recommend:

  • Reasonably use methods to replace attributes to remove duplicates.
  • Where redundancy is necessary, the relevant logic shall be controlled locally as far as possible to reduce the risk caused by duplication.

2.4 characterization repetition

It mainly describes the inevitable repetition when dealing with the outside. The code must hold the knowledge (representation) already contained in the external system. Including API, data schema, error code, etc.

2.4.1 repetition of API

For API, there is duplication between client code, API definition and server code.

recommend:

  • Use swagger and other API s to manage tools and frameworks.
  • Using lib package, you can encapsulate entity classes and even further encapsulate the code of remote calls.

The above two methods eliminate the duplication between API definitions and server code. The disadvantage is that the client duplication cannot be eliminated, but it can also be triggered manually.

2.4.2 duplication of data sources

The definition of the data table by the entity class is duplicate with the actual table structure of the database.

recommend:

  • With the help of orm framework, the mapping between object and relational database is realized automatically. This is a way, but it needs to be treated with caution. There are no trivial data problems.
  • If the json string type field is reasonably used, what it is is completely determined by the client, eliminating the definition of the data table.

2.5 developer duplication

To be exact, different services (developers) have their own implementation of the same requirement. Its biggest problem is that it is difficult to share the same service, especially at the front and back ends, and there are language barriers.

The most easily repeated verification rules are verification rules, such as mobile phone number and email verification. Different developers of different services have their own implementation.

recommend:

  • Strengthen communication.
  • Establish knowledge base. (I have to say that the above two sentences are absolutely correct nonsense)
  • Common lib is extracted from services in the same language.
  • Services in the same language are organized in the same warehouse with the help of project construction tools and rely on common component services.

However, cross language barriers cannot be broken.

3 Summary

  • The repetition described by DRY principle is the repetition of knowledge and intention. Including code duplication, document duplication, data duplication, representation duplication and developer duplication.
  • Many of these types of duplication need to be eliminated, but not all:
    • Some repetitions are not necessarily repetitions of knowledge and intention, but elimination does not make sense.
    • Some knowledge duplication should be retained due to performance considerations, but should be treated properly.
    • There are some repetitions that cannot be eradicated.

4 final advice

Rules are rules after all, and thought is thought after all. There are many difficulties in practice. Advice:

  • Don't abstract in advance under the banner of DRY. Please follow the Rule of three principle.
  • Don't excessively pursue DRY and destroy cohesion. It's difficult to hold both ends. I'm sorry to tell you that there are no rules. Ask experienced programmers for advice.