三毛說過:基礎(chǔ)是重要的東西,沒有基礎(chǔ)的人,將來走任何一條路都比基礎(chǔ)深厚的人來得辛苦和單薄
當(dāng)我們的開發(fā)Leader或者項目組需要我們編寫符合各種規(guī)則的代碼,我一直是一個不守規(guī)矩的“壞小孩”。我們一直強調(diào)我們的開發(fā)人員寫短的方法,必須編寫注釋,我們甚至用各種工具去Check我們的小伙伴的代碼,注釋,命名規(guī)范,方法長度我們用盡了Check Style里面的定義。但是往往我們忘了了初衷,我們?yōu)槭裁匆⑨?,我們?yōu)槭裁匆?guī)范,我們?yōu)槭裁匆椒ā岸绦《伞薄J堑?,為什么?為什么?為什么?/p>
別給糟糕的代碼加上注釋----重新寫吧!
不記得什么時候開始,我們有了這樣的一個想法,糟糕的代碼可以用完美的注釋來彌補,真的真的是這樣嗎?糟糕的代碼,就是糟糕的代碼,不管用多么好的注釋去彌補還是糟糕的,就像一個腐壞的食品,你在用什么華麗的包裝去包裝它,他還是壞的,必須扔掉,重新做。
什么也比不上放置良好的注釋來的有用,什么也比不上亂七八糟的注釋更加有能耐搞亂一個模塊,什么也不會比陳舊,提供錯誤信息的注釋要有更加的破壞性。
記得在做一個項目的時候,有一位高手就告訴我,假如你得編程語言有足夠的表達力,或者我們擅長用這些語言來表達意圖,就不那么需要注釋,因為你的注釋會將別人帶入到溝里面。
是的帶入到溝里面,當(dāng)我的代碼編寫的越來越多,或者說,閱讀的代碼變多的時候,真的。我已經(jīng)不知道多少次被人帶入到溝里面了。
代碼是一直會變的也在一直演變中,從這里遷移到那里,彼此分離,然后又和別的代碼重新組合,變成一對,但是注釋我們不會總是跟著代碼在變動。
糟糕的代碼,注釋也沒法彌補
用代碼來闡述你的意圖
//檢查員工是否有資格獲得免費的福利
if((employee.flags && HOURLY_FLAG)&&(employee.age>65))
if(employee.isEligibleForFullBenefits())
你會選擇哪一個,讓別人第一時間了解的意圖,即使在不知道你的方法具體實現(xiàn)的時候,讓閱讀的人理解你的意圖。
有時候,代碼本身不足以解釋其行為,不幸的消息是,許多開發(fā)人員常常認(rèn)為代碼很少,如果可以的話,能用注釋做好解釋工作。
好的注釋,有一些注釋必須要有的,也是有利的。不過要記住,唯一真正好的注釋是你想辦法不寫注釋。(但是我不完全認(rèn)可這個)。
法律信息
在我們使用很多開源項目的時候,我們往往會看到以下注釋
//Copyright (C) 2003,2004,2005 by Object Mentor,Inc,All rights reserved.
//Released under the terms of the GNU General Public License version 2 or laster.
提供信息注釋
有時候,用注釋來提供有用的信息也是恰其好處。比如
/**
* @return Responder Returns an instance of the Responder being tested.
**/
protected abstract Responder responderInstance();
//format matched kk:mm:ss EEE,MMM dd,yyyy
Pattern timMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w* \\d* \\d*");
這個注釋說明了,該正則表達式的作用在匹配一個經(jīng)過SimleDateFormat方法格式化完的一個字符串的時間和日期。
對意圖的解釋
有時候,注釋不僅提供了有關(guān)實現(xiàn)的具體說明,而且還提供了某個決定后面的意圖。
例如我們在讀取文件的時候,我們提供出來很多方法的時候,往往我們沒有寫在讀寫完文件的時候,告訴調(diào)用的人員,你需要關(guān)閉文件流,有人這時候會說,這些事程序猿肯定知道的??隙ㄖ赖模淮硪欢ㄖ?,或者一定遵守的。
比如
a.compareTo(b) == 0?
a.compareTo(b)<0
a.compareTo(b)>0
這些其實我們不需要寫注釋的,但是往往我們還是會寫,為什么,因為我們要強調(diào)。
a.compareTo(b) == 0 //a ==b
a.compareTo(b)<0 //a<b
a.compareTo(b)>0 //a>b
這時候,你會發(fā)現(xiàn)有時候好的注釋,往往會讓你“蛋疼”。
TODO注釋
TODO,我想很多人已經(jīng)用過了,TODO是一種程序猿認(rèn)為應(yīng)該做的,比如在某種情況下,目前我們可能還不需要完成某種工作,我們就必須使用TODO
公共API中的JavaDoc
如果你在做一些共通的東西的話,好的JavaDoc將會為你省下很多解釋的時間。因為我們可以使用Javadoc生成很好的API文檔提供給別人。這樣的話,使用人員就可以很明確的明白你的意圖,或者方法的作用
請不要喃喃自語
public void loadProperties(){
? ?try{
? ? ? ? ? ? String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE;
? ? ? ? ? ? FileInputStream propertiesStream = new FileInputStream(propertiesPath);
? ? ? ? ? ?loadedProperties.load(propertiesStream);
? ? ? ? }catch(IOException ex){
? ? ? ? ?//No Properties files means all defaults are loaded
? ? ? ? ?}
}
誰能解釋一下Catch里面注釋的意義,這個可能是開發(fā)人員對于沒有Properties文件的情況做的一個特殊處理,但是有沒有闡述情況,因為在Catch里面只是空空的注釋,別沒有對這塊做任何的操作,難道開發(fā)人員會在后面發(fā)現(xiàn)有問題的情況的時候補充代碼嗎?那么為什么我們不是用TODO呢?
循規(guī)蹈矩的注釋
還記得我們循規(guī)蹈矩的注釋嗎?那些循規(guī)蹈矩的注釋是否真的很有用呢?是不是只是為了保證我們的Check Style通過?好吧,是的。就是為了Check Style通過。但是那些注釋的作用又有多少呢?我可以為是0.
/**
*
*@param title The title of the CD
*@param author The author of the CD
*@param track The number of tracks on the CD
*@param durationInMinutes The duration of the CD in minutes
*/
public void addCd(String title,String author,int tracks,int durationInMinutes){
.......
}
我們是否可以不需要這些我們?yōu)榱薈heck Style通過,而編寫這些廢話的注釋呢?
廢話注釋
廢話注釋,就是那些寫的是廢話的注釋,沒有任何營養(yǎng)的注釋,說的再難聽一點,就是,你寫的那些事廢話,沒有任何價值,你在寫那些的時候,就是浪費人月,浪費時間。
/**
* Default constructor.
**/
public AnnualDateRule(){
}
你告訴我,誰不知道這是默認(rèn)構(gòu)造函數(shù),
還有更加規(guī)范的廢話
/**
* Returns the day of the month.
*@return the day of the month .
public int getDayOfMonth(){
return this.dayOfMonth.
}
這樣的規(guī)范注釋,我們見得很多,有時候我們會糾結(jié),要不要加這些廢話的注釋,但是當(dāng)我們命名規(guī)范或者有含義的時候,我真的認(rèn)為不需要了。除非,你想表達的更加清晰明朗。
還有更加廢話的注釋。
/**The name*/
private String name;
/**The Version*/
private String version;
妹的,想罵臟字了,難道我不知道這個是name,那個是version,要你說。
當(dāng)我們思維達到一個邊界的時候,我們往往會忘了初衷,難道不是嗎?我們的規(guī)范,我們的要求,往往忘了為什么。
寫了這么多,參考一下別人的注釋吧!
/**
* Spring Boot 啟動類,加載需要的Bean和設(shè)置啟動時候Config掃描類.
*@author jiang_nan
*/
@Configuration
@Import({
DispatcherServletAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
ErrorMvcAutoConfiguration.class,
FreeMarkerAutoConfiguration.class,
HttpEncodingAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
JacksonAutoConfiguration.class,
MultipartAutoConfiguration.class,
PersistenceExceptionTranslationAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
RedisAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
WebMvcAutoConfiguration.class,
WebSocketAutoConfiguration.class
})
@EnableTransactionManagement// 開啟注解事務(wù)管理,等同于xml配置文件中的
@ComponentScan(basePackages={"com.msk.batch"})
public classApplicationimplementsTransactionManagementConfigurer {
@Resource
privateEnvironmentenvironment;
@Resource
privatePlatformTransactionManagerdataSourceTransactionManager;
@Bean
publicDataSourcedataSource(){
DruidDataSource dataSource =newDruidDataSource();
String url =environment.getProperty("spring.datasource.url");
dataSource.setUrl(url);
String userName =environment.getProperty("spring.datasource.username");
dataSource.setUsername(userName);
String password =environment.getProperty("spring.datasource.password");
dataSource.setPassword(password);
dataSource.setInitialSize(2);
dataSource.setMaxActive(20);
dataSource.setMinIdle(0);
dataSource.setMaxWait(60000);
dataSource.setValidationQuery("SELECT 1");
dataSource.setTestOnBorrow(false);
dataSource.setTestWhileIdle(true);
dataSource.setPoolPreparedStatements(false);
returndataSource;
}
@Bean
publicJdbcTemplatejdbcTemplate(){
return newJdbcTemplate(dataSource());
}
@Bean
publicPlatformTransactionManagertxManager(DataSource dataSource) {
return newDataSourceTransactionManager(dataSource);
}
@Override
publicPlatformTransactionManagerannotationDrivenTransactionManager() {
returndataSourceTransactionManager;
}
public static voidmain(String[] args)throwsException {
SpringApplication.run(Application.class,args);
}
}
沒有一行多余的注釋。