`
wujunrat
  • 浏览: 4757 次
  • 来自: ...
最近访客 更多访客>>
社区版块
存档分类
最新评论

7 tips on writing clean code(ZZ)

    博客分类:
  • JAVA
阅读更多
My job has required me to read quite a bit of code written by other people, and over the years I've found that there are some problems that tend to recur again and again. The idea with this blog entry is to write up some tips on this once and for all, in the hope that it can help people out there who struggle to write clean code.

The main goal with these tips is readability. This is important because usually your code has to be changed or reviewed by other people, and writing readably makes these people's jobs a lot easier. That may be obvious. What's less obvious is that it also makes your own job easier, because working on simple code is a lot easier than working on complex code, even while you are writing it, and the more readable code is always simpler.

An important part of making your code readable is to always work to communicate your intent. The basic idea is that it's usually not difficult to see what a single line of code does. The tricky thing is to see why it's doing what it does. So the more you can make your code communicate the thinking behind the code, the better it is. You'll see this point recurring repeatedly below.

I should add that most people seem to be aware of most of these rules, in a general kind of way. The main point of this posting is really to convince people that these rules are important. So important, in fact, that you should try to always follow them, and that you should have a really bad conscience about any code that breaks them. So bad that you just never write any such code. Some of these rules require you to write a little extra code, but I think I can claim that none of them cause you to actually lose time, on any project.

1. Always know why you are catching an exception
This has to be the most common mistake I see people make, and it seems to me that exceptions is a feature many people haven't really learned how to use yet. One of the reasons for this is probably that before the advent of Java the languages people used at university did not have exceptions, and so no rules were taught about this. It's not a trivial feature to use, so it's hardly surprising that people struggle.

Anyway, the cardinal rule is: if you catch an exception you need to have a good reason. Reporting an expected error condition to the user in a more friendly way is a good reason. Handling an expected, but unusual, condition is another. But very often people just swallow the exceptions with an empty catch block (this is a real nono), or they do like this:

  private static List readLines(String fileName) {
    String line;
    ArrayList file = new ArrayList();
    try {   
      BufferedReader in = new BufferedReader(new FileReader(fileName));
      while ((line = in.readLine()) != null)
        file.add(line);
      in.close();
    } catch (Exception e){
      System.out.println(e);
      return null;
    }
    return file;
  }

The catch block here does nothing useful. In fact, it hides useful information if the program were to crash. If you don't catch the exception, you get a traceback. If you do catch it you get much less. Plus, it takes up 5 lines, and it makes the method almost twice as big as it needs to be. Doing without is just a lot better.

That would give us this:

  private static ArrayList readLines(String fileName) throws IOException {
    String line;
    ArrayList file = new ArrayList();

    BufferedReader in = new BufferedReader(new FileReader(fileName));
    while ((line = in.readLine()) != null)
      file.add(line);
    in.close();

    return file;
  }

2. Never declare implementation types
This is another thing I see very often: parameters, variables, or even return types that are really implementation types. You can see this in the code above, where ArrayList is used where List would do. There are several problems with this: ArrayList is longer, and you have to do a lot of work if you want to change what list implementation you are using.

The main thing, however, is that just using List communicates your intent that this be a list much more clearly. It says "I thought about this, and I really intend this collection to be a List, and not just any sort of collection". In other words: it tells the reader that you care about the order in this collection.

Another round of simplification brings us this:

  private static List readLines(String fileName) throws IOException {
    String line;
    List file = new ArrayList();

    BufferedReader in = new BufferedReader(new FileReader(fileName));
    while ((line = in.readLine()) != null)
      file.add(line);
    in.close();

    return file;
  }

3. Use descriptive variable names
This is a rule that can be hard to follow, but in general variables should be named so that they make it clear what a variable contains. Sometimes this is blindingly obvious, and in these cases short names like i for loop indexes, in for files is perfectly OK. But if you use a longer name, try to make it meaningful.

In the case of the method above, what does file really contain? Yes, it does contain the file, but what it really is is a list of all the lines in the file. So why not call it lines? That would give us:

  private static List readLines(String fileName) throws IOException {
    String line;
    List lines = new ArrayList();

    BufferedReader in = new BufferedReader(new FileReader(fileName));
    while ((line = in.readLine()) != null)
      lines.add(line);
    in.close();

    return lines;
  }

Still not perfect, but arguably a lot more readable than the original.

4. Cut-and-paste code
One simple approach that's suggested quite often as a way to improve people's code is to disable the paste function on every developer machine. While the idea may be a little over the top, the basic thought is sound. If you have a snippet of, say, 7 lines of code that do one thing, and you want to do it again to a different set of variables, don't copy and paste the code. Instead, make a function (or a method, if you're stuck with Java).

There are several reasons for this. One is simple brevity. Another is that it makes your code much easier to read, since you would effectively be replacing 14 lines of code with just 2. This would obviously be at the expense of an additional function/method, but since these stand alone and isolated from the rest of the code, their impact on readability is very low. The main reason, however, is that by doing this you make life much easier for yourself. Even if this is a one-time script, you are still going to change the code around. This is easier if it's broken up into parts, like functions/methods.

5. Variables and communication
One of the hardest things to pick up when reading code is to understand the flow of values through the variables in the code. (This is one reason why functional programming is popular.) This has several implications for how the code should be written.

For one thing, this means that you should try to declare variables as close to where they are used as possible. Let's say you write the following:

String tmp = null;
// 50 lines that don't touch tmp
tmp = whatever;
// ...

This means the reader has to scan 50 lines to see if tmp is used anywhere in there. Merging the assignment and the declaration would remove this problem completely, and would lose you nothing.

Another thing this means is that if a variable is only used inside a block (if statement, while loop, or whatever), then it really should be declared in there. Imagine you write this:

int tmp;
for (...) {
  // code that uses tmp
}
// no more mentions of tmp below this point

In this case, you could have declared tmp inside the for loop. Not doing it sends the signal that "I'm going to keep using this variable" and forces the reader to try to figure out what happens with it later. Moving the declaration inside the loop means that you can't use the variable after the loop, which makes the code much easier to read.

A third consequence is that you should really work hard to keep your functions/methods short. If you have a function/method that's, say, 400 lines long it becomes almost impossible to track the data flow through it. There will just be too many variables and too many assignments to keep track of. So this is a real no-no. Just don't do it. And as usual with these rules, this is a rule that will also help you get the code right the first time, so this is worth doing even if you will just write the code and then discard it.

In fact, if you really do keep your methods short, a lot of the other rules here become less important, because the impact of breaking them will be lessened. The reason is of course that it's very hard for a short method to be really difficult to read. There's so little code in a short method that you can almost always digest it quite easily. So you could think of this as being the most important rule.

6. Don't preserve return values you don't use
This is also related to making it easier to track data flow. et's say you write something like this:

boolean present = myCollection.remove(object);

You could have written it like this, however:

myCollection.remove(object);

You can safely assume that any reader of your code will know this, and therefore using the first form is a signal that "I care about this return value, and I'm going to use it for something". If you don't, you'll be confusing the reader, because they are assuming that they now need to figure out what you're going to do with this variable.

Of course, leaving it out saves space, too, so there's really no reason not to drop these variables.

7. Omit needless code!
It's quite common to find code that's commented out, but still hanging around. This is mainly bad because it bloats the code unnecessarily. People seem to do this because they want to have the possibility to bring the code back, either because they are writing an alternative they are not sure about, or (and this seems quite common) because they don't dare to delete it. However, in nearly all cases there is no real reason to keep such code around. You should be using version control, and that means you could always find any deleted code again.

Also, since this code is no longer compiled or executed there is no real difference between commenting it out or deleting it. You've still made the change. The difference is that now it's quite likely that this code will slowly move out of sync with the code around it, so that by the time you find you want it again it will no longer work. That actually makes the code dangerous, because it tempts you to include code without understanding what it does. (If you really understood it you could retype it quite quickly even if it was deleted.)

Of course, commenting out code while you are working on the code is fine. I do that a lot. However, I never check in code that is commented out, and whenever I find such code I delete it, without asking anyone or telling them. If they wanted the code they shouldn't have commented it out. And it will be in the version history, anyway.

分享到:
评论

相关推荐

    Tips for writing good use cases.pdf

    ### 编写优秀用例的关键技巧 #### 引言 编写优秀的用例更像是一门艺术而非科学。正如任何一门艺术一样,在创造杰作时并没有绝对的规则可循。最终,用例的目标在于清晰地向多元化的受众传达详细的信息,并实现创建...

    tips on WCDMA measurement

    some tips on 3G wcdma measurement

    Writing High-Performance NET Code(2nd).pdf 2018新版

    This second edition incorporates the advances and improvements in .NET over the last few years, as well as greatly expanded coverage of tools, more topics, more tutorials, more tips, and improvements ...

    CodeWarrior IDE使用tips之map文件详解

    CodeWarrior IDE使用tips之map文件详解,汽车电子BOOTLOADer中会使用到。

    Clean Python.pdf

    addition, Python doesn’t have any books about clean code like Java and Ruby do. There have been attempts to write those kinds of books to bring clarity to good Python practices, but those attempts ...

    Tips for Optimizing C/C++ Code

    在编程领域,特别是C/C++的性能优化是一门重要技巧,对于代码运行效率提升至关重要。以下是根据上述文档内容提炼出的一些优化C/C++代码的技巧。 首先,要记住阿姆达尔定律(Amdahl's Law)。这个定律用来预测系统或...

    Terraform: Up and Running: Writing Infrastructure as Code

    Terraform: Up and Running: Writing Infrastructure as Code English | ISBN: 1491977086 | 2017 | PDF/EPUB/MOBI | 152 pages | 55 MB With this practical book, you’ll learn how to get you up and running ...

    abap tips abap tips

    abap tips abap tips abap tips abap tips abap tips

    S7_200中文实例Tips&tricks.rar

    《S7_200中文实例Tips&tricks》是一个针对西门子S7-200系列PLC(可编程逻辑控制器)的实用技巧和经验分享集合。S7-200是西门子公司推出的一款小型PLC,广泛应用于自动化控制领域,尤其在中小型制造业中,因其小巧、...

    tips

    一个非常好的tips

    Visual Studio Code tips and tricks for JavaScript developers

    Visual Studio Code tips and tricks for JavaScript developers

    code blocks汉化包

    1. 打开"Settings" -> "Environment",找到"Tips on startup"选项。 2. 勾选该选项,并在下方的"Tips file name"中指定"tips.txt"文件的路径。 3. 设置完成后,每次启动Code::Blocks时,将会显示一条随机的提示信息...

    jquery做的一个onmouse出tips帮助文档的一个效果

    标题 "jquery做的一个onmouse出tips帮助文档的一个效果" 提示我们这个压缩包中的内容是关于使用jQuery实现鼠标悬停(onmouseover)时显示提示信息(tips)的示例。这种效果常见于许多网站,当用户将鼠标移到某个元素...

    S7_200中文实例Tips&tricks

    《S7_200中文实例Tips&tricks》是一个针对西门子S7-200系列PLC编程的实用资源集合。S7-200是西门子推出的一种小型可编程逻辑控制器,广泛应用于工业自动化领域,尤其适合中小型控制系统。这个压缩包中的内容可能是由...

    librarymobile Tips on Designing and Developing Mobile Web Sites

    Bridges和Hannah Gascho Rempel,他们在Code4lib Journal上分享了创建移动图书馆网站的经验。他们探讨了如何通过移动应用提升图书馆资源的易用性,吸引新用户,并加强图书馆与用户的连接。 【标签】: ...

    CodeWarrior 10.x+编译器使用Tips

    ### CodeWarrior 10.x+编译器使用技巧详解 #### 引言 随着技术的进步与发展,CodeWarrior 编译器自 V10 版本以来经历了一次重大革新,这一变化使得新版编译器与之前的版本形成了显著区别。最显著的变化在于新版...

    Writing Windows WDM design drivers

    This well-paced and informative guide offers numerous excellent tips, including how to design device drivers that fit your needs, and a good deal of material on how to test and debug driver code. ...

    python decorator & closure demo code for learning the use tips

    python decorator & closure demo code for learning the use tips

Global site tag (gtag.js) - Google Analytics