clean-code-dotnet part 1 (命名,变量)

clean-code-dotnet

Table of Contents

  1. 介绍
  2. 命名
  3. 变量

介绍

Humorous image of software quality estimation as a count of how many expletives you shout when reading code

这是来自 Robert C. Martin’s 所写的 Clean Code中文版》 本文适用于.NET 和 .NET Core的软件工程实践。它不是一个单纯的编码规范,而是让你创建一个可读写,可重用,可重构的.NET软件开发规范。

当然并非所有的规范都必须严格遵守,甚至有些规范都没有得到普遍认同。这些只是《Clean Code》的作者在多年的实践经验里总结出来的指导方针。

本文灵感来自 clean-code-javascriptclean-code-php

我也fork了clean-code-javascript

命名

命名是一个很难,很花时间的事情,但是花点时间取一个好名字还是非常值得的。它会在未来帮你(以及其他看你代码的人)在阅读代码上节约很多时间。命名应该要反映它要做什么,以及和上下文的关系。

个人观点
关于命名,用英文对于我们很大一部分开发者来说,会更困难一些,在一些场合要找到一个合适的英文单词做名字会比较困难。我的建议,要么好好学英文,要么,用好中文变量名(是中文变量名,不是拼音缩写,也不是拼音)。一些词不达意的命名还不如中文,当然前提是项目仅限内部交流的项目。

Bad:

int d;

Good:

int daySinceModification;

⬆ Back to top

避免无效信息命名

程序员必须避免使用无效信息命名,变量的名称应该以反映出我们想用它做什么。

Bad:

var dataFromDb = db.GetFromService().Tolist();

Good:

var listOfEmployee = _employeeService.GetEmployeeListFromDb().Tolist();

⬆ Back to top

使用可以读得出来的名字

如果我们不能读出变量、函数,会发生什么呢?我们会花很多时间在追查这些变量所包含的意思(有时会让我们像个傻瓜一样讨论它)。

PS
原文是发音,翻译为能读出来。demo的例子是变量名用来某些特定缩写,导致无法正确的读出来。我们很多的开发都会有一些这样不好的习惯,在一些场合使用单词缩写做前缀。

Bad:

public class Employee 
{
    public Datetime sWorkDate { get; set; } // 工作日期是要说明什么
    public Datetime modTime { get; set; } // 同样,这是啥意思
}

Good:

public class Employee 
{
    public Datetime StartWorkingDate { get; set; }
    public Datetime ModificationTime { get; set; }
}

⬆ Back to top

使用驼峰命名法(Camelcase)

变量和函数参数使用 驼峰式 进行命名。

Bad:

var employeephone;

public double CalculateSalary(int workingdays, int workinghours)
{
    // some logic
}

Good:

var employeePhone;

public double CalculateSalary(int workingDays, int workingHours)
{
    // some logic
}

⬆ Back to top

使用领域名称

读我们代码的也是程序猿,我们可以使用一些模式,算法等编程领域内的专有名词,来对变量和函数命名。这样我们就不用花很多时间来解释这些变量与函数的用途,进而节约阅读者的理解时间。

Good

public class SingleObject 
{
   //create an object of SingleObject
   private static SingleObject _instance = new SingleObject();

   //make the constructor private so that this class cannot be
   //instantiated
   private SingleObject() {}

   //Get the only object available
   public static SingleObject GetInstance() 
   {
      return _instance;
   }

   public string ShowMessage()
   {
      return "Hello World!";
   }
}

public static void main(String[] args) 
{
    // illegal construct
    // var object = new SingleObject();

    // Get the only object available
    var singletonObject = SingleObject.GetInstance();

    // show the message
    singletonObject.ShowMessage();
}

⬆ Back to top

变量

使用有意义的和可发音的变量名 :page_facing_up:

Bad:

var ymdstr = DateTime.UtcNow.ToString("MMMM dd, yyyy");

Good:

var currentDate = DateTime.UtcNow.ToString("MMMM dd, yyyy");

⬆ Back to top

对同一类型的变量使用同一个词汇 :page_facing_up:

Bad:

GetUserInfo();
GetUserData();
GetUserRecord();
GetUserProfile();

Good:

GetUser();

⬆ Back to top

使用可搜索(理解)的名词 (part 1) :page_facing_up:

我们读代码的时间比写代码的要多。因此写出一个好读好理解的代码非常重要。如果无法从变量里帮助我们了解程序的含义,会让我们很受伤。
所以,请取一个能理解的变量名吧。

Bad:

// What the heck is data for?
var data = new { Name = "John", Age = 42 };

var stream1 = new MemoryStream();
var ser1 = new DataContractJsonSerializer(typeof(object));
ser1.WriteObject(stream1, data);

stream1.Position = 0;
var sr1 = new StreamReader(stream1);
Console.Write("JSON form of Data object: ");
Console.WriteLine(sr1.ReadToEnd());

Good:

var person = new Person
{
    Name = "John",
    Age = 42
};

var stream2 = new MemoryStream();
var ser2 = new DataContractJsonSerializer(typeof(Person));
ser2.WriteObject(stream2, data);

stream2.Position = 0;
var sr2 = new StreamReader(stream2);
Console.Write("JSON form of Data object: ");
Console.WriteLine(sr2.ReadToEnd());

使用可搜索(理解)的名词 (part 2) :page_facing_up:

Bad:

var data = new { Name = "John", Age = 42, PersonAccess = 4};

// What the heck is 4 for?
if (data.PersonAccess == 4)
{
    // do edit ...
}

