Friday, September 25, 2015

Misc - How to Write High Quality Code



https://www.jdon.com/49996
https://medium.com/@kentbeck_7670/what-to-tidy-28cb46e55009
make things a little better, stay safe, celebrate progress

Some uses of conditionals obscure the programmers’ intent.

One way conditionals go wrong is when they conceal the simple case. Turn this:

if (condition) {
 …many lines…
} else {
 …one line…
}
into:

if (!condition) {
 …one line…
} else {
 … many lines…
}
(You get bonus points if the condition was already negated and you can remove the negation.)

A conditional ought to say, “There are two possible paths of computation here.” Sometimes, however, the programmers want to say, “Here is a precondition. If it isn’t met, then this computation isn’t valid/necessary.” For example, a value needn’t be computed if it is cached.

if (cache) {
 return cache;
} else {
 …compute the cached value…
 return cache;
}
This snippet of code doesn’t really have two equally balanced alternatives, it has a precondition and then a computation. Tidy up to use a Guard Clause instead.

if (cache) return cache;
…compute cached value…
return cache;

Redundancy
As code evolves, locally-optimized programming decisions can leave messes where there is a shorter, clearer alternative. Tidy up by fixing these spots one at a time. Replace “if (flag == true)” with “if (flag)” (assuming your programming language supports this). Replace “collection.size == 0” with “collection.isEmpty”.

The idea with this tidying is to find a dominating way of expressing a bit of computation. The tidy way of speaking is just shorter, clearer, and in all ways better.

A more extreme example is when exception handling is used where return values would work just fine. Don’t use a bigger stick than necessary.

Extraction
Expressions can start simple and then grow. At each step it is easier to add to the expression than to factor out parts. That’s where tidying comes in.

Tidy expressions by extracting parts and giving the temporary variable a suggestive name. Turn this:

return new Point(…long expression to compute x…, …long expression to compute y, which is interesting for different reasons than x…)
into:

x := expression to compute x;
y := expression to compute y;
return new Point(x, y);
When tidying it is perfectly okay to extract a single Explaining Variable and commit. There will be time to tidy

A more ambitious (perhaps I should say “courageous”) tidying is extracting a Method Object. See (link) for details. Method Objects often enable dramatic subsequent cleanup, but if you’re tidying, just extracting the new object and invoking it is plenty of work for one commit.

Depending on your reader, you might put all the helpers first and the main logic flows at the end or you might have the main flow first and the helpers after.

https://www.facebook.com/notes/kent-beck/the-life-changing-magic-of-tidying-up-code/1544047022294823/
If it’s hard, don’t do it
Start when you’re fresh and stop when you’re tired
Land each session’s work immediately
Two reds is a revert
Practice
Isolate tidying

Tidying up can happen in parallel with development, but only if you carefully track other changes (I messed this up with my latest diff). Rule #3 is Land each session’s work immediately. Unlike feature development, where it sometimes makes sense to land only when a chunk of work is done, tidying up is time based.
Tidying up requires little effort for any step, so I am willing to discard any step at the first sign of trouble. For example, Rule #4 is Two reds is a revert. If I tidy, run the tests, and encounter a failed test, then if I can fix it immediately I do. If I try to fix it and fail, I immediately revert to the last known good state.
Tidying up works only if the risk of collateral damage is low and the cost of reviewing tidying changes is also low. Rule #6 is Isolate tidying. This can be tough when you run across the chance to tidy in the midst of writing new code. Either finish and then tidy or revert, tidy, and make your changes.
Try it. Move the declaration of a temp adjacent to its first use. Simplify a boolean expression (“return expression == True” anyone?). Extract a helper. Reduce the scope of logic or state to where it is actually used.
https://zhuanlan.zhihu.com/p/43105253
  1. 外在美
    外观看起来优雅美观的代码会使人心情愉悦。其中主要体现在:代码所在的位置是否恰当,代码里是否有适当的注释,适当的缩进和空行以及没有重复代码等等。
  2. 内在美
    外在美只是“看起来”使人心情愉悦,如果缺乏内在美,那么当别人真正开始读的时候,刚才愉悦的心情会在一瞬间烟消云散。而内在美则体现在:尽量少的API,代码之间的尽量少的依赖,干净利落的抽象和直截了当的控制语句等。
  3. 有意义的命名

    错误处理
    代码运行时的错误如何处理吗?全部抛出去,交个用户处理?全部catch住,隐藏起来不处理?这两种程序员相信都会被老板当成错误处理掉吧。



    合格的单元测试
    什么样的单元测试才算合格,单元测试对代码的覆盖率要达到多少?



    迭代
    胖子从来都不是一口吃成的,怎么才能让你的代码越来越饱满,系统越来越稳定呢?唯有不断迭代。
    为什么函数要短小呢,如何才能是自己的函数更加短小?第一个问题我也无法证明,只能告诉你短小的函数看起来更加清晰,更加容易理解。那怎么才能让函数变得更加短小呢?很简单,抽离方法。将一些代码抽离成另一个函数。什么样的长度才是合适的呢?我认为不必过于追求短。这里的长度我们可以以代码块的层来定义

