Clean Code - Meaningful Name

曾经以为只要能够满足需求的代码就是好的代码,直到真正从事项目的开发。反复修改,总也找不到技巧。究竟什么是好的代码呢?如何才是简洁高效的表达,如何才能一次approve?我有问题,你知道答案吗?

这是Clean Code的阅读笔记,简单介绍clean code法则。

一句话总结什么是好的代码:

  1. 消除重复代码
  2. 提高代码的表达力
  3. 提早构建简单的抽象

如何确保有意义的命名

  1. 命名需要有含义:
    假设我们有这样一段代码:
#include <iostream>
#include <list>
#include <string>

int main() {
    std::list<std::string> myList = {"A", "B", "C", "D", "E", "F"};

    if (myList.size() >= 4) {
        auto it = myList.begin();
        std::advance(it, 3);  // 从第一个元素开始,向前移动 3 步 -> 第四个元素
        std::cout << "第四个元素是: " << *it << std::endl;
    } else {
        std::cout << "list 中元素不足 4 个" << std::endl;
    }

    return 0;
}

看起来是不是思路很清晰,从list中获取第四个参数。

但是如果放在项目中,我并不清楚myList是什么。

如果是一个扫雷游戏,那么可以选择gameBoard来命名,这样依据具体的项目来表达,会更加易读。

  1. 避免误导
    accountList 看起来是符合规则的,但是List在JAVA中是特殊的含义,可以考虑使用accountGroup,看起来更为明确。

像hp,aix等Unix的专有名称也不适用于直接拿来命名。

maxReplicationCheckerTestRunCount, maxReplicationCheckerRunCount,这些看起来几乎一样的名称,使得代码的可读性变得很差。

真正可怕的还是用小写字母 l 和大写字母 O 作为变量名,实在是难以区分。

  1. 做有意义的区分:
    a1, a2, … aN, ProductInfo and ProductData, 这样的区分就像a,an和the一样,毫无意义。想要区分名称,就要以读者能鉴别出的不同之处来区分。
  2. 使用读得出来的名称
    比如genymdhms,看起来不知道是何含义,改成generationTimestamp,一眼就能了解其含义。
  3. 使用可以搜索的名称
    单字母名称和数字常量有个问题,就是很难在一大篇文字中找出来。
  4. 避免使用编码
    Java 程序员不需要类型编码,也不必用 m_前缀来标明成员变量。

有时也会出现采用编码的特殊情形。比如,你在做一个创建形状用的抽象工厂(Abstract Factory)。该工厂是个接口,要用具体类来实现。你怎么来命名工厂和具体类呢?IShapeFactory 和 ShapeFactory 吗?不想让用户知道我给他们的是接口,就想让他们知道那是个 ShapeFactory。如果接口和实现必须选一个来编码的话,我宁肯选择实现。ShapeFactoryImp,甚至是丑陋的 CShapeFactory,都比对接口名称编码来得好。

  1. 避免思维映射
    传统上惯用单字母名称做循环计数器。
  2. 类名
    类名和对象名应该是名词或名词短语,如 Customer、WikiPage、Account 和 AddressParser。避免使用 Manager、Processor、Data 或 Info 这样的类名。类名不应当是动词。
  3. 方法名
    方法名应当是动词或动词短语,如 postPayment、deletePage 或 save。属性访问器、修改器和断言应该根据其值命名,并依 Javabean 标准[10]加上 get、set 和 is 前缀。
    重载构造器时,使用描述了参数的静态工厂方法名。
    例如:
Complex fulcrumPoint = Complex.FromRealNumber(23.0);

好于

Complex fulcrumPoint = new Complex(23.0);

可以考虑将相应的构造器设置为 private,强制使用这种命名手段。

  1. 每个概念对应一个词
    给每个抽象概念选一个词,并且一以贯之。例如,使用 fetch、 retrieve 和 get 来给在多个类中的同种方法命名。

  2. 别用双关语
    避免将同一单词用于不同目的。同一术语用于不同概念,基本上就是双关语了。
    比如,在多个类中都有 add 方法,该方法通过增加或连接两个现存值来获得新值。假设要写个新类,该类中有一个方法,把单个参数放到群集(collection)中。该把这个方法叫做 add 吗?这样做貌似和其他 add 方法保持了一致,但实际上语义却不同,应该用 insert 或 append 之类词来命名才对。把该方法命名为 add,就是双关语了。

  3. 使用解决方案领域的名称
    尽管用那些计算机科学(Computer Science,CS)术语、算法名、模式名、数学术语吧,例如JobQueue.

  4. 使用源自所涉问题领域的名称
    如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称吧。

  5. 添加有意义的语境
    很少有名称是能自我说明的——多数都不能。反之,你需要用有良好命名的类、函数或名称空间来放置名称,给读者提供语境。如果没这么做,给名称添加前缀就是最后一招了。

