[工作經驗] 程式讀書會其實是學新東西的好機會

各式各樣的程式讀書會在公司已經辦了很久了,每過一段時間我們就會找一本有人有興趣的書,大家每週找一小時開會報告,大家輪流報告書的一個章節。

最近報的書大概就是 Threading Building Blocks, Approximation Algorithm 和 Design Patterns。有些是有人工作上需要用到,剛好大家一起報一起學新東西,也有一些是為了像是我們剛進公司的新手複習的。

跳脫不了常規的簡報格式

每一團讀書會的人都不太一樣,早就讀過相關類型的人其實就不會來 meeting,有老鳥和新手一起的,也有只有對這主題有興趣的人來參加,或是只有三四人的讀書會也是有。

可是參加了一陣子後突然發現讀書會變得非常"規格化",這什麼意思呢? 因為大家因為還要忙於平常的工作,常常導致最後一週突然想起下週換他報告,只好臨時準備一下。

這時候不知道要怎麼做簡報怎麼辦? 簡單啦,我看一下上次的人怎麼報的就好了。

於是就把上一個人的簡報或好幾年前有報過相關的簡報抄來改一下,結果大家的簡報都長得很像這樣:


而且不只一頁,幾乎是每一頁都長這樣。但這也怪不了大家,因為這本來就不是我們的主要工作,況且時間這麼少,能有什麼變化?

沒時間準備讀書會怎麼辦?

我們有沒有辦法同時做到以下的兩件事:

  • 讓大家快速了解某章節的內容
  • 自己又學會新東西

這是我在突然發現我要報讀書會只剩三天的準備時間時思考的事情。

我心中想: Oh no 完蛋了,只剩三天我還不如就直接把前幾年的人做的投影片拿來朗誦一遍就好了吧?

但喜歡跳脫框架的我又覺得: 不行啊,只會抄前人的,可以學到什麼?

但當我打開前人做的投影片的那瞬間,我意識到我只能跳脫框架了,因為我發現幾年前做同一個主題的人竟然只是把書中的內容截圖下來放進投影片。沒錯真的每一頁都只有截圖不誇張。

這也怪我前幾次都用了很創新的方式來呈現讀書會:有次我用 Jupyter Notebook + Plotly Express 來做 interactive 的教學、又有一次我真的用 Qt 做出一個能做 syntax highlighting 的小程式。這讓我真的沒辦法抄一抄就好。

於是我就靈機一動突然想到,那我給我自己辦一場 hackathon 如何?

React JS 黑客松

我要報的 Head First Design Patterns 裡面用 Java 在講解 design patterns,但其實目標是增進我們 C++ 的 design patterns 實力。

我快速用半天看完整個我要報告的 "Proxy pattern" 的章節後,發現雖然前面的概念我可以放到投影片裡,但後面的範例 code 實在對我來說沒什麼感覺,如果我要把這些 code 貼到投影片那真又陷入了常規的簡報格式,因為很多人也都是這樣做。

不過書中另外一個有 screenshot 的範例是一個 Java 小程式點選單之後,會先出現讀取的文字,再顯示 CD cover 的圖片。剛好讓我想起 Facebook 或 Dcard 都有類似的讀取畫面:


我是不是也可以用網頁來重現他 Java 小程式的範例呢? 就是這個念頭讓我開始了我自己的黑客松。

剛好我從來沒用過 React library 但又一直想學,就趁這個機會學一下如何?

一人黑客松第一天

第一天當然是先搞懂 React 裡面的基礎原理,就去官網把 getting started 裡面的 documents 稍微看一看。

他的 "Learn React" 那邊其實有分 learn by doing 或 learn concepts step by step。我是喜歡邊學邊試的人,但我點進去 learn by doing 稍微看一下發現範例太複雜,怕花太多時間卡關所以就反而選了 learn concepts step by step 來看。

