Beact

不少認識我的人應該知道,這學期因為跑到電機系去修了一門跟網路開發有關的專題使得我花了一堆時間在寫 Code。而 Beact 是我在專題中和兩位學長(電機系的 Vibert 和外文系的 Joey)花了快兩週做的 Final Project,也是至今第一次參與總行數過萬的中型 Project。這篇會稍微介紹這個 Project 的一些功能使用方式,也會談談整個開發過程中遇到的難點和心得。

  • Github:Link
  • Demo:Link
  • Vibert 學長的心得:Link
  • Joey 學長的心得:Link

宣傳影片

按鍵功能

  • 點選格子設定鼓機各拍的內容。
  • 空白鍵開始、暫停。
  • 上下鍵改變播放速度。
  • 左右鍵改變內建音源。
  • 數字鍵 1 ~ 8 選擇內建鼓機節奏。
  • 字母鍵觸發不同的音效與動畫。
  • shift+上下鍵改變鍵盤動畫。(新功能!)
  • shift+上下鍵改變鼓機動畫。(新功能!)- 點選右上角火影忍者標誌啟動火影系列鍵盤動畫。(新功能!)

側欄功能

  • Start / Stop:播放、暫停鼓機內容。
  • Pattern:自創鼓機節奏譜,支援新增、更新、播放、刪除等功能。
  • Chain:將不同的鼓機節奏譜串連起來,支援新增、更新、播放、刪除等功能。
  • Recorder:將錄音期間的鼓機與鍵盤的聲音與動畫全部錄起來,支援新增、播放、刪除等功能。

詳細使用方式請見 README。

先大概講一下我自己在開發過程中所遇到的難點。

我最一開始的工作是把基本的 server 和 database 部分架起來,連上 Vibert 和 Joey 的前端鼓機原型。由於 Beact 的重點在前端工程,且本身是單頁面的程式,所以在後端架設的部分基本上沒什麼遇到障礙。後期的開發會動到後端也通常只有在因應需要存取的資料內容情況下去調 API routing 和 Mongo Schema 的內容。

這邊唯一遇到的問題是在開發的效率。因為我這學期使用 Webpack 時做的東西都偏小,會在開發過程中就直接把前端 build 到 public 然後連上 server 測試。但 Vibert 在一開始的環境架構上用了 webpack-dev-server,理論上來說比較好的方式是用它來做 bundle,並想辦法讓 bundle 出來的東西連上自己的 server。這樣改 code 的時候 webpack-dev-server 會直接將改的內容更新到 bundle 裡面,在比較大型的專案裡頭速度會比每次都要重新 build 來得快上許多。

可惜的是因為一開始 Vibert 和 Joey 主要都在弄動畫和介面,前端還不太需要開 server,使得這個問題發現的比較晚。再加上我對 webpack-dev-server 不太熟,當下因時間因素也沒去重新調整整個配置。

後來開始轉過來幫忙做前端才是個人覺得這次的專案比較有挑戰性,也學到最多東西的地方。前端的部分我負責做的東西主要有兩個,一個是在 DrumMachine.js 裡用 React 給鼓機寫功能(Pattern、Chain、Recorder),另一個是寫 Audio.js 把聲音的 library 和 React 端串接起來。

Audio.js 裡面的核心架構是 Sequencer 和 Keyboard 這兩個 class,分別管理鼓機和鍵盤的音效。由於 Vibert 一開始已經研究過 Tone.js 並寫了一個簡單版本的 Sequencer 在裡面,我寫 Sequencer 的時候就直接研究他寫的邏輯,然後因應 React 端的新功能去新增、調整裡面的函數和 constructor。開始做 Keyboard 的時候才真正去比較仔細的看 Tone.js 的 document。

這裡碰到的問題大都在把 React 端的 state 傳到 sequencer 裡,出來的結果不如預期。主因在於自己對 JS Object 的一個觀念錯誤,使得我不小心把同一個 state property 重複性的 push 到 array 裡面,讓預期的錄音效果變成循環播放同一個 Pattern。其餘的難點就是鼓機和鍵盤的聲音同步、外援套件的選取等,但相較於觀念的疏失這類難點通常多花些時間就找到解決方法了。

另一個比較大的問題是隨著在 React 寫愈來愈多的功能,因為這些功能多多少少都會影響到某些特定的 state 和函數,所以過程中常常會因漏考慮某些潛在危險的觸發因素而出 bug。當 DrumMachine.js 行數開始破千時就愈來愈陷入窘境,因為每次都要仔細檢查各式各樣的情況。Bug 就像地鼠一樣,常常一個解掉,另一個又不知道從哪裡冒出來,也是在這時候我才意識到自己應該寫測試,但那時時間已經快到死線了,測試一寫又動輒上百個情況!

後來想到了一個當下絕佳的解決方案,就是請 Joey 幫忙調 CSS。Bug 會出現的原因通常是在按鈕上進行各式各樣的排列組合時,某些組合下函數觸發到的行為會相互抵制。比方說我在設定函數的判定條件時會用 Boolean,但某個按鈕用來判定狀態的 Boolean 在按了另一個按鈕時可能會產生變化,下一次再按原本的按鈕時得到的資訊就會錯誤。如果用特定的規範來使用的話雖然不會有問題,但就怕使用者很好奇的到處亂按觸發了不該發生的事情。

調 CSS 厲害的地方在於它可以讓我在按下某個按鈕時,把另外幾個可能會碰到雷的按鈕給隱藏掉,以此避免掉有特殊情況的觸發。而這樣的解決方案同時也影響了整體的設計,讓程式的使用變得更單純、直覺,算是相當好運。

最後 deploy 到 Heroku 的部分就很單純,除了忘記把 .gitignore 裡頭的 public 資料夾取消掉花了我不少時間才發現以外,其他配置都還算順利。

總體而言,這次 Final Project 的經驗真的讓我學到超多東西,像是在 github 上面進行協作時,除了基本的 push pull 以外,Vibert 還帶著我們實作各種 pull request、解 conflict、發 issue 或是在 commit 裡面加 emoji 等功能 XD。而且做的東西真的很酷,之前三份作業因為都不難,常常功能做完 deploy 上去就了事了。但在做 Beact 的過程中雖然遇到的任務更具挑戰性,卻愈寫愈有動力,就是因為這東西超酷的,一開始只是想快點完成被要求做出來的功能,到後來寫到會想要自己加上新功能來讓整個程式更完整。

整次 Project 的分工是讓我感觸最深的一環。每次我介面上有什麼想法,Joey 都能用神奇的我根本不知道怎麼辦到的 CSS 技巧和 React 端的調整把它調成心中想要的樣子,印象中沒有哪次是完成不了的。然後 Vibert 懂的東西又超多,一人包辦所有動畫,中途有時間還會來幫我看 issue,每次問他程式的問題都能得到一些新觀念,讓我打從心底感到佩服。

最猛的是,Vibert 很知道怎麼引導出我們寫 code 的潛力,打一開始就已經把開發環境架構好讓我寫的時候很舒服,分派的任務難度又逐步提升,讓我不知不覺中開始做到以前認為做不到的事情。至今還是很難想像竟然能在一周內(算上一開始架構的話是兩週)完成這樣的作品,還蠻有成就感的,覺得內心寫程式的熱情愈來愈旺了!