设想你有名为 firstName、lastName、street、houseNumber、city、state 和 zipcode 的变量。当它们搁一块儿的时候,很明确是构成了一个地址。不过,假使只是在某个方法中看见孤零零一个 state 变量呢?你会理所当然推断那是某个地址的一部分吗?可以添加前缀 addrFirstName、addrLastName、addrState 等,以此提供语境。至少,读者会明白这些变量是某个更大结构的一部分。当然,更好的方案是创建名为 Address 的类。这样,即便是编译器也会知道这些变量隶属某个更大的概念了。

  1. 不要添加没用的语境
    只要短名称足够清楚,就要比长名称好。别给名称添加不必要的语境。Address 是个好类名。如果需要与 MAC 地址、端口地址和 Web 地址相区别,我会考虑使用 PostalAddress、MAC 和 URI。这样的名称更为精确,而精确正是命名的要点。

  2. 总结
    取好名字最难的地方在于需要良好的描述技巧和共有文化背景。与其说这是一种技术、商业或管理问题,还不如说是一种教学问题。其结果是,这个领域内的许多人都没能学会做得很好。

Executing tasks: [:app:clean, :app:assembleDebug, :app:assembleDebugUnitTest, :app:assembleDebugAndroidTest] in project C:\Users\EDY\Desktop\项目文件\Android studio项目\DeviceDataUpload > Configure project :app AGPBI: {"kind":"warning","text":"The option setting 'android.overridePathCheck=true' is experimental.\nThe current default is 'false'.","sources":[{}]} > Task :app:clean UP-TO-DATE > Task :app:preBuild UP-TO-DATE > Task :app:preDebugBuild UP-TO-DATE > Task :app:mergeDebugNativeDebugMetadata NO-SOURCE > Task :app:checkKotlinGradlePluginConfigurationErrors > Task :app:generateDebugResValues > Task :app:dataBindingMergeDependencyArtifactsDebug > Task :app:generateDebugResources > Task :app:packageDebugResources > Task :app:parseDebugLocalResources > Task :app:mapDebugSourceSetPaths > Task :app:createDebugCompatibleScreenManifests > Task :app:extractDeepLinksDebug > Task :app:checkDebugAarMetadata > Task :app:processDebugMainManifest > Task :app:mergeDebugResources > Task :app:processDebugManifest > Task :app:dataBindingGenBaseClassesDebug > Task :app:javaPreCompileDebug > Task :app:mergeDebugShaders > Task :app:compileDebugShaders NO-SOURCE > Task :app:generateDebugAssets UP-TO-DATE > Task :app:mergeDebugAssets > Task :app:compressDebugAssets > Task :app:processDebugManifestForPackage > Task :app:checkDebugDuplicateClasses > Task :app:desugarDebugFileDependencies > Task :app:processDebugResources FAILED > Task :app:mergeDebugJniLibFolders > Task :app:mergeLibDexDebug > Task :app:mergeDebugNativeLibs NO-SOURCE > Task :app:stripDebugDebugSymbols NO-SOURCE > Task :app:validateSigningDebug > Task :app:writeDebugAppMetadata > Task :app:writeDebugSigningConfigVersions > Task :app:preDebugUnitTestBuild UP-TO-DATE > Task :app:preDebugAndroidTestBuild SKIPPED > Task :app:javaPreCompileDebugUnitTest > Task :app:dataBindingMergeDependencyArtifactsDebugAndroidTest > Task :app:generateDebugAndroidTestResValues > Task :app:generateDebugAndroidTestResources > Task :app:mergeDebugAndroidTestResources > Task :app:dataBindingGenBaseClassesDebugAndroidTest > Task :app:checkDebugAndroidTestAarMetadata > Task :app:mapDebugAndroidTestSourceSetPaths > Task :app:processDebugAndroidTestManifest > Task :app:javaPreCompileDebugAndroidTest > Task :app:mergeDebugAndroidTestShaders > Task :app:compileDebugAndroidTestShaders NO-SOURCE > Task :app:generateDebugAndroidTestAssets UP-TO-DATE > Task :app:mergeDebugAndroidTestAssets > Task :app:compressDebugAndroidTestAssets > Task :app:checkDebugAndroidTestDuplicateClasses > Task :app:desugarDebugAndroidTestFileDependencies > Task :app:mergeExtDexDebugAndroidTest > Task :app:mergeDebugAndroidTestJniLibFolders > Task :app:mergeDebugAndroidTestNativeLibs NO-SOURCE > Task :app:stripDebugAndroidTestDebugSymbols NO-SOURCE > Task :app:validateSigningDebugAndroidTest > Task :app:writeDebugAndroidTestSigningConfigVersions > Task :app:mergeLibDexDebugAndroidTest > Task :app:processDebugAndroidTestResources > Task :app:mergeExtDexDebug FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:processDebugResources'. > A failure occurred while executing com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask$TaskAction > Android resource linking failed com.example.devicedataupload.app-mergeDebugResources-32:/layout/activity_scan_qr_code.xml:42: error: resource id/frame (aka com.example.devicedataupload:id/frame) not found. error: failed linking file resources. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at https://help.gradle.org. BUILD FAILED in 24s 50 actionable tasks: 49 executed, 1 up-to-date 这是什么错误?和哪个文件有关,该如何修改!
01-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值