Code style 2014-07-18-pub

51
Code Style PersiaCai 2014-07-18

Transcript of Code style 2014-07-18-pub

Page 1: Code style 2014-07-18-pub

Code StylePersiaCai

2014-07-18

Page 2: Code style 2014-07-18-pub
Page 3: Code style 2014-07-18-pub
Page 4: Code style 2014-07-18-pub

一致的风格比“正确”的风格更重要

Page 5: Code style 2014-07-18-pub

目录

Why Code Style What’s Code Style about How to follow

Page 6: Code style 2014-07-18-pub

WHY

1、业界约定俗成

2、代码结构美学3、工程化的需要

Page 7: Code style 2014-07-18-pub

WHAT

1、Specification(根据GoogleCodeStyle) 源文件及其结构 格式及注释 声明及命名

2、Best Practice方法、命名

Page 8: Code style 2014-07-18-pub

1.1源文件及其结构

1、编码格式:UTF-82、换行:UNIX/LINUX 换行 (git设置)3、import,不使用通配符4、类成员顺序:

A、public – protected – private B、类成员在上,方法在下

Page 9: Code style 2014-07-18-pub

2.1格式—括号

1、可选大括号也加上 if, else, for, do, while语句一起使用,即使只有一条语句(或是空),也应该把大括号写上

2、Kernighan和Ritchie风格

左大括号前不换行左大括号后换行右大括号前换行

if (condition()) { try {

something(); } catch (ProblemException e) { recover(); }}

Page 10: Code style 2014-07-18-pub

2.2格式—注释

1、字段 /** xxx */2、方法

/** * */public void push(PaintBoard paintBoard) { doSomething(); }

Page 11: Code style 2014-07-18-pub

2.2格式--注释

3、好代码>坏代码+注释4、记录你的思想 //这个用法是出于…考虑

Page 12: Code style 2014-07-18-pub

2.3格式-缩进

1、语句块缩进每当一个新的语句块产生,缩进就增加两个空格。

当这个语句块结束时,缩进恢复到上一层级的缩进格数。

2、每句代码的结束都需要换行。3、行长度限制:80或100 长行要断行,断行缩进4字符

Page 13: Code style 2014-07-18-pub

2.4格式-空白

1、垂直空白方法间空白行间隔

方法体类空白行进行逻辑分组

类成员之间,可以不空白行间隔

2、水平空白赋值等号前后的空白间隔

Page 14: Code style 2014-07-18-pub

3.1声明

1、每次声明一个变量不要采用一个声明,声明多个变量。例如 int a, b;

2、不能像C风格一样声明数组应该是String[] args,而不是 String args[]

3、修饰符顺序public protected private abstract static final transient volatile synchronized

native strictfp

Page 15: Code style 2014-07-18-pub

3.2命名

1、标示符只应该使用ASCII字母、数字和下划线,字母大小写敏感

尽量不使用前后缀,比如name_, s_name

2、包名全小写,并不使用下划线3、类名 class命名一般使用名词或名词短语。interface的命名有时也可以使用形容词或形容词短语;测试类以Test结尾;接口不加I,实现类Impl结尾

Page 16: Code style 2014-07-18-pub

3.2命名

4、方法名 方法命名一般使用动词或者动词短语,在JUnit的测试方法中,可以使用下划线,用来区分测试逻辑的名字经常使用如下的结构:test<MethodUnderTest>_<state> 。例如:testPop_emptyStack 。

5、常量 大写加下划线分隔;一般使用名词或者名词短语命名。

6、变量非常量的成员变量命名(包括静态变量和非静态变量),采用lowerCamelCase命名;

Camel case 命名:XMLHTTPRequest改为XmlHttpRequest

7、参数名应该避免使用一个字符作为参数的命名方式。

Page 17: Code style 2014-07-18-pub

Best Practice

Page 18: Code style 2014-07-18-pub

代码的写法应当使别人理解它的时间最小化

