[活動記實] 讀書會~Clean Code (無瑕的程式碼)@加爾第咖啡

** 所有相關活動的完整照片,可至-「2013.05.18_Clean Code 讀書會」Flickr 相片集瀏覽。 **

上上星期六 (5/18) HSDc. 所舉辦的「Clean Code (無瑕的程式碼) 讀書會」,在相當熱絡的研討與歡樂的氣氛下,圓滿落幕了。

「Clean Code」中譯本的技術編輯(Simon, 博碩文化)也特別蒞臨此次的活動,與會過程中不只用心地回應讀者許多問題外,還分享了在翻譯該書時的用字遣詞,以盡能表達出原文的意境,實在相當感謝他能為業界翻譯如此高品質的譯本。還有,他也為讀友們帶來一項福利,在博碩的粉絲團內按個「讚」,就有機會抽中「Clean Code」原版書籍,定價可是 NT$2,200,不便宜呢。

這次讀書會的導讀與主持不得已就由我個人來擔任。我把時間安排大致分為讀書內容的心得分享、問題提問、自由討論。

一開始先作個腦力激盪 (brain storm),這裡我用心智圖 (mindmap)先整理出關於「Clean Code」的 5W-What, Why, When, Which, Who。雖然看來僅是簡單的整理,但讀友們大都發言踴躍,在分享一些對「乾淨的程式碼」的看法與心得,以及一些問題討論,這樣也討論到中午 12:40 才休息,大家各自用完中餐後,下午 1:30 繼續研討。

Clean Code 心智圖

下午整個主題就完全以書本大綱內的「How-to」為重心了,一章一章地討論大綱內容。畢竟作者就已開宗明義內提及:「小事情上誠實,可不是一件小事。」;同時又提到:「神 (我以為是魔鬼?)就在細節內。」。所以,程式碼當然就要回歸到「How-to」細節內,這可是不能眼高手低的。

事實上,這本書大概到第 10 章就足夠了,後續的內容,有其他作者撰寫的、有作者早期的論文,也有從「Refactoring」一書節錄的重構型錄,許多內容其實翻過就可以了。(不過看來我最認真!? 關於第14章-「持續地精煉」,我可是逐行閱讀其程式碼,整整花了三個晚上還不容易了解內容,直至與 Ringle 討論過後,他認為該範例還是不夠「Clean」,仍需要繼續「精煉」。 >_<) 即使只研讀到第10章左右,但也不容易,直到下午約5:00結束時才勉強「翻完」,其實仍是有諸多細節尚未討論的。不過也算是盡心了,讀友們的發言夠是踴躍了,也相信有許多研討的內容對未來他們的工作,在長期上會有相當體會與助益的。 讀書會@吳興街加爾第咖啡


讀書會@吳興街加爾第咖啡

這次讀書會仍是在吳興街的「加爾第咖啡」舉辦的。因為這裡交通也算便利,地下1F可容納近30人的會議空間,還可以擺上投影機簡報,另外他們家的手工單品咖啡,可是相當甘醇美味的。

我們請店家準備了兩筒-咖啡與紅茶供無限暢飲。這咖啡可是店內服務生一壺壺煮出來單品曼巴,外面這樣一杯起碼要百元以上。下午讀友們喝完後還再請店內加煮一筒,但就喝不完啦,我看每位讀友平均有喝上三杯以上之多,過量啦。
讀書會@吳興街加爾第咖啡

同時也準備了一些小點心餅乾,就當作是下午茶點。
讀書會@吳興街加爾第咖啡

對了,我也請 Ringle 展示一下書本第10章內的範例程式碼。我是一直認為重構僅從程式碼解析,那是只有大師級的才可以輕而易舉做到,若是一般平凡如我輩者,最好能佐以「設計圖」的視覺化方式來解讀,相信就會輕鬆許多的。

對於要解讀他人的程式碼,最重要的可不是「類別圖 (class diagram)」,反而是凸顯物件互動的「循序圖 (sequence diagram)」。所以早在兩年餘前,HSDc. 就已開發出「sequnce generator」產品,可以掃描程式碼,並產出 UML 循序圖,可以參考原整理的共四篇文-程式碼與 UML 類別_循序圖 的關係探討-完結 (4)。這次剛好可以派上用場,就利用自家的工具產品展示如何解析該範例程式碼。
Clean Code 範例碼

UML 循序圖 for Clean Code 範例碼

書內已重構後的程式碼參考如下,可以比對上列循序圖的 method call 呼叫情形。

/**
 * This class Generates prime numbers up to a user specified
 * maximum.  The algorithm used is the Sieve of Eratosthenes.
 * Given an array of integers starting at 2:
 * Find the first uncrossed integer, and cross out all its
 * multiples.  Repeat until there are no more multiples
 * in the array.
 */
 
public class PrimeGenerator
{
  private static boolean[] crossedOut;
  private static int[] result;
  public static int[] generatePrimes(int maxValue)
  {
    if (maxValue < 2)
      return new int[0];
    else
    {
      uncrossIntegersUpTo(maxValue);
      crossOutMultiples();
      putUncrossedIntegersIntoResult();
      return result;
    }
  }
  private static void uncrossIntegersUpTo(int maxValue)
  {
    crossedOut = new boolean[maxValue + 1];
    for (int i = 2; i < crossedOut.length; i++)
      crossedOut[i] = false;
  }
  private static void crossOutMultiples()
  {
    int limit = determineIterationLimit();
    for (int i = 2; i <= limit; i++)
      if (notCrossed(i))
        crossOutMultiplesOf(i);
  }
  private static int determineIterationLimit()
  {
    // Every multiple in the array has a prime factor that
    // is less than or equal to the root of the array size,
    // so we don't have to cross out multiples of numbers
    // larger than that root.
    double iterationLimit = Math.sqrt(crossedOut.length);
    return (int) iterationLimit;
  }
  private static void crossOutMultiplesOf(int i)
  {
    for (int multiple = 2*i;
         multiple < crossedOut.length;
         multiple += i)
      crossedOut[multiple] = true;
  }
  private static boolean notCrossed(int i)
  {
    return crossedOut[i] == false;
  }
  private static void putUncrossedIntegersIntoResult()
  {
    result = new int[numberOfUncrossedIntegers()];
    for (int j = 0, i = 2; i < crossedOut.length; i++)
      if (notCrossed(i))
        result[j++] = i;
  }
  private static int numberOfUncrossedIntegers()
  {
    int count = 0;
    for (int i = 2; i < crossedOut.length; i++)
      if (notCrossed(i))
        count++;
    return count;
  }
 }

文章導覽

   

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *