你可以從你們現在項目里面隨便找幾處注釋,看看寫注釋的代碼是不是存在如下兩種毛病之一:
1. 命名不准確;
2. 方法太長(超過50行)。
如果你找到的代碼沒有出現上面兩種毛病而注釋依然存在,那你再看看這個注釋是否有實際意義,是不是這個注釋不要也無所謂呢。
注釋是惡魔
這個觀點可能你第一次看到,你可能很難接受,因為寫了這么多年的注釋,你從未想過注釋居然是惡魔,所以,你看到這個觀點的時候可能就會本能的找出1000種理由反對(絕對不可能實現啊什么的),但是,這個觀點並不是今天才出現,相信很多年前就有人提出,現在已被越來越多的人認可。
我第一次接受到這個觀點還是從一個美國客戶(十幾年編程經驗的技術大牛)那里,2011年,他讓我們不要寫注釋。他當時主要意思是我們寫的中式英語他猜起來太費勁,所以他后面又安慰我們說“好的代碼是不需要注釋的”,而我從此就將他后面那半句話奉為至寶。
注釋是惡魔,它將我們的代碼變得很難理解。就像本文開篇說的,你可以找找你們項目中出現注釋的地方,要么命名不准確,要么方法太長。你可以隨機找10處注釋,看看有幾處是惡魔,歡迎貼到評論中。
舉一個以前項目中的例子吧,命名不准確的例子:
/// <summary> /// 管理員是否可以審核該申請 /// </summary> public bool IsAudit { get; set; }
在這個例子中,其實將"is"換成"can"就不需要注釋了。
寫注釋讓代碼更難讀。
首先,如果一個程序員可以隨便寫注釋,那么他對命名准確性和方法長度的控制就不會那么在意,寫代碼更隨意,代碼質量比不能寫注釋的程序員更大幾率低下。
其次,代碼注釋只是在寫代碼的時候提供說明,如果讀代碼都依靠注釋的話,那一個類被另一個類引用來引用去的就根本沒法閱讀了。
所以,“寫注釋是為了讓代碼更易讀”本身就是站不住腳的。
不寫一行注釋?根本就做不到!
這句話可能從你閱讀本文開始在心里面重復了無數遍,這也是大多數人的心聲。
其實前面說的,寫注釋讓代碼更難讀的觀點很多朋友從內心上是認可的。因為確實沒有辦法啊,有的方法業務邏輯復雜,不知不覺方法已上百行,有的命名還是中西結合的,不寫注釋自己第二天就讀不懂了。所以,真是糾結,內心承受百般折磨。
寫到這里,突然想起在園子里看到的一個笑話,說一個公司的產品每年都在更新換代,因為每年新招的程序員都要把程序重新寫一遍。
“零注釋”根本做不到?如果你叢刻開始懷疑自己的這個觀點,那你就可能做得到。
如何做到不寫一行注釋
1. 從現在開始,強迫自己不要寫注釋。
2. 控制每個方法不超過50行,用方法定義來描述方法的實現邏輯。
3. 變量命名不要太過隨便。
本文想要告訴大家的是,零注釋一點都不難。我們團隊大約從2012年開始全面執行零注釋,后面經歷2個產品項目,多個外包項目,積累的經驗越來越多,獲得的質量效果越來越好,零注釋越來越深入人心。
零注釋這個編碼規則也是我們團隊近些年質量建設非常重要的里程碑之一,再此分享給大家。如果能夠影響你一點點,那都足夠了。
附2個我們的代碼片段
雖沒有注釋,大家不妨猜猜這兩個方法做什么用的。
1. 查詢的例子
1 public PageResult<IssueDto> Search(IssueSearchCriteria criteria, PageRequest request) 2 { 3 using (var db = base.NewDB()) 4 { 5 return db.Issues 6 .WhereByAssignee(criteria.AssignedUserId) 7 .WhereBySupervisor(criteria.SupervisorUserId) 8 .WhereByCategory(criteria.CategoryId) 9 .WhereBySearchStatus(criteria.Status) 10 .WhereDateRange(criteria) 11 .WhereNotDeleted() 12 .WhereByKeyword(criteria.Keyword) 13 .ToDtos() 14 .OrderByDescending(x => x.CreatedTime) 15 .ToPageResult(request.PageIndex, request.PageSize); 16 } 17 }
2. 更新的例子
1 public void Submit(Guid userId, string content, string text, double lng, double lat, string address) 2 { 3 using (var db = base.NewDB()) 4 { 5 var issue = new Issue(userId, content, text, lng, lat, address); 6 db.Issues.Add(issue); 7 db.AddIssueLog(IssueLog.CreateOnSubmit(issue.Id, db.Users.GetNickName(userId))); 8 db.SaveChanges(); 9 10 issue.GenerateSerialNumber(); 11 if (!string.IsNullOrEmpty(SettingContext.Instance.AdminOpenIds)) 12 { 13 var name = db.Users.GetName(userId); 14 var totalPendings = db.Issues.Count(x => x.Status == IssueStatus.None && x.IsDeleted == false); 15 var adminOpenIds = SettingContext.Instance.AdminOpenIds.Split(','); 16 foreach (var openId in adminOpenIds) 17 { 18 var message = new PendingProcessTemplateMessage(openId, issue, name, totalPendings); 19 db.WeixinScheduledMessages.Add(message.ToWeixinScheduledMessage()); 20 } 21 } 22 db.SaveChanges(); 23 } 24 }