可读性基本原理

Page 19: Code style 2014-07-18-pub

一、命名

1、提防使用不同之处较小的名称 XYZControllerForEfficientHandlingOfStrings 与

XYZControllerForEfficientStorageOfStrings

在IDE自动补全,容易补全错。

2、使用可搜索的名称 变量作用域大的可以命名相对长一些,便于搜索。

3、每个概念对应一个词 fetch、retrieve、get等若同时出现,容易造成混乱,尽量统一只用一个词。

Page 20: Code style 2014-07-18-pub

一、命名4、布尔值 经常以is开头后面跟名称或名称短语

isDigit,isProbablePrime,isEmpty,isEnabled,hasSiblings

缺点是降低逻辑表达式可读性:if isEmpty (if empty)

5、类型转换 使用toType,比如toString,toArray

6、返回视图使用asType,比如asList

7、返回基本类型使用typeValue,比如intValue

8、静态工厂经常使用valueOf,of,getInstance,newInstance,getType,newType

Page 21: Code style 2014-07-18-pub

一、命名

9、避免泛泛的词downloadPage()要优于getPage()

countSize(),calculateSize()要优于getSize(),size(),前者表示重量级的,需要消耗时间

maxChars要优于maxLength

Page 22: Code style 2014-07-18-pub

一、命名

10、用min,max表示上下限 minInputSize,maxInputSize

11、first,last表示包含的范围 firstDate,lastDate

12、begin,end表示包含-排除的范围 beginDate,endDate

13、动宾结构描述好所做的全部事情 printDocument, calcMonthlyRevenues

描述好返回值 printer.isReady()

14、计算值限定词加到名字最后revenueTotal、revenueAverage这样比totalRevenue、averageRevenue更容易看出命名含义、更有规则性

Page 23: Code style 2014-07-18-pub

一、命名

15、常用对仗词begin/end、first/last、locked/unlocked、min/max、next/previous、old/new、opened/closed、visible/invisible、source/target、up/down

15、缩写的一般指导原则去掉所有非前置元音(computer->cmptr,apple->appl)使用每个单词的第一个或前几个字母

保留每个单词的第一个和最后一个字母

去除无用的后缀(ing、ed等)

Page 24: Code style 2014-07-18-pub

二、函数

1、函数参数越少越好 调用方不用了解细节

2、同类型函数参数最好间隔 不间隔容易传错而不自知

3、避免out型参数 容易引起混乱,统一在返回值里返回

4、避免boolean参数 调用方不知道啥意思,采用枚举替代5、超过4个参数最好封装为类 同时增加precondition校验

Page 25: Code style 2014-07-18-pub

二、函数

6、参数避免传null null值意义不明确

7、返回值避免传null 集合类型返回EMPTY_LIST/EMPTY_MAP/EMPTY_SET, EMPTY_ARR?

8、分隔指令与询问 函数要做什么,要回答什么,二者不可兼得。

只做一件事情,提供功能内聚性。

if(set("username","unclebob")){ ...}

if(attributeExists("username")){ setAttribute("username","unclebob");}

Page 26: Code style 2014-07-18-pub

二、函数

9、异常代替错误码 错误码常常暗示这枚举,应变性差,容易造成if嵌套,改用exception,错误处理就能从主路径代码中分离出来,得到简化。

10、不要使用异常控制循环体

for(Item item : items){ try{ doSomething(item); }catch(Exception e){ continue; } }

try{ Iterator<Foo> i = collection.iterator(); while(true){ Foo foo = i.next(); }}catch(NoSuchElementException e){}

Page 27: Code style 2014-07-18-pub

二、函数

11、分离try/catch的主体 抽出方法,简洁

12、使用卫述句void compute(){ Server server=getServer(); if(server==null) return; Client client=server.getClient(); if(client==null) return; Request current=client.getRequest(); if(current==null) return; processRequest(current);}

Page 28: Code style 2014-07-18-pub

