Note of CLEAN CODE chapter 3 - Function

本文讨论了编程中的最佳实践,如保持函数小而单一,使用清晰的命名,遵循单一职责原则和开闭原则,避免副作用,提倡异常处理而非错误代码,以及遵循结构化编程原则,如适当使用嵌套和缩进。
摘要由CSDN通过智能技术生成

Small

Functions should be small. You can fit about 150 characters in a line and 100 lines in a screen, so

  • A line should not contain more than 150 characters
  • A function should not be 100 lines long()

for example in Listing 3-3

public static String renderPageWithSetupsAndTeardowns(
    PageData pageData, boolean inSuite) throws Exception{
    if(isTest(pageData)){
        includeSetupAndTeardownPages(pageData, isSuite);
    }
    return pageData.getHtml();
}

block and indenting

As we can see in the example

  • blocks within if when for statements and so on should be one line long;

includeSetupAndTeardownPages(pageData, isSuite);

Functions should be large enough to hold nested structures;

  • indent level of a function should not be greater than 1 or 2

Do one thing

Make sure your function only does one thing, which does steps that are only one level below the stated name of the function.

Purpose of it is to compose a larger concepot into the next level of abstraction.

How to know your function is doing more than one thing?

  • Make sure you can extract a function from it with a name that isn’t merely restatement of the implementation.

One Level of Abstraction per Function

reading code from top to bottom - Stepdown Rule

  • include setups and teardowns, we include setups, then testpage content, teardowns
    • include setups, we include suite setup if this is a suite, the regular setup
      • to include the suite setup serach parent hierarchy for …

make it like a tree.

Switch

Try to bury switch statements in a low-level class and never repeat them.
Bury them into an ABSTRACT FACTORY and use INHERITANCE and POLYMORPHISM, and the rest of the system can never read them.

//original
public Money calculatePay(Employee e) throws InvalidEmployeeType{
    switch(e.type){
        case COMMISSIONED:
            return calComissionPay();
        case HOURLY:
            return calHourlyPay();
            ...
    }
}

Codes above do more than one thing, and they will grow, and they violate SRP, OCP;

//ABSTRACT
public abstract class Employee(){
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliveryPay(Money money);
}


public interface EmployeeFactory(){
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}


public class EmployeeFactoryImpl() implements EmployeeFactory{
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType{
        switch(r.type){
            case COMMISSIONED:
                return new CommissionedEmployee(r);
            case HOURLY:
                return new HourlyEmployee(r);
                ...
        }
    }
}

Descriptive Name

Do not be afraid to make the name long

  • spend time choosing a name
  • descriptive names will clarify the design
  • be consistent in your names

Function Aruguments

More than three aruguments requires special justification

And output aruguments are harder to understand – cause us to do a double-take

Monadic Form

  • First, make it clear to know it is a event
  • If the function will change the input arugument, you are supposed to return it
    StringBuffer transform(StringBuffer in) is better than void transform(StringBuffer in)

Flag Argument

Flag arguments are ugly, and it will make function do more than one thing, so if you need to distinguish if statements, just get rid of the flag arguments and write two different functions.

Dyadic Functions and Triads

Convert them into monads or make the arguments in a natural order.

Argument Objects

if a function needs more than three arguments, they are supposed to be wrapped into a class.
makeCircle(int x, int y, int radius) can be turned to makeCircle(Point center, int radius)

Argument List

When we want to pass a variable number of arguments into a function, we can make them equivalent to a single argument of type List like the String.format() function

Verbs and Keywords

Function can use verb/noun form to include arguments. Like writeField(name) might be better than write(name). And assertExpectedEqualsActual(expect, actual) might be better than assertEquals

Have no Side Effects

When you check a user password, only check it and DO NOT initialize it.(initialize is the side effect, and it might be coupling).
If someone call it inadvertantly, it will make the session data lost.

If you have to add initialization to the function, rename it! like checkPasswordAndInitSession()(but it violates do one thing principle)

Output Arguments

when you want to output sth, it is not supposed to use it as a argument like
public void appendFooter(StringBuffer report), you can just change it as report.appendFooter()

Output arguments should be avoided

Command query Separation

A function either change the data state, or return some data information.
Avoid doing both at the same time like boolean set(String id, String name), which returns true when it successfully set the name and returns false to mean the id does not exist.

But it is not readable for readers when they see the codes

if(set("10", "bob")){
    ...
}

maybe it is better to seperate them

if(userIdExists("10")){
    setUserName("10", "bob");
    ...
}

Prefer Exception to Error Codes

Throwing Exceptions might make your code cleaner compared to return error codes.

Extract the try/catch blocks

package your code and throw exception, then try/catch it at the most abstract level

public void delete(Page){
    try{
        deletePageAndAllReference(page);
    }catch(Exception e){
        log.info(e.getMessage());
    }
}

public void deletePageAndAllReference(Page page){
    page.delete();
    register.deletePageReference(page.name);
    configKeys.deleteKey(page.name.makeKey());
}

Error Handling is One Thing

there should be nothing after catch/finally blocks

Error.java Dependency Magnet

Returning codes are basically defined in some enum or class

When the enum/class is changed, all other classes dependent on it will be recompiled and redeployed, so it will cause more burden.

Don’t repeat yourself

make the repeat statements become functions

Structured Programming

Edsger Dijkstra said

  • every function/block within a function should have one entry and one exit
    • one return in a function
    • never break or continue in a loop
    • never ever use goto

It is hard, so occasional multiple return, break, continue statements do no harm if you keep your functions small, and sometimes they might be more expressive.

How to do it?

  1. first draft(even if it is clumsy and idsorganized)
  2. wordsmith, restructe and refine your draft
  3. mention
    1. indenting and nested loops
    2. long argument lists
    3. name
    4. duplicated code
  4. action
    1. split out functions
    2. change names
    3. eliminate duplications
    4. shrink and reorder method
  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值