「我们是认真严肃地看待命名这件事,请您牢记这一点」
取自: Clean Code (p.20)
我们替 jar、war、ear、json...等档案不断地命名再命名...
这是一个专案的目录结构:
code/
├─ a/
├─ b/
│ ├─ A
│ ├─ B
├─ c/
├─ d.x/
├─ d.y/
├─ d.z/
有可能从这样的命名结构看出上列专案在做什麽吗? 恐怕是很困难的
实务上虽不至於有人会这麽胡乱地命名,但由於对命名 (Naming) 的小看,导致还没点开程序码,专案本身的可读性就先下降了,这种情况倒是屡见不鲜...
接着将上面的目录结构改为:
code/
├─ lib/
├─ machine/
│ ├─ mipssim
│ ├─ console
├─ network/
├─ build.cygwin/
├─ build.linux/
├─ build.macosx/
我想每个读者即使不了解作业系统,也能从架构中大概猜到这是一个:
好的命名使读者在尚未深入细节前,就能对专案的模块、类别的定位、函式行为...等有初步的概念
书中作者假设这是常识了,连提都不提 QQ
现代软件开发基本都是采用下列命名惯例:
string firstName = "JJJJ";
string userPhone = "123456789"
public class HomeController : Controller
{
public HomeController()
{
}
public IActionResult Index()
{
return View();
}
}
# 切分训练资料集
array = data.values
X = array[:, :-1]
Y = array[:, -1].astype('int')
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=0)
例如:
int d; // elapsed time in days
// vs.
int elapsedTimeInDays;
int daysSinceCreation;
int fileAgeInDays;
哪一种命名更有表达力呢?
若这些变数是从外部环境引入(import, using),不实际点开档案前,有谁会知道 "xxx.d" 代表什麽呢?
「如果一个变数名称还需要注解的辅助,那麽这个名称就不具备展现意图的能力」
「避开使用那些与原意图相违背的常见单词」
def get_dist(a1, a2):
return a2 - a1
# Which Do you Like?
def get_dist(source, destination):
return destination - source
P.S. 笔者真的有在工作场合看过取名为 List1, List2, List3 这样的程序码...,也许改成ListForXXX, ListForYYY, ListForZZZ 会是更好一点的作法
说明:
当全域搜寻某变数时,我们不会希望跳出一大堆与目标无关的内容,只因他们的名称太类似、甚至一样 (白话文: 菜市场名)。在命名的时都要问自己: 如果未来想搜寻这个名称、是否能马上就找到?
不用担心影响到打字时间,现代开发工具补齐功能都很完善
例: 如果我们未来想搜寻 "34"、"5" 出现在哪,试问专案搜寻结果会出现几种可能性?
int s = 0;
for (int i = 0; i < 34; ++i){
s += t[i] / 5;
}
而我们多宣告了 2 个变数,就能大大地减少变数搜寻时间:
const int NUMBER_OF_TASKS = 34;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int i = 0; i < NUMBER_OF_TASKS; ++i){
sum += tasks[i] / WORK_DAYS_PER_WEEK;
}
「就这一点而言,长命名胜过短命名」
class Employee
{
public:
void setEmployeeName(string empName);
string getEmployeeName() const;
void setEmployeeId(string empId);
int getEmployeeId() const;
bool isEmployeeNameValid();
bool isEmployeeIdDuplicate();
private:
private string employeeName;
private int employeeId;
}
「替单一抽象概念挑选一个字词,并坚持持续地使用它」
「我们需要注解,因为我们无法每次都找到不使用注解就能表达意图的方法,但使用注解并不值得庆贺」
取自: Clean Code (p.62)
算一下你花了几秒才理解这段 Code 的意义?
// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))
{
// Do Something
}
else
{
// Do Something
}
从上面的 Code 我们可观察到:
接着看看下面的 Code (笔者针对 Clean Code p.63 进行的补充,如有不足敬请指点)
if (employee.isEligibleForFullBenefits())
{
// Do Something
}
else
{
// Do Something
}
bool isEligibleForFullBenefits()
{
bool isApplyRetire = employee.flags & HOURLY_FLAG;
bool isEligibleForRetire = employee.age > RETIRE_AGE_LIMIT;
return isApplyRetire && isEligibleForRetire;
}
NOTE: 某一些程序语言 (例如 C#) 可能会习惯在每一个 Method 或 Variables 之上写些 Doc 型注解
/// <summary>
/// To calculate total salary.
/// </summary>
/// <param name="salary"></param>
/// <param name="bonus"></param>
public void GetEmployeeSalary( int salary, int bonus)
{
int totalSalary = salary + bonus;
return totalSalary;
}
这种情形建议还是遵照惯例会比较妥当,以利後续 API 文件的自动产生法律型注解
// utility.cc
// Debugging routines. Allows users to control whether to
// print DEBUG statements, based on a command line argument.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "utility.h"
但如果可能,这样的注解内容不应直接是契约或条款,建议让它去参考一个外部文件
对意图的解释 & 後果的告诫
currentThread->Finish(); // NOTE: if the procedure "main"
// returns, then the program "nachos"
// will exit (as any other normal program
// would). But there may be other
// threads on the ready list. We switch
// to those threads by saying that the
// "main" thread is finished, preventing
// it from returning.
return(0); // Not reached...
上述的注解特别提醒了 Thread 完成後需要注意的事项,尤其我们可以知道 return 是不会马上被触发到的
TODO (待办事项) 注解
大部分的 IDE 都提供 Task Tags 查找的机制来找出所有的 TODO 注解。建议定期地审视这些待办事项,并且删除已经不再需要的待办事项
衍生阅读: 特殊注解:TODO、FIXME、XXX
误导型的注解
绝对不要写下错误的注解!!!
被注解起来的程序码
这是很讨人厌的,别这样做!!!
日志型注解 & 出处和署名
现代版控工具都很发达,别再用注解写日志
多余的注解
别让读注解比读程序码还费时
其他
位置标志 (效果非常显着时才使用,否则只是凌乱物)
{
// code...
// Actions //////////////////////////
// code...
}
右大括号後面的注解
while (...)
{
// code...
} // end while
「程序的编排是很重要的。编排是一种沟通方式,而沟通是专业开发者的首要之务」
取自: Clean Code (p.86)
/* Eaxmple 1 */
(-b+Math.sqrt(determinant))/(2*a);
// vs.
(-b + Math.sqrt(determinant)) / (2*a);
/* Eaxmple 2 */
return b*b-4*a*c;
// vs.
return b*b - 4*a*c;
>>: Day3 AR其实在生活中很常见?他们又有那些好处哩(成为史莱姆猎人的萌新)
资料来源: 为什麽没有「防火墙」? 火灾袭「是方电讯」!某天然呆老板:不是有防火墙吗? 内湖机房失...
作者说明 forEach()、every()、some() 三者在跑回圈运作上的差异 forEach...
NNI搬到Colab上,环境类似本机。虽然,NNI很容易搬到Colab平台上,但由於Colab并不公...
显示声波图形 教学原文参考:显示声波图形 这篇文章会介绍,在 Scratch 3 里侦测麦克风的声音...
Command and Control 攻击者已经进入工控环境之後,从自己的服务器传送指令给受害主机...