二、函数

13、容器成员提供额外封装 封装增加或删除元素方法,对于返回整个容器,尽量返回不可变类型

List<Book> getBooks(){ return Collections.unmodifiableList(books);}

void addBook(Book arrival){ books.add(arrival);}

int bookCount(){ return books.size();}

Iterator getBooks(){ return books.iterator();}

Page 29: Code style 2014-07-18-pub

二、函数

14、尽量避免连续调用 builder,stream等模式除外

predeal.getPlanTask().getProduct().getCoverImg();

Page 30: Code style 2014-07-18-pub

二、函数

15、方法命名帮助传参

16、描述化

assertEquals(expected,actual),让调用者需要注意传入的顺序,有一定的犯错的概率。

assertExpectedEqualsActual(expected,actual),这样的函数命名,就大大减轻了记忆参数顺序的负担。

List moduleDependees = module.getDependSubsystems();String ourSubSystem = subSysMod.getSubSystem();if(moduleDependees.contains(ourSubSystem ))

//does the module from the global ....if(module.getDependSubsystems().contains(subSysMod.getSubSystem()))

Page 31: Code style 2014-07-18-pub

二、函数

17、防卫式校验

18、慎用可变参数

public Period(Date start, Date end) { if (start.compareTo(end) > 0) throw new IllegalArgumentException( start + " after " + end); this.start = start; this.end = end; }

#wrongSystem.out.println(Arrays.asList(myArray));#rightSystem.out.println(Arrays.toString(myArray));

Page 32: Code style 2014-07-18-pub

二、函数

19、for优先于whileIterator<Element> i = c.iterator();while(i.hasNext()){ doSomething(i.next());} for(Iterator<Element> i =c.iterator();i.hasNext();){ doSomething(i.next());} �

Iterator<Element> i2 = c2.iterator();//BUG,拷贝出错了while(i.hasNext()){ doSomething(i.next());}//compile errorfor(Iterator<Element> i2 =c2.iterator();i.hasNext();){ doSomething(i.next());}

Page 33: Code style 2014-07-18-pub

二、函数