好險 learn concepts step by step 那邊其實每個 code 範例後面都有附 "Try it on CodePen",我當然都幾乎每個點開來,把一些我覺得好奇的東西改一下看看會發生什麼事,就這樣邊 try 邊學基礎。

一人黑客松第二天

我想做出 proxy pattern 的 demo,我簡單定個 functional spec:

  1. 使用者會先選取某個 album
  2. 我會去 Wikipedia 抓資料,抓資料的同時顯示讀取中的畫面
  3. 讀取完後呈現 album 的照片和 Wikipedia 資訊的第一行

所以我開始研究我要怎麼呈現這個東西,我勢必要有一個可以跑程式的地方吧。

最理想應該是 Visual Studio Code,但環境設置我怕我真的來不及了,所以就趕快 Google 一下 "Online React Playground" 希望有類似 CodePen 或 JSFiddle 那樣已經架好的環境可以跑 React,結果還真的有,一下就找到 CodeSandbox

當然二話不多說趕快來寫 code。一開始我就先能把書中的 demo 可以重現就好,先不管 proxy pattern,我就有預感一定程式碼會亂成一團,畢竟我要做一個 Component 同時負責兩件事,一個是讀取的畫面:


另一個就是最終呈現出來的樣子:


最終的 Component 在 render 的時候的 code 真的就看起來滿亂的:


  render() {
    if (this.state.error) return `Error: ${this.state.error}`;
    if (this.state.isInitial) return "";

    if (this.state.isLoading) {
      return (
        <Card style={{ width: "18rem" }}>
          <Row>
            <ContentLoader viewBox="0 0 286 286" speed="0.5">
              <rect x="0" y="0" rx="0" ry="0" width="286" height="286" />
            </ContentLoader>
          </Row>
          <Card.Body>
            <Card.Title>
              <ContentLoader viewBox="0 0 286 24" speed="0.5">
                <rect x="0" y="0" rx="3" ry="3" width="286" height="20" />
              </ContentLoader>
            </Card.Title>
            <Card.Text>
              <ContentLoader viewBox="0 0 286 80" speed="0.5">
                <rect x="0" y="15" rx="3" ry="3" width="280" height="8" />
                <rect x="0" y="40" rx="3" ry="3" width="280" height="8" />
                <rect x="0" y="65" rx="3" ry="3" width="200" height="8" />
              </ContentLoader>
            </Card.Text>
          </Card.Body>
        </Card>
      );
    } else {
      return (
        <Card style={{ width: "18rem" }}>
          <Card.Img
            variant="top"
            src={this.albumToImageUrl[this.props.albumName]}
            className="img-thumbnail"
          />
          <Card.Body>
            <Card.Title>{this.state.wikiTitle}</Card.Title>
            <Card.Text>{this.state.wikiFirstSentence}</Card.Text>
          </Card.Body>
        </Card>
      );
    }
  }

接著再從已經做好的 sandbox clone 一個出去開始 refactor 成 proxy pattern 該有的樣子,這步驟就輕鬆很多了,因為只要是 class 的概念不管是 C++ 還是 JavaScript 都一樣可以套用 design patterns。

改完之後讀取的 Component 就變成這樣:


class CDCoverDisplayLoading extends CDCoverDipsplay {
  renderImage() {
    return (
      <ContentLoader viewBox="0 0 286 286" speed="0.5">
        <rect x="0" y="0" rx="0" ry="0" width="286" height="286" />
      </ContentLoader>
    );
  }

  renderTitle() {
    return (
      <ContentLoader viewBox="0 0 286 24" speed="0.5">
        <rect x="0" y="0" rx="3" ry="3" width="286" height="20" />
      </ContentLoader>
    );
  }

  renderText() {
    return (
      <ContentLoader viewBox="0 0 286 80" speed="0.5">
        <rect x="0" y="15" rx="3" ry="3" width="280" height="8" />
        <rect x="0" y="40" rx="3" ry="3" width="280" height="8" />
        <rect x="0" y="65" rx="3" ry="3" width="200" height="8" />
      </ContentLoader>
    );
  }
}