只做一件事

参数数量越少越好
https://mp.weixin.qq.com/s/jxFSsrOZ2Bp8i0vSyf4fiw

说明发生异常的环境

在Java中,系统异常通常会给出调用栈,便于我们进行问题的定位和调试。对于我们自己抛出的异常,也应该给出异常发生的环境,例如列出调用栈,给出请求参数等等。
是不是适当增加空白行就提高了代码的可读性呢,这里说的是适当增加空白行,并不代表随意增加。事实上,如果增加一些无意义的空白行反而会使代码的可读性变差。
最后,我们通常把实体变量定义在类的顶部,这个只是我们Java程序员的习惯操作,如果突然在类的中间位置出现一个变量声明会让人觉得很奇怪。如果你想说,定义在中间是不想让定义位置和调用位置离太远,那么只能说明你的类定义出现了问题
代码洁癖系列(四):可忽略的注释

提供信息的注释


// Returns an instance of the Responder being tested.
protected abstract Responder responderInstance()

这样的注释就是不错的注释,给读者提供了返回值的信息,不过,如果我们把函数命名为responderBeingTested,那么这个注释也就显得多余了。

自说自话

写的东西只有自己能看懂,别人都不明白要表达什么。如果读代码时连注释都看不明白,还有人想看下去吗。
所谓见贤思齐焉,见不贤而内自省也。看完了好的注释,就要想想怎么才能写出好的注释;接下来再来看看坏的注释,看的同时需要多反省自己,尽量避免写出坏的注释。
https://dzone.com/articles/clean-code-principles
It all started in 2001 when I was reading the Pragmatic Programmer by Andy Hunt and Dave Thomas. I read statements (like, “never accept a broken window,”) that resonated with me.

On the other hand, I want my code to be perfect as possible the first time, not because I like wasting time, but because I’m thrifty enough to see that it’ll save me way more time later on.
15 Rules for Writing Quality Code
Rule 1: Follow the Style Guide
Rule 2: Create Descriptive Names

Rule 3: Comment and Document
Start every routine you write (function or method) with a comment outlining what the routine does, its parameters, and what it returns, as well as possible errors and exceptions.

Rule 4: Don't Repeat Yourself

Rule 5: Check for Errors and Respond to Them

Rule 6: Split Your Code into Short, Focused Units
Rule 7: Use Framework APIs and Third-Party Libraries

Rule 8: Don't Overdesign
Keep your design focused on today's needs. Your code can be general to accommodate future evolution, but only if that doesn't make it more complex. Don't create parameterized classes, factory methods, deep inheritance hierarchies, and arcane interfaces to solve problems that don't yet exist—you can't guess what tomorrow will bring. On the other hand, when the code's structure no longer fits the task at hand, don't shy away from refactoring it to a more appropriate design.

Rule 9: Be Consistent
Your code should adopt the conventions of the framework in which you're programming.

Rule 10: Avoid Security Pitfalls
Rule 12: Include Unit Tests
Rule 14: Make Your Code Buildable
http://simpleprogrammer.com/2013/04/14/what-makes-code-readable-not-what-you-think/
  • Variables, classes and methods that have a single purpose
  • Reduction of the nesting level in code
http://bensmith.io/20-tips-for-better-naming
http://www.codeceo.com/article/20-naming-tips-programmer-know.html
1. Use intention revealing names:
A name should tell you what it does, why it exists, and how it is used. Choosing names that reveal intent makes it much easier to understand and change code.

