PWA Online hackathon: ประสบการณ์ การเข้าร่วม และ การพัฒนา
สวัสดีครับ อาทิตย์ที่ผ่านมา ได้เข้าร่วมงาน PWA Online hackathon จึงอยากมาแชร์ประสบการณ์ การแข่งขันให้ฟังกันครับ
โดยมีหัวข้อดังนี้
1. PWA Online hackathon: overview
เป็นการแข่ง hackathon แบบ online (ทำที่ไหนก็ได้) ระหว่าง 23–25 มิถุนายน 2560, โดยจะมีกฏหลักๆดังนี้
- ไม่มี backend
- สามารถรันบน static server ได้
- code อยู่บน GitHub
- host อยู่บน Firebase hosting
- application มี Web app manifest
- ติดตั้ง Service Worker เพื่อทำให้ใช้งาน ขณะที่ไม่สามารถเชื่อมต่อ internet ได้
- ถ้าจะใช้ Firebase ใช้ได้แค่บางอย่างเท่านั้น — Firebase rules
โดยการให้คะแนนก็จะพิจารณาถึง
- ความสมบูรณ์ของ Web Application
- ความคิดสร้างสรรค์
- การเลือกใช้เทคโนโลยี
- (คะแนนพิเศษ) คะแนน Lighthouse เกิน 98 แต้ม
- (คะแนนพิเศษ) มี Web notification
- (คะแนนพิเศษ)ใช้ Geolocation API หรือ getUserMedia API
- (คะแนนพิเศษ) ทำ Web application เป็น Web VR
2. การเตรียมตัว
งานนี้ประกาศตั้งแต่ 25 พฤษภาคม เห็นประกาศก็สนใจทันที, ส่วนตัวเป็น web programmer อยู่แล้ว และได้ศึกษา PWA จาก Udacity: Front-End Web Developer Nanodegree และ Firebase มาแล้ว
เลยคิดว่าคงจะต้องศึกษาเพิ่มไม่มากเท่าไร กะไว้ว่าจะใช้ 1 อาทิตย์ก่อนแข่งเตรียมตัว แต่พอเอาเข้าจริง มีเนื้อหาให้ต้องศึกษา ค่อนข้างเยอะเลยทีเดียว ทำให้เตรียมตัวไม่ได้ดีเท่าที่ควร
3. Tool ที่ใช้
- Editor: Visual Studio Code
- Package manager, dependency management: npm และ yarn
- Development flow, build tool: Gulp และ npm
- Browser: Chrome และ Chrome Canary
4. Package และ Service ที่ใช้
4.1 Unit test
- Library: mocha
- Assertion: chai ช่วยสนับสนุนการ test แบบ BDD (syntax จะเหมือนภาษาพูด)
- Coverage: nyc ช่วยบอกว่า test ที่เราเขียนไป ครอบคลุมกี่ %
- Report: codecov ใช้งานได้ฟรีสำหรับ coverage report — ตัวอย่าง coverage report ของโปรเจค pwa-online-hackathon บน codecov
4.2 Lint tool
Lint tool พวกนี้จะช่วยควบคุมคุณภาพของ code ได้เบื้องต้น และช่วยกัน bug ได้บางส่วน
4.3 Development flow, build flow
- Static server: firebase/firebase-tools — จริงๆแล้วมีหลายตัว เช่น http-server, SimpleHTTPServer แต่ตัดสินใจใช้ firebase-tools เพราะยังไงก็ต้องใช้ในการ deploy ขึ้น Firebase hosting ด้วย
- Development flow:ใช้ npm-run-all package รัน ESLint และ Gulp (ทำ concat และ minify ทั้ง javascript และ css ไฟล์) ให้ทำงานไปพร้อมๆกัน
4.4 Source control และ commit conventions
- Source control: Git และเก็บไว้ที่ Github
- Commit conventions: cz-cli และ cz-conventional-changelog
ปกติแล้วเวลาเรา commit เราจะเขียน commit message อะไรก็ได้ — ปัญหาก็คือบางที commit message นั้นสื่อสารไม่ชัดเจนว่า commit นั้นเปลี่ยนแปลงอะไรบ้าง
โดย tool นี้จะช่วยเลือกหมวดหมู่ของ commit เราให้ ทำให้เราพอจะรู้คร่าวๆ ว่าใน commit นั้นๆทำอะไรบ้าง โดยไม่ต้องดู code ที่เปลี่ยนไปเลย
แล้วเราจะใช้ ghooks ช่วยในการ commit ด้วย — โดยเมื่อเรารัน yarn commit
เราจะสั่งให้ไปรัน yarn validate
ก่อนเสมอ ทำให้ code ถูก validate ก่อนที่จะ commit ทุกครั้ง
4.5 Build CI service
ใช้ Travis CI ในการทดสอบการ build project บน environment ที่ต่างกัน โดย project นี้จะทดสอบบน Node.js version 6, 7 , 8 และตั้งค่าไว้ว่า เมื่อ build สำเร็จก็ให้ทำการสร้าง coverage report ไปที่ โปรเจค pwa-online-hackathon ที่อยู่บน codecov.io
4.6 Project management tool
จะเขียน todo list (รายการที่จะต้องทำ) ลงใน README.md ง่ายๆแบบนี้เลย
5. ประสบการณ์ระหว่างการแข่งขัน
โดยจะไล่ตาม commit timeline
23/06@20.00
- ติดตั้ง tool เช่น Gulp, firebase/firebase-tools, ESLint, etc.
- หา idea — สรุปว่า จะทำเกมแนว clicker / idle games
โดยจะเป็นเกมอ้างอิงถึงระบบขนส่ง (Public transportation) กะว่าจะใส่อะไรสนุกๆ อย่าง รถม้าลําปาง, Uber, จรวด SpaceX, หรืออะไรแปลกๆลงไป แล้วจะได้ใช้ Geo location API เพื่อที่จะได้คะแนนพิเศษด้วย
ตัวอย่างเกมแนว clicker / idle games
24/06@01.00
- นอน
24/06@9.30
- ตั้งค่า tool, lib เช่น ESLint, Firebase, Lodash
เนื่องจากยังคิด game layout ใน screen size ขนาดต่างๆ ไม่ได้ (เช่น PC, tablet, mobile) เลยทำได้แค่ ตั้งค่า tool, lib ไปเรื่อยๆ
24/06@11.00
- ใส่หิมะ, ดาว, ดาวตก ไปใน background ของ game
- ตั้งค่า Gulp task เช่น concat javascript ทุกไฟล์
- ติดตั้ง Web App Manifest
- ติดตั้ง GoogleChrome/lighthouse — ไว้ตรวจสอบคุณภาพของ game ตามแนวทางของ PWA (Progressive Web Apps) และ optimze เพื่อเพิ่มคะแนน
- ใส่ Service woker (ทำให้ใช้งานขณะที่ไม่สามารถเชื่อมต่อ internet ได้)
- Deploy ไปที่ Firebase hosting
24/06@18.00
- ตัดสินใจเปลี่ยนเกม เนื่องจากคิด game layout บนขนาดต่างๆไม่ออก — เป็นเกมปัจจุบัน MeteorKiller: Kill all Star lord’s meteor , โดยใช้ดาวตกที่ได้ทำไว้ก่อนหน้าเป็นตัวหลักของเกม
- ออกแบบและคิด feature ของเกมเพิ่มเติม
- Game over screen
24/06@22.00
- ทำ icon homescreen ของ game กะไว้ว่าจะให้เหมือนดาวตก แบบ modern หน่อยๆ แต่ว่าผลงานที่ได้ ออกมาแล้วดูจะไม่เหมือนไม่สักเท่าไร แต่ก็โอเค
- ใส่ effect ตอน click (กลมๆ เหลืองๆ)
- เพิ่มระบบ score และ high score
25/06@01.00
- นอน
25/06@07.00
- sign-in และ sign-out ด้วย Firebase ผ่าน Gmail
25/06@11.00
- ติดตั้ง Firebase notification
- ติดตั้ง Firebase Realtime Database ไว้เก็บ score และ high score
- ทำ screenshake เมื่อเลือด (life) ในเกมลด — feature นี้จะเป็นการ สั่นจอแบบหลอกๆ (สังเกต ตอนสั่น, จะสั่นแค่ตรง คะแนน ไม่ได้สั่นทั้งจอ เพราะคิดว่า ถ้าสั่นทั้งจอ คนเล่นจะเล่นยาก)
- ใส่เสียง effect เวลาเลือดลด — เอามาจาก Bfxr
25/06@16.00 ถึงจบงาน 20.00
ทำการเพิ่ม performance และคะแนน GoogleChrome/lighthouse
- เพิ่ม start screen เวลาเริ่มเกม, เพื่อให้ไม่ให้เกม render เยอะขณะทำการเปิดเกมขึ้นมา ซึ่งทำให้ใช้ทรัพยากรเครื่องลดลง (ปล. code ส่วนนี้ไม่ค่อยดี เนื่องจากตอนแรกที่ทำ game engine ไม่ได้ออกแบบให้รองรับอะไรแบบนี้ไว้)
- สร้าง debounce function ขึ้นมาใช้เอง แล้วเอา Lodash ออก
- สร้าง random number และ boolean ขึ้นมาใช้เองแล้วเอา Chance.js ออก
- หลังจาก concat + minify ไฟล์ css และ javascript ทั้งหมด — ก็จะใช้ gulp-inline-source ในการยัด css และ javascript เข้า index.html ไฟล์เดียวเลย เพื่อจะได้โหลดแค่ไฟล์เดียว และรวมถึงลดปัญหาจาก network latency ด้วย (ปัจจุบันสามารถเอา css เข้าไปได้แล้ว แต่ javascript ยังต้องทำเองอยู่ ด้วยการ copy and paste)
6. ปัญหาที่เจอ
6.1 Commit ด้วยคำสั่ง yarn commit
ผ่าน commitizen (cz-conventional-changelog) และ ghooks ใช้เวลานานมากประมาณ 60 วินาที ต่อการ commit 1 ครั้ง บน Windows OS
6.2 Performance score of Lighthouse
คะแนน Performance ของ Lighthouse แกว่งบน Windows OS
- บน Windows คะแนนแกว่งระหว่าง 85–99
- บน OSX จะได้ 99 ตลอด
6.3 Lighthouse tool
ขณะที่เขียนบทความอยู่ เราสามารถรัน GoogleChrome/lighthouse ได้ 3 แบบ
- CLI
- Lighthouse Chrome extension ของ Chrome Web Browser
- Audits tab ใน Chrome DevTools ของ Chrome Canary
ตอนที่พัฒนาบน Windows OS จะใช้วิธีที่ 1 และ 2 พอทดสอบไปสักพัก ก็ใช้งานไม่ได้อีกเลย, จึงใช้วิธีที่ 3 มาโดยตลอด
7. สิ่งที่ควรปรับปรุงแก้ไขและศึกษาทำเพิ่ม
7.1 Test และ QA tool เยอะเกินไป
บางตัวแทบจะไม่ได้ใช้ เช่น unit test หรือบางตัวก็ไม่แน่ใจว่าคุ้มไหม กับเวลาที่ใช้ไป ในการติดตั้ง, ตั้งค่าและปรับปรุง
7.2. Development flow + build flow ในหัวข้อที่ 4.3
- คิดว่าในส่วนนี้ควรใช้ tool เดียวไปเลย เช่น Gulp, webpack module bundler
- คำสั่ง
yarn dev
ที่ใช้ในการพัฒนาหลัก ยังขาดการเรียกใช้งานบาง tool อยู่เช่น htmlhint และ stylelint
7.3 Test
- Unit test แทบจะไม่ได้ใช้ในโปรเจคนี้เลย
- การทดสอบการแสดงผล — code ส่วนใหญ่เป็นการ render บน canvas จนตอนนี้ก็ยังไม่แน่ใจว่าจะทดสอบ code ส่วนนี้ให้มีให้มีประสิทธิภาพได้อย่างไร (ตอนนี้คิดได้แค่ว่า ถ้าจะทดสอบคงใช้ใช้เทคนิคแบบเดียวกับ storybooks/storybook ที่ใช้ทดสอบ React)
- คำสั่งทดสอบที่เขียนไว้ใน .travis.yml ที่ใช้ยังไม่ตอบโจทย์เท่าไร คำสั่ง
coverage
และcoverage.check
ไม่ค่อยได้ใช้เพราะไม่ได้เขียน test สักเท่าไร, ส่วนbuild
นั้นยังไงก็ผ่านเพราะแค่ concat และ minify ไฟล์เฉยๆ
# .travis.yml
script:
- npm run build
- npm run coverage
- npm run coverage.check
7.4 Automated script
resize homescreen icon อัตโนมัติ เช่น เวลาทำรูปใหม่ก็จะได้ไม่ต้องมา resize ขนาดเป็นขนาดต่างๆเอง
7.5 Code pattern
ควรต้องนั่งดูทั้งโปรเจคใหม่อีกที ในโปรเจคผสมหลาย pattern มากเพื่อให้มันทำงานได้ (กลัวเสร็จไม่ทัน) ซึ่งส่วนตัวแล้วคิดว่าเขียนเป็น pattern เดียวกันหมดเลยน่าจะดีกว่า เช่นใช้ ES6 ทั้งโปรเจค
8. FAQ
8.1 ทำไมต้องเขียน game engine ขึ้นมาเอง
- อยากศึกษาการเขียน game engine
- ไม่เข้าใจ core ของ game framework เพียงพอ — ส่วนตัวเคยได้ลองเขียนเกมบนเวบ โดยใช้ Phaser — game framework มาบ้าง แต่มีปัญหาตรงที่เวลาอยากทำอะไรแปลกๆ ต้องค้น Google ตลอดแทบจะ 100% เพราะเนื่องจากไม่เข้าใจ core ของมัน
8.2 ทำไมเอา Lodash และ Chance.js ออก
- เพื่อศึกษา
- เพื่อรีดประสิทธิภาพให้ได้มากที่สุด
ผมใช้ debounce ของ Lodash กับ random number และ boolean ของ Chance.js สรุปแค่ 3 functions แต่ขนาดของทั้ง 2 libraries นั้นเยอะมาก ก็เลยตัดสินใจเอาออก แต่อย่างการเล่นไฟล์เสียง นั้นผมไม่ค่อยแน่ใจ ผมก็เลยยังคงใช้ howler.js
9. ส่งท้าย
ขอบคุณผู้อ่านที่เสียสละเข้ามาเยี่ยมชมนะครับ — ผิดพลาดอย่างไร, อยากให้ขยายความจุดไหนเพิ่มหรือคิดเห็นอย่างไร คอมเม้นด้านล่างได้เลยครับ
ท้ายนี้อยากจะขอบคุณคณะผู้จัดงาน และ ผู้สนันสนุนงานด้วยครับที่ได้จัดงานดีๆ แบบนี้ขึ้นมา
ปล. code อาจไม่ตรงไปบ้าง เพราะตอนนี้ยัง push code ใหม่ขึ้นไปที่ GitHub ไม่ได้ครับ
Updated 1@27/06/2017 เปลี่ยนคำพูดที่ใช้เล็กน้อย
Updated 2@28/06/2017 อัพเดทหัวข้อ 7.3 และ เปลี่ยนคำพูดที่ใช้เล็กน้อย