20、for-each优先于forpublic class NestedIteration { public static void main(String[] args) { Collection<Suit> suits = Arrays.asList(Suit.values()); Collection<Rank> ranks = Arrays.asList(Rank.values()); List<Card> deck = new ArrayList<Card>(); //BUG,NoSuchElementException for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); ) deck.add(new Card(i.next(), j.next())); // Preferred idiom for nested iteration on collections and arrays// for (Suit suit : suits)// for (Rank rank : ranks)// deck.add(new Card(suit, rank)); }}

Page 34: Code style 2014-07-18-pub

二、函数

21、不要修改入参

inputVal是入参,容易理解为不变的,后续修改者可能把它当做不变量用。

public int sample(int inputVal){ inputVal = inputVal * 2; … return inputVal; }

public int sample(int inputVal){ int workingVal= inputVal * 2; … return workingVal; }

Page 35: Code style 2014-07-18-pub

二、函数

22、异常的抽象层次应与方法一致

此处不应该把底层异常抛出去,暴露了实现细节,应该包装为与之在同一层次的异常

class Employee{ public TaxId getTaxId() throws EOFException{ }}

class Employee{ public TaxId getTaxId() throws EmployeeDataNotAvailable{ }}

Page 36: Code style 2014-07-18-pub

二、函数

23、用布尔变量对程序加以文档说明

目的不明确的布尔判断 VS 目的明确的布尔判断

if( (elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || (elementInddex == lastElementIndex) ){}

finished = (elementIndex < 0) || (MAX_ELEMENTS < elementIndex) ;repeatedEntry = elementInddex == lastElementIndex ;If (finished || repeatedEntry){

}

Page 37: Code style 2014-07-18-pub

函数

相对于追求最小化代码行数,一个更好的度量方法是最小化人们理解它所需的时间。

if (exponent >= 0) {return mantissa * (1 << exponent);

} else {return mantissa / (1 << -exponent);

}

return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);

Page 38: Code style 2014-07-18-pub

三、循环

1、在写一个比较时

(while(bytes_expected>bytes_received)),

把改变的值写在左边并且把更稳定的值写在右边更好一些(while(bytes_received<bytes_expected))。

Page 39: Code style 2014-07-18-pub

三、循环

2、什么时候使用while,什么时候使用for

while是灵活的循环,适用于预先不知道循环要迭代多少次;

for循环用来执行那些不需要循环内部控制的简单操作,适合循环控制就是简单的递增或递减,无须在循环内部去控制循环条件。

尽量不要在for循环通过直接修改下标值的方式迫使它终止。

Page 40: Code style 2014-07-18-pub

三、循环

3、带退出循环,更容易维护

while(true){ if(rating < target){ break; } rating = cal(parm);}

rating = cal(param);while(rating < target){ rating = cal(param);}

重复的代码,在修改的时候,常常忘记保持一致

Page 41: Code style 2014-07-18-pub

三、循环

4、循环内务操作尽量放到循环体内,循环头仅仅控制条件

while((inputChar = dataFile.getChar()) != EOF_CHAR){ ;}

do{ inputChar = dataFile.getChar();} while( inputChar != EOF_CHAR)

Page 42: Code style 2014-07-18-pub

三、循环

4、误用for循环

for(inputFlie.moveToStart(),recordCount =0; !inputFile.endOfFile(); recordCount++){ inputFile.getRecord();}

For循环头的位置保留给循环控制语句。

inputFile.moveToStart();recordCount=0;while(!inputFile.endOfFile()){ inputFile.getRecord(); recordCount++;}

Page 43: Code style 2014-07-18-pub

单元测试

(1)快速(Fast) 快速运行

(2)独立(Independent) 每个测试相互独立,某个测试不应该为下一个测试的设定条件

(3)可重复(Repeatable) 在任何环境可以重复通过

(4)自足验证(Self-Validating) 测试应该有布尔值输出,无论是通过还是失败,不应该通过日志文件来确认测

试是否通过。

(5)及时(Timely) 在编写代码之前编写测试

Page 44: Code style 2014-07-18-pub

单元测试

1、一个单元测试是一段代码,这段代码调用一个工作单元,并检验该工作单元的一个具体的最终结果。如果关于这个最终结果的假设是错误的,单元测试就失败了。一个单元测试的范围可以小到一个方法,大到多个类。

2、集成测试是对一个工作单元进行的测试,这个测试对被测试的工作单元没有完全的控制,并使用该单元的一个或多个真实依赖物,例如时间、网络、数据库、线程或随机数产生器等。

3、单元测试方法的命名:[UnitOfWorkName]_[ScenarioUnderTest]_[ExpectedBehavior]

实例:isValidFileName_badExtension_returnFalse()

isValidFileName_goodExtensionLowercase_returnsTrue()

4、一个测试通常包括Arrange、Act和Assert这3部分,分别表示测试准备、调用带测方法、验证结果是否符合预期。

5、在一个测试中先写最后的Assert部分,然后推导出Act和Arrange这两部分代码,会更加符合TDD的测试驱动风格,营造出分形的和谐气氛。

Page 45: Code style 2014-07-18-pub

单元测试臭味

1、强制的测试顺序

不能保证测试的可重复性

2、测试方法中调用其他测试方法

破坏了测试的独立性

3、破坏共享状态

破坏了测试的稳定性

Page 46: Code style 2014-07-18-pub

HOW

Page 47: Code style 2014-07-18-pub

Reference

Google Java Code Style

Page 48: Code style 2014-07-18-pub

Reference

Page 49: Code style 2014-07-18-pub

Reference

Page 50: Code style 2014-07-18-pub

Q

A

Page 51: Code style 2014-07-18-pub