zoukankan      html  css  js  c++  java
  • 《构建之法》 读书笔记

    《构建之法》

    读书笔记

    娄雨禛 PB16060356

     

    第一部分 关于结对编程的体悟与实践

      在结对编程这一部分我曾讲过很多的注意点,比如代码变量命名风格、缩进风格、注释风格,前后语句次序风格,等等。然而这里还有一些新的东西。代码风格这个老掉牙的话题咱们先搁置不谈,而说说在结对编程中同样重要的其他注意点。

     

      代码复审

      代码复审是一门学问。良好而有序的复审将帮助我们快速排查问题和增进代码可读性,而低劣的复审则纯粹在浪费时间。这里拿我在个人项目中的代码举一个例子。

     

      1 void anothermain(char *fileString)
      2 {
      3     char *offset = fileString;
      4     char move;
      5     char temp;
      6 
      7     int count;
      8     do
      9     {
     10         if(temp = *offset)
     11         {
     12             if(temp >= 32 && temp <= 126)
     13             {
     14                 Characters++;
     15                 if(temp >= 65 && temp <= 122)
     16                 {
     17                     if(temp >= 91 && temp <= 96)
     18                     {
     19                         offset++;
     20                         continue;
     21                     }
     22                     else
     23                     {
     24                         offset++;
     25                         word[0] = temp;
     26                     }
     27                 }
     28                 else if(temp >= 49 && temp <= 57)
     29                 {
     30                     offset++;
     31                     while(*offset >= 49 && *offset <= 57)
     32                     {
     33                         Characters++;
     34                         offset++;
     35                     }
     36                     while((*offset >= 49 && *offset <= 57) || (*offset >= 65 && *offset <= 90) || (*offset >= 97 && *offset <= 122))
     37                     {
     38                         Characters++;
     39                         offset++;
     40                     }
     41                     continue;
     42                 }
     43                 else
     44                 {
     45                     offset++;
     46                     continue;
     47                 }
     48             }
     49             else
     50             {
     51                 if(*offset == 10)
     52                     enterNum++;
     53                 offset++;
     54                 continue;
     55             }
     56         }
     57         else
     58             break;
     59         if(temp = *offset)
     60         {
     61             if(temp >= 32 && temp <= 126)
     62             {
     63                 Characters++;
     64                 if(temp >= 65 && temp <= 122)
     65                 {
     66                     if(temp >= 91 && temp <= 96)
     67                     {
     68                         offset++;
     69                         continue;
     70                     }
     71                     else
     72                     {
     73                         offset++;
     74                         word[1] = temp;
     75                     }
     76                 }
     77                 else if(temp >= 49 && temp <= 57)
     78                 {
     79                     offset++;
     80                     while(*offset >= 49 && *offset <= 57)
     81                     {
     82                         Characters++;
     83                         offset++;
     84                     }
     85                     while((*offset >= 49 && *offset <= 57) || (*offset >= 65 && *offset <= 90) || (*offset >= 97 && *offset <= 122))
     86                     {
     87                         Characters++;
     88                         offset++;
     89                     }
     90                     continue;
     91                 }
     92                 else
     93                 {
     94 
     95                     offset++;
     96                     continue;
     97                 }
     98             }
     99             else
    100             {
    101                 if(*offset == 10)
    102                     enterNum++;
    103                 offset++;
    104                 continue;
    105             }
    106         }
    107         else
    108             break;
    109         if(temp = *offset)
    110         {
    111             if(temp >= 32 && temp <= 126)
    112             {
    113                 Characters++;
    114                 if(temp >= 65 && temp <= 122)
    115                 {
    116                     if(temp >= 91 && temp <= 96)
    117                     {
    118                         offset++;
    119                         continue;
    120                     }
    121                     else
    122                     {
    123                         offset++;
    124                         word[2] = temp;
    125                     }
    126                 }
    127                 else if(temp >= 49 && temp <= 57)
    128                 {
    129                     offset++;
    130                     while(*offset >= 49 && *offset <= 57)
    131                     {
    132                         Characters++;
    133                         offset++;
    134                     }
    135                     while((*offset >= 49 && *offset <= 57) || (*offset >= 65 && *offset <= 90) || (*offset >= 97 && *offset <= 122))
    136                     {
    137                         Characters++;
    138                         offset++;
    139                     }
    140                     continue;
    141                 }
    142                 else
    143                 {
    144                     offset++;
    145                     continue;
    146                 }
    147             }
    148             else
    149             {
    150                 if(*offset == 10)
    151                     enterNum++;
    152                 offset++;
    153                 continue;
    154             }
    155         }
    156         else
    157             break;
    158 
    159         if(temp = *offset)
    160         {
    161             if(temp >= 32 && temp <= 126)
    162             {
    163                 Characters++;
    164                 if(temp >= 65 && temp <= 122)
    165                 {
    166                     if(temp >= 91 && temp <= 96)
    167                     {
    168                         offset++;
    169                         continue;
    170                     }
    171                     else
    172                     {
    173                         offset++;
    174                         word[3] = temp;
    175                         for(count = 4; isLetterOrNum(*offset); offset++, count++)
    176                         {
    177                             Characters++;
    178                             word[count] = *offset;
    179                         }
    180                         word[count] = '';
    181                         NumOfWords++;
    182                         SolveTheWord(word);
    183                     }
    184                 }
    185                 else if(temp >= 49 && temp <= 57)
    186                 {
    187                     offset++;
    188                     while(*offset >= 49 && *offset <= 57)
    189                     {
    190                         Characters++;
    191                         offset++;
    192                     }
    193                     while((*offset >= 49 && *offset <= 57) || (*offset >= 65 && *offset <= 90) || (*offset >= 97 && *offset <= 122))
    194                     {
    195                         Characters++;
    196                         offset++;
    197                     }
    198                     continue;
    199                 }
    200 
    201                 else
    202                 {
    203                     offset++;
    204                     continue;
    205                 }
    206             }
    207             else
    208             {
    209                 if(*offset == 10)
    210                     enterNum++;
    211                 offset++;
    212                 continue;
    213             }
    214         }
    215         else
    216             break;
    217 
    218 
    219     }
    220     while(*offset != '');
    221 }

     

      这是我在进行匆忙的数据结构转型时书写的非常潦草的代码。虽然潦草,但还是包含了我的很多想法,比如,进肯能利用“流式操作”减少机器的循环流程,提高代码效率,尽管这样会使代码变得非常难读。很快,我就意识到了,这样的操作虽然节省了机器执行的时间,却大大浪费了我自己的时间。这段代码的可读性非常的差,以至于我自己常常被绕晕。其中杂乱的命名方式就不多说了,简直不忍卒读。由于是一次个人作业,又到了马上要提交的截止日期,我只关心这段程序的执行结果是否正常(作用是判断是否为一个单词并进行储存),因此在最后输出结果正确之下,我就没有再对它进行优化和修改。

      而如果这换成一次结对编程,将会怎样呢?

      是的,代码复审就登场了。那么下面,我就结合这个例子,简要说说应该怎样利用复审,改进代码。

     

      Step1:“自己改+你说我看”:不符合共同协定的编码风格的地方,一律修改

      我们需要在一开始就商定好代码风格,比如哪些地方需要换行,变量的命名规则等等。

      然后,先过自己这一关——自己对代码进行修改。比如在上面的例子中,函数名为anothermain,这是什么鬼意思?这种根本不知其所以然的命名,必须根除。还有像enternum这样的变量,也会让人摸不着头脑,应该改为characterNum这种规范的命名。

      在自己认为没有大毛病之后,还需要对方对自己进行挑错。在这里,挑错要注意一个原则:不要在鸡蛋里挑骨头,要本着找出有意义的错误的原则,认真查错。比如,“这样的函数命名会不会和以后的命名冲突,从而引起歧义?”

      Step2:探讨潜在的逻辑问题,预防“逻辑灾害”的发生

      上面这段代码的逻辑完全是给机器看的,对于人类阅读者来说,几乎看不下去。这时候,虽然程序在执行的时候结果没有问题,代码还是得改。把从头执行到尾的“流式操作”改为稍微慢一些却容易阅读地多的代码,我们可以增加一些执行很小功能的函数,然后反复调用它们。这样,将得到容易阅读得多的代码。

      Step3:修改完后也不松懈,继续进行经验总结

      总结这个步骤,是让我们“事半功倍”的不二捷径。它不容忽视

     

      在修改之后,代码变成了下面这样。

     1 void WordCheck(FILE *fp)
     2 {
     3         bool stop = false;
     4         bool isEmpty = false;
     5         char ch;  // ch gets the character one by one
     6         short check = 0;  // to check if the first four characters are letters
     7         short i = 0;
     8  
     9         ch = fgetc(fp);
    10         if(ch == EOF)
    11                  isEmpty = true;
    12  
    13         for(; !stop; ch = fgetc(fp))  // if it is not the end of the text
    14         {
    15                  if(ch >= 32 && ch <= 126)
    16                          characterNum++;
    17                  if(ch == '
    ')
    18                          lineNum++;
    19  
    20                  if(check < 4)  // to check the first four characters
    21                  {
    22                          if(ch == EOF)
    23                          {
    24                                   stop = true;
    25                                   if(isEmpty == false)
    26                                           lineNum++;
    27                          }
    28  
    29                          else if(IsLetter(ch) == true)
    30                          {
    31                                   ++check;
    32                                   tempWord[i] = ch;
    33                                   ++i;  // search for the next
    34                          }
    35                          else
    36                          {
    37                                   i = 0;
    38                                   check = 0;
    39                                   ClearTemp();
    40                          }
    41                  }
    42                  else  // first four characters are all letters, ready to store
    43                  {
    44                          if(IsSeparator(ch) || ch == EOF)  // have met a separator, store the word
    45                          {
    46                                   i = 0;  // roll back to the beginning in the next search
    47                                   check = 0;  // roll back to the beginning in the next search
    48  
    49                                   wordNum++;  // have found another word
    50                                   StoreWord();  // store the word
    51                                   ClearTemp();  // prepare for the next search
    52  
    53                                   if(ch == EOF)
    54                                   {
    55                                           stop = true;
    56                                           if(isEmpty == false)
    57                                                   lineNum++;
    58                                   }
    59                          }
    60  
    61                          else  // have not met a separator, keep searching
    62                          {
    63                                   tempWord[i] = ch;
    64                                   ++i;  // search for the next
    65                          }
    66                  }
    67         }
    68 }

     

      根据运行结果显示,修改后的代码运行时间是原来的两倍,但我们却获得了清爽得多的函数。这应该是一个好的结果,至少在对速度的要求不高的情况下。

      然而,如果我们进行过程序优化,就会发现,这是一个很令人诧异的结果——代码的运行时间变成了原来的两倍!这究竟是怎么回事呢?

      原来,在新的函数中,我采取了反复调用子函数的措施来精简代码。而在我的子函数中,我为了继续精简代码,又套用的新的子函数,这里进行了两次的套用。而在判断是否为一个单词并进行储存的时候,这种层层调用的次数是超乎想象的。正是这里头的反复嵌套,大大拖慢了程序的运行速度。

      接下来是进行修改,在不损失代码简洁性的前提下进行代码优化,其中主要是性能优化。我首先要做的是把两层的函数嵌套改为一层

      注意,在这里我并没有把子函数放上来,是出于阅读的简洁性和直观性——直接把我的实践结论告诉大家,而不是用代码和大家继续兜圈子。

      通过将两层的函数嵌套改为一层,我的子函数从原来的16行变成了42行,可以说复杂了不少,但接下来我们看一下运行效率。

      代码的运行时间大约是最初运行时间的 1.4 倍

      这个结果比第一次优化的结果好了不少,但没有达到本次代码优化的最终目的——在不损失性能的前提下进行感官上阅读体验的提升。当然,我也已经知晓了代码变慢的原因——函数嵌套和函数调用花去了太多无用的时间,接下来的优化步骤也明晰了。

  • 相关阅读:
    hdoj--2098--分拆素数和(枚举)
    hdoj--3594--Cactus(tarjan)
    hdoj--1251--统计难题(字典树)
    hdoj--2534--Score(gcd)
    nyoj--1185--最大最小值(线段树)
    hdoj--1166--敌兵布阵(线段树)
    hdoj--1754--I Hate It(线段树)
    poj--2234--Matches Game(尼姆博弈)
    lightoj--1005--Rooks(组合数)
    SPOJ
  • 原文地址:https://www.cnblogs.com/RainLou/p/9008681.html
Copyright © 2011-2022 走看看