Git การใช้งานและเกม RxJS part 2: Workflow
พูดถึงการพัฒนางานใดๆหรือเกม Space Invaders นี้ ผมอยาก design ให้แยก branches ออกมา ประกอบด้วย master, develop, feature, release และ hotfix
Space Invaders พูดถึงภัยคุกคามต่างดาวที่บุกรุกจากอวกาศ เป็นยานต่างดาวจำนวนหนึ่งต่อสู้กับยานอวกาศของโลก สาดกระสุนใส่กันมันส์จะตาย
Reona: ขณะนั่งขัดสมาธิก็ปรบมือใหญ่ ดวงตาเป็นประกาย “ว้าวๆๆ ข้าเคยเล่นนะเกมแนวนี้”
Sven: พยักหน้า “ข้าก็เคยเล่นหนหนึ่งก่อนออกไปรบ มีนับคะแนนตอนยิ่งยานต่างดาวร่วงด้วยใช่ไหม”
ผู้เขียน: ใช่ครับ และนอกจากนั้นแล้วยัง-
Odin: โพล่งออกมา “พวกโบราณ”
… ทุกคนเงียบเป็นเป่าสาก
.
.
.
สักพัก Reona ก็ลุกขึ้น: มาพัฒนาเกมนี้กันต่อดีกว่า ข้าอยากเล่นไวๆแล้ว!
ความเดิมตอนที่แล้ว
RxJS
ก่อนจะไปต่อก็ขอกล่าวถึงไลบรารีตัวนี้สักเล็กน้อยครับ กระแสของการเขียนโปรแกรมโดยเน้นไปที่รูปแบบการเขียนโปรแกรม หลายคนคงพอจะได้ยินคำว่า Reactive Programming หรือการเขียนโปรแกรมเพื่อตอบสนองต่อ บางสิ่ง ที่เกิดขึ้น
กล่าวคือ บางสิ่ง นี้ต้องเกิดขึ้นก่อน มาถึงก่อน มันได้เกิดขึ้นแล้วแล้วจึงมีการโปรแกรมตามมา เช่นนี้จึงต้องไป reactive บางสิ่งนั่นยังไงล่ะ
สอดคล้องกับบทความของพี่ somkiat เพราะเมื่อเราได้เน้นไปที่รูปแบบ (style) การเขียนโปรแกรมแบบ reactive ฉันใด ตัว application ที่ได้จึงเป็น application แบบ Reactive Application ไปด้วยฉันนั้น
ความคิดคำถามคือ แล้วจะ reactive programming ไปใย?
คำตอบคือ 4 ประการนี้เป็นคำสัญ (ยกมาจากพี่ somkiat)
- ตอบรับกับ Event ต่างๆ ได้ นั่นคือ Event driven
- ตอบรับกับจำนวนการใช้งานที่สูงขึ้นมากๆ นั่นคือ Scalable
- ตอบรับกับการทำงานที่ผิดพลาด เพื่อแก้ไขให้ถูกต้อง นั่นคือ Resilient
- ตอบรับกับผู้ใช้งานได้อย่างรวดเร็ว นั่นคือ Responsive
หลายภาษาไม่ว่าจะเป็น จาวา, จาวาสคริปต์, C# และอื่นๆก็ได้ implement หรือนำรูปแบบ (ตลอดจนหลักการของมัน) ไปใช้แล้ว สำหรับภาษาจาวาสคริปต์ก็คือ RxJS ครับ
แล้ว บางสิ่ง นั่นคืออะไรล่ะ?
คำตอบคือ observable streams
อ่านเพิ่มเติม
master, develop, feature, release and hotfix
เอาล่ะตามความตั้งใจดังที่ว่าไว้ เมื่อเราใช้คำสั่ง git log
เราได้ git history
commit ล่าสุดจะอยู่บนสุด จากรูปข้างต้นยังบอกอีกว่า head pointer ชี้ไปที่ branch ชื่อ master
คำถาม head pointer นี้สำคัญอย่างไร?
คำตอบ การชี้ไปยัง branch ใดๆของมันเท่ากับว่า action ที่กำลังจะเกิดจะเกิดขึ้น ณ ตรงนี้เป็นต้นไป
ดูรูปประกอบครับ
เมื่อตัวเลข f9557, 2c975 และ 14a56 ผมนำมาจาก 5 ตำแหน่งแรกของหมายเลข commit ในแต่ละครั้ง
commit 14a56 คงเกิดขึ้นไม่ได้ถ้าไม่มี commit 2c975
commit 2c975 คงเกิดขึ้นไม่ได้ถ้าไม่มี commit f9557
commit f9557 คือจุดเริ่มต้น
จากรูปข้างต้นเราจะเห็นว่า master branch ก็เป็น pointer ที่กำลังชี้ commit 14a56 ซึ่งตัว pointer นี้จะเลื่อนไปยัง commit ล่าสุดให้อัตโนมัติ
และจากรูปข้างต้นเราจะเห็นอีกว่า head pointer กำลังชี้ master branch เท่ากับว่า action ที่กำลังจะเกิดจะเกิดขึ้น ณ ตำแหน่งของ master branch เป็นต้นไป
สร้าง develop branch
Reona: ข้าเข้าใจว่าท่านจะเริ่มทำงานได้จะไม่ทำที่ master branch แต่ท่านจะแยก branch ออกมาใหม่ ให้ชื่อว่า develop จากนั้นจะทำงานที่ branch นี้เป็นสำคัญ
ถูกต้องครับ
Git มีคำสั่งสร้าง branch แยกออกมาจาก branch ที่ head pointer ชี้อยู่ คำสั่งนั้นคือ git branch <branch-name>
ผมอยาก design ให้แยก branches ออกมา ประกอบด้วย master, develop, feature, release และ hotfix โดยแต่ละ branch มีความหมายดังนี้
- master เป็น branch หลัก โค้ดหรือชิ้นงานล่าสุดที่ได้ส่งมอบลูกค้าจะอยู่ที่นี่
- develop เป็น branch ที่แยกจาก master โดยทั่วไปกำหนดให้นักพัฒนา (developer) แต่ละคนที่มีส่วนร่วมทำงานกับ branch นี้เป็นหลัก งานหรือโค้ดที่อยู่กับ branch นี้นั้นมักจะไปไกล (จำนวน commit) กว่า master
- feature เป็น branch ที่แยกจาก develop อีกทีด้วยความคิดที่ว่า มันย่อมดีกว่าเมื่อเราได้รู้ว่ากำลังจะทำอะไร กำลังจะเพิ่มสิ่งใดเข้าไปซึ่งมันเหล่านั้นได้ถูกแยกเป็น feature ต่างๆไว้แล้ว ตัวอย่างเช่น จะเพิ่มหน้า dashboard เราก็จะสร้าง branch ใหม่ชื่อ dashboard แยกออกมาจาก develop
- release เป็น branch ที่แยกจาก develop อีกทีด้วยความคิดที่ว่า เมื่อใดก็ตามที่เราได้ทำ feature อย่างเพียงพอที่จะส่งมอบชิ้นงาน (ขึ้นอยู่กับข้อตกลงร่วมกันของทีม) ในแต่ละครั้งหรือแต่ละรอบ (เช่นทุกๆ 2 สัปดาห์) release branch จะถูกสร้างขึ้นพร้อมกับติด tag หรือที่เรียกว่า tagged ระบุเวอร์ชันของชิ้นงาน และโดยทั่วไปแล้วจะมีข้อตกลงว่าหลังจากเกิด release ใดในแต่ละครั้งไปแล้วจะไปเพิ่ม feature ให้กับ release นั้นอีกไม่ได้ (feature นี้ต้องเป็นของ release ถัดไปเท่านั้น) ยกเว้นว่า release ไปแล้วเกิด bug หรือต้องการเพิ่ม document อย่างนี้ทำได้และเมื่อทำแล้วก็ต้อง merge กลับไปยัง develop ด้วย
- hotfix เป็น branch ที่แยกจาก master ถูกสร้างก็ต่อเมื่อเกิดความผิดพลาดอันไม่คาดฝันขึ้นกับชิ้นงานที่ถูกส่งมอบไปแล้ว หลังจากจัดการเรียบร้อยก็จะต้องถูก merge กลับไปยัง master และ develop เป็นเหตุให้ master ควรติด tag และ update version ย่อยด้วย
เรามาสร้าง develop branch กันก่อน
git branch develop
คำสั่งนี้เป็นผลให้เกิดรูปนี้ครับ
สอดคล้องกับคำสั่ง git log
และโปรดสังเกตว่า head pointer ยังคงชี้ที่ master branch
หรือจะดูแบบนี้ก็ได้ (เพิ่มเติม)
git log --oneline --decorate
ดูใน Sourcetree บ้าง
สังเกตมุมซ้ายล่างของรูปส่วนที่เรียกว่า BRANCHES ปรากฏ develop branch ซึ่งสัญลักษณ์วงกลม o นี้อยู่กับ master branch หรือก็คือตำแหน่งที่ head pointer ชี้อยู่
ย้ายไปยัง develop branch
คำสั่งนี้จะย้าย head pointer ไปยัง branch ที่กำหนด
รูปแบบคำสั่ง git checkout <branch-name>
git checkout develop
feature: Game Title
เราจะเริ่มต้นด้วยการทดสอบสร้าง feature แรกกัน นั่นคือ title ของเกม โดยจะให้ชื่อว่า Space Invaders Game แสดงอยู่ใน h1 ประมาณนี้
<h1>Space Invaders Game</h1>
ทว่าการจะใส่ title เข้าไปได้ขอกลับไปเตรียมความพร้อมให้โปรเจกต์ ณ develop branch สามารถ render ไฟล์ index.html ได้ก่อน (อ่านเพิ่มเติม)
เราอยู่ที่ develop branch อยู่แล้ว ดังนั้น
npm i -D html-webpack-plugin
ขอเพิ่มอีก 1 plugin แก่ webpack เพื่อให้มันสร้างไฟล์ index.html ให้เราอัตโนมัติ
จากนั้นแก้ไขไฟล์ webpack.config.js บอกให้ใช้งาน plugin นี้
บันทึกแล้วเริ่ม commit
อย่างแรกที่ Sourcetree จะมองเห็นว่ามีการแก้ไขไฟล์เกิดขึ้น
เช่นนั้นคลิกที่ File status
3 ไฟล์ข้างต้นนี้อยู่ในสถานะถูก modified (เพราะไม่ได้สร้างใหม่) จำเป็นต้อง staged ทั้งหมดเพื่อให้สามารถ commit ได้ให้คลิกเลือกทุกไฟล์ครับ
จากนั้นระบุเหตุผลในช่องของ message แล้วกดปุ่ม commit
จะเห็นว่า develop branch ได้นำ master branch ไปแล้ว 1 commit
กลับมาที่ feature ของเรา เราต้องการ title ของเกมถูกไหม สร้าง game-title branch แยกออกมาจาก develop branch
git branch game-title
แล้วย้ายไปยัง game-title branch
git checkout game-title
แต่เดี๋ยวก่อน! Git มีหนทางที่ให้เราทำ action ข้างต้นในคำสั่งเดียว นั่นคือ
git checkout -b game-title
เมื่อ -b หมายถึง branch
เท่านี้เราก็พร้อมแล้ว เปิดไฟล์ app.js แล้วเพิ่มโค้ดได้
บันทึกไฟล์แล้วเรียก npm มาทำงาน (ถ้าเกิดว่าได้ปิดไปแล้ว)
npm run start
ผล
เมื่อผลทดสอบเป็นที่พอใจเราจึงต้องไป commit
กระบวนการ commit เราได้ทราบและทำเป็นแล้ว ฉะนั้นให้ทำเองและขอข้ามไปนะ
Merge game-title (feature) branch
เป็นธรรมดาเมื่อ feature ถูกพัฒนาและทดสอบ (ที่เครื่อง local ของ developer) เรียบร้อยแล้วก็จะถูกรวมเข้ากับ branch ที่ได้แยกออกมาแต่แรก
game-title branch จะต้องถูกรวมเข้ากับ develop branch เท่านั้นจะข้ามไป branch อื่นไม่ได้
การรวม branch นี้ Git เรียกว่า merge รูปแบบคำสั่ง git merge <branch-name>
สำคัญมาก จะรวม game-title เข้ากับ develop ก็ต้องอยู่ ณ develop เสียก่อน
จึงต้องย้าย head pointer ไปยัง develop
git checkout develop
ลองดู git log ด้วยคำสั่งต่อไปนี้
git log --oneline --decorate --all
จากนั้นรวม game-title เข้ามาครับ
git merge game-title
ผล
Updating c8b6bf3..30c0454
Fast-forward
src/app.js | 1 +
1 file changed, 1 insertion(+)
Delete game-title (feature) branch
เมื่อเสร็จศึกฆ่าขุนพล game-title branch ไม่มีความจำเป็นอีกต่อไปก็ลบทิ้ง
โปรดสังเกตว่าการจะลบ branch ใดๆได้นั้น เราจะให้ head pointer อยู่ ณ branch นั้นๆไม่ได้ แต่ขณะนี้ head pointer อยู่ที่ develop จึงสามารถลบ game-title ได้เลย
git branch -d game-title
ทั้งหมดนั่นคือทำด้วย command line หรือ terminal เช่นกันเราสามารถทำด้วย Sourcetree ได้ไม่แตกต่าง
จะว่าอย่างไรดีล่ะ ผมเองก็ฝึกใช้และเขียนบทความนี้สดๆควบคู่กันไป ก่อนหน้านี้ก็ไม่ได้ใช้ Sourcetree จริงจัง หนนี้ก็ลองผิดลองถูก หาผลลัพธ์ตามที่คาดหวังครับ
feature: Star Space Background
Google ค้นหาพื้นหลังเป็นรูปอวกาศและดวงดาว ได้รูปนี้มา
บันทึกแล้วตั้งชื่อว่า bg-star-space (สกุล .jpg)
ใช้ Sourcetree สร้าง (feature) branch ใหม่ชื่อ star-space โดยการ
- แน่ใจว่าเลือกอยู่ ณ develop branch
- คลิกปุ่ม Branch
- แน่ใจว่าได้เลือก Working copy parent และ Checkout new branch ไว้ด้วย
- ตั้งชื่อ star-space
- กดปุ่ม Create Branch
ผลเหมือนกับใช้คำสั่งนี้เมื่ออยู่ที่ develop branch
git checkout -b star-space
ที่โปรเจกต์ภายใน src folder ให้เพิ่ม folder ใหม่ชื่อ assets แล้วนำรูปที่โหลดได้มาใส่ไว้
แก้ไขไฟล์ app.js
- เพิ่ม div tag
- และเพิ่ม CSS class ให้ div tag ชื่อ bg-star-space
- สร้างไฟล์ชื่อ style.css ไว้ภายใน src folder
- ประกาศและระบุรายละเอียดของคลาส bg-star-space
import './style.css'
document.body.innerHTML = '<h1>Space Invaders Game</h1>'
const createStarSpace = () => { const elem = document.createElement('div') elem.classList.add('bg-star-space') return elem}
document.body.appendChild(createStarSpace())
ไฟล์ style.css
.bg-star-space { background-image: url("assets/bg-star-space.jpg"); background-color: black; background-repeat: no-repeat; background-position: center; background-size: cover; height: 450px;}
เมื่อ webpack ทำงานเราจะได้ bundle.js ซึ่งถูกเรียกใช้โดย index.html และเมื่อใดก็ตามเราเรียกใช้ไฟล์ .css จำต้องใช้ความสามารถในการโหลด .css เหล่านั้น ข่าวดีคือเรามี css-loader ทำหน้าที่โหลด .css และ style-loader ทำหน้าที่เขียน selector ทั้งหมดไว้ภายใน style tag ซึ่งจะถูกฝังไว้ใน head tag ของ index.html อีกทีหนึ่ง
เราจำเป็นต้องเพิ่ม css-loader และ style-loader แก่ webpack
npm i -D style-loader css-loader
จากนั้น config เพิ่มในไฟล์ webpack.config.js
...module: { rules: [ { ... }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ]}...
หยุด webpack dev server แล้วรันมันใหม่
ผล
กลับไปยัง Sourcetree
เลือก File status
แล้ว Staged file ทุกไฟล์
ให้คำอธิบายเล็กน้อยที่ช่อง commit แล้วกดปุ่ม commit
ดูที่ history จะพบว่า start-space feature branch ได้นำ develop branch ไปแล้ว 1 committed
Merge star-space (feature) branch
เมื่อทดสอบแล้วว่าไม่มี bug ใดๆเราก็ต้องการ merge รวม star-space เข้ากับ develop ดังนั้น
checkout หรือ switch branch ไปยัง develop สำหรับ Sourcetree สามารถทำได้เลยด้วยการ double click ที่ develop
จากนั้น merge
- แน่ใจว่าอยู่ develop
- กดปุ่ม Merge
- แน่ใจว่าได้เลือก Merge From Log
- เลือก star-space
- เลือก Options แค่ Commit merge immediately (if no conflicts)
- กดปุ่ม OK
ผล
Delete star-space (feature) branch
เมื่อเสร็จนาฆ่าโคถึก star-space branch ไม่มีความจำเป็นอีกต่อไปก็ลบทิ้ง
- แน่ใจว่าอยู่ develop
- กดปุ่ม Branch
- เลือก Delete Branches
- เลือก star-space
- กดปุ่ม Delete Branches
เพิ่มเติม
webpack.config.js
การ checkout
การ checkout หรือ switch branch จาก branch หนึ่งสู่อีก branch หนึ่ง ต้องให้แน่ใจว่าไม่ได้แก้ไขไฟล์ใดๆไว้ (แก้ไขแล้วบันทึกแต่ไม่ได้ commit) เพราะไฟล์เหล่านั้นจะอยู่ในสถานะ modified กล่าวคือ Git รับทราบแล้วว่าเปลี่ยนแปลง หากยืนยันจะ checkout ให้ได้จะต้องทำอย่างหนึ่งอย่างใดใน 3 อย่างนี้ (เลือกเอาสักทาง)
- commit ไฟล์เหล่านั้นให้เสร็จก่อน
git add <path-of-file>
ต่อด้วยgit commit -m "description..."
- ยกเลิกการเปลี่ยนแปลงเหล่านั้นเสีย
git checkout <path-of-file>
- เก็บการเปลี่ยนแปลงเหล่านั้นไว้ก่อนด้วย
git stash
แล้วค่อยดำเนินการต่อด้วยgit stash pop
Odin: เอาล่ะๆน่าจะพอได้แล้ว ข้าหิว!
จ้า งั้นโอกาสหน้าพบกันใหม่ครับ จะพาไปรู้จักกับ Github พร้อมกับ git remote
อ้างอิง
https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
https://webpack.js.org/guides/asset-management/
https://blog.jakoblind.no/css-modules-webpack/
https://www.w3schools.com/cssref/pr_background-image.asp