Git การใช้งานและเกม RxJS part 2: Workflow

Phai Panda
8 min readMar 1, 2020

--

พูดถึงการพัฒนางานใดๆหรือเกม 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

git history, ออกจาก git log กด q

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

คำสั่งนี้เป็นผลให้เกิดรูปนี้ครับ

create develop branch

สอดคล้องกับคำสั่ง git log และโปรดสังเกตว่า head pointer ยังคงชี้ที่ master branch

create develop branch

หรือจะดูแบบนี้ก็ได้ (เพิ่มเติม)

git log --oneline --decorate
create develop branch

ดูใน Sourcetree บ้าง

create develop branch

สังเกตมุมซ้ายล่างของรูปส่วนที่เรียกว่า BRANCHES ปรากฏ develop branch ซึ่งสัญลักษณ์วงกลม o นี้อยู่กับ master branch หรือก็คือตำแหน่งที่ head pointer ชี้อยู่

ย้ายไปยัง develop branch

คำสั่งนี้จะย้าย head pointer ไปยัง branch ที่กำหนด

รูปแบบคำสั่ง git checkout <branch-name>

git checkout develop
move to develop branch
move to develop branch
move to develop branch

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 นี้

webpack.config.js

บันทึกแล้วเริ่ม commit

อย่างแรกที่ Sourcetree จะมองเห็นว่ามีการแก้ไขไฟล์เกิดขึ้น

Sourcetree History: Uncommitted changes

เช่นนั้นคลิกที่ File status

Sourcetree File status: Unstaged files

3 ไฟล์ข้างต้นนี้อยู่ในสถานะถูก modified (เพราะไม่ได้สร้างใหม่) จำเป็นต้อง staged ทั้งหมดเพื่อให้สามารถ commit ได้ให้คลิกเลือกทุกไฟล์ครับ

Sourcetree File status: Staged files

จากนั้นระบุเหตุผลในช่องของ message แล้วกดปุ่ม commit

commit message box
เกิด commit ใหม่ ณ develop branch
เกิด commit ใหม่ ณ develop branch
เกิด commit ใหม่ ณ develop branch

จะเห็นว่า 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

create game-title feature branch & move to it
head pointer ชี้ที่ game-title
head pointer ชี้ที่ game-title

เท่านี้เราก็พร้อมแล้ว เปิดไฟล์ app.js แล้วเพิ่มโค้ดได้

บันทึกไฟล์แล้วเรียก npm มาทำงาน (ถ้าเกิดว่าได้ปิดไปแล้ว)

npm run start

ผล

Reona: เย้! ออกมาแล้ว

เมื่อผลทดสอบเป็นที่พอใจเราจึงต้องไป commit

กระบวนการ commit เราได้ทราบและทำเป็นแล้ว ฉะนั้นให้ทำเองและขอข้ามไปนะ

Sven: เข้าใจง่ายดีแฮะ
Odin: ไม่เห็นว่ามันจะยากตรงไหน
Reona: ข้ากลับรู้สึกชอบ command line (terminal) มากกว่า Sourcetree ฮ่าๆ

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
move to develop before merge game-title

ลองดู git log ด้วยคำสั่งต่อไปนี้

git log --oneline --decorate --all
move to develop before merge game-title
move to develop before merge game-title

จากนั้นรวม game-title เข้ามาครับ

git merge game-title

ผล

Updating c8b6bf3..30c0454
Fast-forward
src/app.js | 1 +
1 file changed, 1 insertion(+)
merge: fast-forward
merge game-title feature branch into develop branch
merge game-title feature branch into develop branch

Delete game-title (feature) branch

เมื่อเสร็จศึกฆ่าขุนพล game-title branch ไม่มีความจำเป็นอีกต่อไปก็ลบทิ้ง

โปรดสังเกตว่าการจะลบ branch ใดๆได้นั้น เราจะให้ head pointer อยู่ ณ branch นั้นๆไม่ได้ แต่ขณะนี้ head pointer อยู่ที่ develop จึงสามารถลบ game-title ได้เลย

git branch -d game-title
after delete game-title feature branch
after delete game-title feature branch
after delete game-title feature branch

ทั้งหมดนั่นคือทำด้วย command line หรือ terminal เช่นกันเราสามารถทำด้วย Sourcetree ได้ไม่แตกต่าง

จะว่าอย่างไรดีล่ะ ผมเองก็ฝึกใช้และเขียนบทความนี้สดๆควบคู่กันไป ก่อนหน้านี้ก็ไม่ได้ใช้ Sourcetree จริงจัง หนนี้ก็ลองผิดลองถูก หาผลลัพธ์ตามที่คาดหวังครับ

feature: Star Space Background

Google ค้นหาพื้นหลังเป็นรูปอวกาศและดวงดาว ได้รูปนี้มา

บันทึกแล้วตั้งชื่อว่า bg-star-space (สกุล .jpg)

bg-star-space.jpg

ใช้ Sourcetree สร้าง (feature) branch ใหม่ชื่อ star-space โดยการ

  1. แน่ใจว่าเลือกอยู่ ณ develop branch
  2. คลิกปุ่ม Branch
  3. แน่ใจว่าได้เลือก Working copy parent และ Checkout new branch ไว้ด้วย
  4. ตั้งชื่อ star-space
  5. กดปุ่ม Create Branch
create star-space feature branch

ผลเหมือนกับใช้คำสั่งนี้เมื่ออยู่ที่ develop branch

git checkout -b star-space
star-space already created

ที่โปรเจกต์ภายใน 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 แล้วรันมันใหม่

ผล

Reona: ท่านนี่ไม่ธรรมดา

กลับไปยัง Sourcetree

เลือก File status

แล้ว Staged file ทุกไฟล์

Reona: เลือกทั้งหมดเลยนะ, Sven: ใช่

ให้คำอธิบายเล็กน้อยที่ช่อง commit แล้วกดปุ่ม commit

ดูที่ history จะพบว่า start-space feature branch ได้นำ develop branch ไปแล้ว 1 committed

hisotry

Merge star-space (feature) branch

เมื่อทดสอบแล้วว่าไม่มี bug ใดๆเราก็ต้องการ merge รวม star-space เข้ากับ develop ดังนั้น

checkout หรือ switch branch ไปยัง develop สำหรับ Sourcetree สามารถทำได้เลยด้วยการ double click ที่ develop

double click ที่ develop branch

จากนั้น merge

  1. แน่ใจว่าอยู่ develop
  2. กดปุ่ม Merge
  3. แน่ใจว่าได้เลือก Merge From Log
  4. เลือก star-space
  5. เลือก Options แค่ Commit merge immediately (if no conflicts)
  6. กดปุ่ม OK

ผล

Reona: เรียบร้อย!

Delete star-space (feature) branch

เมื่อเสร็จนาฆ่าโคถึก star-space branch ไม่มีความจำเป็นอีกต่อไปก็ลบทิ้ง

  1. แน่ใจว่าอยู่ develop
  2. กดปุ่ม Branch
  3. เลือก Delete Branches
  4. เลือก star-space
  5. กดปุ่ม Delete Branches
delete star-space feature branch
after deleted star-space feature branch
after deleted star-space feature branch
after deleted star-space feature branch

เพิ่มเติม

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

--

--

No responses yet