Good:

public enum PersonAccess : int
{
    ACCESS_READ = 1,
    ACCESS_CREATE = 2,
    ACCESS_UPDATE = 4,
    ACCESS_DELETE = 8
}

var person = new Person
{
    Name = "John",
    Age = 42,
    PersonAccess= PersonAccess.ACCESS_CREATE
};

if (person.PersonAccess == PersonAccess.ACCESS_UPDATE)
{
    // do edit ...
}

⬆ Back to top

使用解释型的变量 :page_facing_up:

Bad:

const string Address = "One Infinite Loop, Cupertino 95014";
var cityZipCodeRegex = @"/^[^,\]+[,\\s]+(.+?)\s*(\d{5})?$/";
var matches = Regex.Matches(Address, cityZipCodeRegex);
if (matches[0].Success == true && matches[1].Success == true)
{
    SaveCityZipCode(matches[0].Value, matches[1].Value);
}

Good:

通过解释型的变量名,来帮助理解正则表达式。

const string Address = "One Infinite Loop, Cupertino 95014";
var cityZipCodeWithGroupRegex = @"/^[^,\]+[,\\s]+(?<city>.+?)\s*(?<zipCode>\d{5})?$/";
var matchesWithGroup = Regex.Match(Address, cityZipCodeWithGroupRegex);
var cityGroup = matchesWithGroup.Groups["city"];
var zipCodeGroup = matchesWithGroup.Groups["zipCode"];
if(cityGroup.Success == true && zipCodeGroup.Success == true)
{
    SaveCityZipCode(cityGroup.Value, zipCodeGroup.Value);
}

⬆ back to top

避免深层嵌套并及早返回 :page_facing_up:

太多的 if else 嵌套会让你的代码难追踪,显式好于隐式。

Bad:

public bool IsShopOpen(string day)
{
    if (string.IsNullOrEmpty(day))
    {
        day = day.ToLower();
        if (day == "friday")
        {
            return true;
        }
        else if (day == "saturday")
        {
            return true;
        }
        else if (day == "sunday")
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }

}

Good:

public bool IsShopOpen(string day)
{
    if (string.IsNullOrEmpty(day))
    {
        return false;
    }

    var openingDays = new string[] {
        "friday", "saturday", "sunday"
    };

    return openingDays.Any(d => d == day.ToLower());
}

Bad:

public long Fibonacci(int n)
{
    if (n < 50)
    {
        if (n != 0)
        {
            if (n != 1)
            {
                return Fibonacci(n - 1) + Fibonacci(n - 2);
            }
            else
            {
                return 1;
            }
        }
        else
        {
            return 0;
        }
    }
    else
    {
        throw new System.Exception("Not supported");
    }
}

Good:

public long Fibonacci(int n)
{
    if (n == 0)
    {
        return 0;
    }

    if (n == 1)
    {
        return 1;
    }

    if (n > 50)
    {
        throw new System.Exception("Not supported");
    }

    return Fibonacci(n - 1) + Fibonacci(n - 2);
}

⬆ back to top

避免内心映射 :page_facing_up:

不要强迫阅读你代码的人自己去转换出变量的真正含义。
显式好于隐式。

Bad:

var l = new[] { "Austin", "New York", "San Francisco" };

for (var i = 0; i < l.Count(); i++)
{
    var li = l[i];
    DoStuff();
    DoSomeOtherStuff();

    // ...
    // ...
    // ...
    // Wait, what is `li` for again?
    Dispatch(li);
}

Good:

var locations = new[] { "Austin", "New York", "San Francisco" };

foreach (var location in locations)
{
    DoStuff();
    DoSomeOtherStuff();

    // ...
    // ...
    // ...
    Dispatch(location);
}

⬆ back to top

不要添加不必要的上下文 :page_facing_up:

如果你的类/对象的名称告诉你一些东西,就不要出现在变量名里了。

Bad:

public class Car
{
    public string CarMake { get; set; }
    public string CarModel { get; set; }
    public string CarColor { get; set; }

    //...
}

Good:

public class Car
{
    public string Make { get; set; }
    public string Model { get; set; }
    public string Color { get; set; }

    //...
}

⬆ back to top

使用默认参数来替代一些参数验证判断 :page_facing_up:

Not good:

这个版本不好,因为 breweryName 可能需要为 NULL.

public void CreateMicrobrewery(string name = null)
{
    var breweryName = !string.IsNullOrEmpty(name) ? name : "Hipster Brew Co.";
    // ...
}

Good:

这个版本比上面的容易理解,因为他能更好的说明变量的默认值。也允许传入空值

public void CreateMicrobrewery(string breweryName = "Hipster Brew Co.")
{
    // ...
}

避免魔法字符串

魔法字符串是指在应用程序里影响程序运行的特定字符串值。通常这些字符串会在系统里不停的复制,并且无法通过重构工具进行自动更新,所以当对某些字符串进行修改,但又没有全部更改时,日常BUG就这样出现了。

Bad

if(userRole == "Admin")
{
    // logic in here
}

Good

string ADMIN_ROLE = "Admin"
if(userRole == ADMIN_ROLE)
{
    // logic in here
}

我们只需要修改这一个地方,其它的都会变化。

⬆ back to top

«   2023年9月   »
123
45678910
11121314151617
18192021222324
252627282930
网站分类
文章归档

Powered By Z-BlogPHP 1.6.5 Valyria

Copyright csharptools.cn Rights Reserved. 桂ICP备17007292号-1