而最終顯示資訊的 Component 會長這樣:


class CDCoverDisplaySubject extends CDCoverDipsplay {
  constructor(props) {
    super(props);

    this.albumToImageUrl = ...;
  }

  getAlbumImageUrl(album) {
    return this.albumToImageUrl[album];
  }

  renderImage() {
    return (
      <Card.Img
        variant="top"
        src={this.getAlbumImageUrl(this.props.albumName)}
        className="img-thumbnail"
      />
    );
  }

  renderTitle() {
    return this.props.title;
  }

  renderText() {
    return this.props.firstSentence;
  }
}

而用 fetch 去和 Wikipedia 要資料的 API 就被抽到 Proxy 本身去,整個程式結構真的好像變乾淨許多,但相對的複雜性也提高。

一人黑客松第三天

最後一天衝刺! 因為下午就要報告了,所以一人黑客松當然要結束啦! 還不趕快做投影片。所以我就花了上午的時間快速弄出投影片,上半部介紹 proxy patterns 基礎概念,投影片頁數就不多。主軸就放在下半部分我拋出了 React JS 這樣的 demo。

但 demo 也不是就只是把網頁秀出來晃一下,或是細讀裡面的程式碼,畢竟同事們幾乎都是寫 C++/Python 居多的,我們工作其實幾乎不會碰到 JavaScript。

所以我還是用投影片靜態地描述我想做的 demo 的架構、把東西混一起會遇到什麼問題,乖乖地把 architecture 用 diagram 秀出來。再來描述要從哪邊下手,用完 proxy pattern 後主要和舊的 architecture 差異在哪,也是同樣用 diagram 秀出來,特別是要把差異的地方用顏色標記起來。


真正的 demo 我也是只用一頁給大家看一下 gif 動畫:


最後同事也有問 diagram 的一些問題,所以我覺得至少我有成功獲得一些關注,否則通常就是報告完之後沒問題就解散了。

最終的成品有興趣的話也可以看一下我放在 CodeSandbox 上的 projects:

這次黑客松學到

原來我真的有辦法能在短短幾天內學會新東西,我一開始以為 React 很難,甚至可能要開另外一個讀書會才能學會。但事實證明時間壓力加上充足睡眠 (這次黑客松可以睡覺 XD) 是可以蹦出新花樣出來。

另外我還學到幾個技術上的小細節:

  • 從 CodeSandbox 發 API request 給 Wikipedia 的時候如果不加上 "&origin=*" 會遇到 CORS 問題 (也是查 Google 找到 StackOverflow 有人問才知道解答的)
  • 網路實在太快了,為了 demo 讓讀取畫面慢一點我只好故意 sleep 3 秒鐘才比較好 demo

但我覺得最重要的就是有勇氣去嘗試新東西,學東西永遠不嫌晚,只怕永遠躲在前人的框架下。

也感謝同事聽完我跳脫框架的讀書會,他們其實也等同是用三十分鐘的縮時錄影看我跑完我三天亂搞出來的一人黑客松。

留言

  1. 好文,Head First Design Patterns很讚👍
    但參加讀書會都不揪我QQ

    回覆刪除
    回覆
    1. 謝啦XD 我們大部分讀書會還是以自己 team 的人為主,因為相關的參考 slides 檔案也都在我們的 SharePoint 上。我只有參加過一個 ML 讀書會是跨部門的,可是沒多久疫情來後來就沒了,拍拍以後有跨部門的讀書會我再找你

      刪除

發佈留言

此網誌的熱門文章

[試算表] 追蹤台股 Google Spreadsheet (未實現損益/已實現損益)

[Side Project] 互動式教學神經網路反向傳播 Interactive Computational Graph

[插件] 在 Chrome 網頁做區分大小寫的搜尋