2. Don’t be afraid to spend time choosing a name:
3. Refactoring names:
4. Avoid noise words in your names:
Noise words like Manager , Processor, Data, or Info and are synonyms for “I don’t know what to call this”. If you find yourself wanting to use one of these words it may be that the thing you are trying to name is doing too much.

5. Be wary of hard to name classes/functions:
A hard to name class or function is a possible code smell. If you are finding it difficult to give a class or function an expressive name this could be a sign that:

the offending code is doing too much.
the offending code is not doing enough.
you do not understand the domain well enough and need to get more information before continuing.

6. Class names:
Classes should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. When using inheritance superclasses should have short and punchy names. Subclasses should have longer names containing adjectives that describe how this class differs from it’s superclass e.g. SavingsAccount derives from Account.

7. Variable names:
Variables often hold instances of classes so they should be nouns too. They are often derived from the name of the class that they refer to. Boolean variables should be written as predicates e.g. isEmpty or isTerminated so that they read well in if statements.

9. Scope size to variable name length:
For variables the length of the name should correspond to the size of it’s scope. If the variable is used in only a very short scope then the length of the variable name should be very short. Conversely, if the variable is within scope for a long time, the name of the variable should be more descriptive and so the name should be longer.

10. Scope size to method/class name length:
For methods and classes the length of the name should inversely correspond to the size of it’s scope. For public methods, shorter names are usually better as they will be called many times. Private methods will only be called within the scope of the class and so longer names are preferred that will act as documentation. The exception to this rule are derived class names. The more derived a class, the more adjectives are applied to the base class name and the longer it will be.

11. Pick one word per concept:
Pick one word for one abstract concept and stick to it. For example it’s confusing to have get(), fetch() and retrieve() as equivalent methods of different classes. A consistent lexicon is an important tool for programmers that must work with your code.

12. Avoid using the same term for two disparate concepts:
If you follow the one word per concept rule then you will end up with many classes that have the same method names. This is fine as long as the parameter lists and return values of the various methods are semantically equivalent. Where problems will occur is if you use the same term for two disparate concepts.

13. Use solution domain names:
The code we write will be viewed by other programmers. Since this is the case it is beneficial to use technical terms where appropriate such as algorithm names, pattern names and maths terms given that these should evoke the correct concepts in the minds of the reader.

14. Use problem domain names:
When there is no technical name for a concept then it is wise to use a name from the problem domain. This will provide the option for future readers of your code to consult a domain expert if they are unsure what something in the code is doing.

15. Add meaningful context:
Most names are not meaningful in and of themselves and would need to be placed within a context (class/function/namespace) for a reader to understand what they refer to. In some cases it may be necessary to prefix names to add some context. For example, if we have a number of variables that are used to represent an address firstName, lastName, street, houseNumber, city, state and zip . If you just saw the state variable it would be hard to automatically infer what it was referring to, a better solution would be to encapsulate the variables in an Address class.

16. Don’t add gratuitous context:
Short names are generally better than longer ones, so long as it is clear, don’t add context to a name that does not need it. Names should not be prefixed with unnecessary information that can be inferred from the class/package/namespace that the name is within.

17. Avoid encodings:
Given the power of modern day IDE’s, we do not need to encode type or scope information into the names of our variables or classes. This includes not appending I to interfaces, the users of our code do not need to know that their classes are being passed an interface. If you have to use encoding then it is better to encode the implementation than it is to encode the interface.

18. Avoid disinformation:
Do not leave false clues that misinform the reader as to the meaning of the code. If you have a variable named accountList that actually holds an array this may lead to false conclusions. A name should say what it means, and mean what it says.

19. Use pronounceable names:
Programming can be a social activity, using unpronounceable names hampers our ability to discuss the code that we are working on with others.

20. Use searchable names:
Using short generic names hampers our ability to search for things within our codebase. This is important for manoeuvring around the code and in our ability to refactor.

This imprecision makes Manager a bad word to use in naming classes. For instance, take a class named UrlManager – you cannot tell whether it pool URLs, manipulates URLs or audits the use of them. All the name tells you is that this class does something with URLs. On the other hand, the name UrlBuilder provides a much clearer picture of what the class does.
In the Java world, the Manager suffix is thrown around a lot. Almost anywhere you have a class that is responsible in any way for other objects, it automatically earns the Manager label.
Giving your classes and objects good, descriptive names isn't easy. Steve McConnell provides a few helpful guidelines for routine naming in Code Complete:
  1. Describe everything the routine does
    And we mean literally everything. If that makes the name ridiculously long, the name isn't the problem. Your routine is.
  2. Avoid meaningless, vague, or wishy-washy verbs
    Like UrlManager, or HandleOutput(), or PerformServices(). Be specific. What does it do? If you can't answer that question succinctly, it may be time to refactor the code until you can.
  3. Don't differentiate routine names solely by number
    I include this only for completeness. If you ever find yourself writing OutputUser1()and OutputUser2(), God help you. And God help the team you work with.
  4. Make names as long as necessary
    According to McConnell, the optimum name length for a variable is 9 to 15 characters; routines tend to be more complex and therefore deserve longer names. Make your names as long as they need to be in order to make them understandable.
  5. For functions, try using a description of the return value
    An easy, straightforward rule. Some examples are printer.IsReady()pen.CurrentColor(), etcetera.
  6. Use opposites precisely
    For every Open(), there should be a Close(); for every Insert(), a Delete(); for every Start(), a Stop().
  7. Establish conventions for common operations
    This is best illustrated with an example, and McConnell provides an excellent one:
    employee.id.Get()
    dependent.GetId()
    supervisor()
    candidate.id()
    
    Now how do I get an Id again?
I'd say renaming classes and variables is one of my most frequent refactoring activities.Creating good names is hard, but it should be hard, because a great name captures essential meaning in just one or two words
Bucket
"Pool" has a more computer-sciency feel to it, but means the same thing.
Supervisor
A "Supervisor" implies allocating work or checking its progress.
In a sytem handling workflow for users, an object responsible for balancing units of work amongst user queues could properly be called a QueueSupervisor.
There are plenty of other words to use to describe objects that interact with, coordinate are are responsible for others: Auditor, Gatekeeper, Coordinator, Planner, Home, Utility, Builder all come to mind. The trick is to be succinct and accurate.

纠结才能写出好代码
程序员的代码修炼应该有两个目标,一个是代码的执行效率,另一个是代码的可读性

想要写出好的代码,就要在写的时候纠结一会儿。 解决一个问题,有时候我们要适度纠结,来使我们的代码更加可读,效率更高。
public Bitmap getFavicon(final WebView webview) { if (null != webview && null != webview.getFavicon()) { return webview.getFavicon(); } else { return BitmapFactory.decodeResource(getResources(), R.drawable.default_favicon); } }
===>
public Bitmap getFavicon(final WebView webview) { Bitmap favicon = null; if (null != webview && (favicon = webview.getFavicon()) != null) { return favicon; } else { return BitmapFactory.decodeResource(getResources(), R.drawable.default_favicon); } }
===>
public Bitmap getFavicon(final WebView webview) { Bitmap favicon = null; if (null != webview && (favicon = webview.getFavicon()) != null) { return favicon; } else { return BitmapFactory.decodeResource(getResources(), R.drawable.default_favicon); } }

http://www.cnblogs.com/leefreeman/p/3585032.html
编码标准:这个想必都很清楚,每个公司几乎都有一份编码规范,类命名、包命名、代码风格之类的东西都属于其中。
代码重复:顾名思义就是重复的代码,如果你的代码中有大量的重复代码,你就要考虑是否将重复的代码提取出来,封装成一个公共的方法或者组件。
代码覆盖率:测试代码能运行到的代码比率,你的代码经过了单元测试了吗?是不是每个方法都进行了测试,代码覆盖率是多少?这关系到你的代码的功能性和稳定性。
依赖项分析:你的代码依赖关系怎么样?耦合关系怎么样?是否有循环依赖?是否符合高内聚低耦合的原则?通过依赖项分析可以辨别一二。
复杂度分析:以前有人写的程序嵌套了10层 if else你信吗?圈复杂度之高,让人难以阅读。通过复杂度分析可以揪出这些代码,要相信越优秀的代码,越容易读懂。

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts