มาทำ Automate Code Review กัน

Jedsada Tiwongvorakul
20Scoops CNX
Published in
6 min readApr 17, 2018

สวัสดีครับ เนื่องจากเป็นวันหยุดยาว…. ไม่มีอะไรทำก็เลยไปไล่อ่านโปรเจ็คคนอื่นใน Github จนไปสะดุดตาโปรเจ็คหนึ่ง “เห้ยมันมีไฟล์อะไรไม่คุ้นเลย มันเอาไว้ทำอะไรวะ” ลองมองดูแล้วก็ยิ่งไม่เข้าใจ ฮ่า ฮ่า ฮ่า ก็เลยเป็นที่มาของบทความนี้ ซะเลย

ซึ่งเจ้าไฟล์นั้นมันเข้ามาช่วยในเรื่องของการทำ Code Review ให้เป็น Automate ในบางส่วนนั่นเอง ซึ่ง ณ​ ปัจจุบัน Developer ในยุคไทยแลนด์ 4.0 คงไม่มีใคร ไม่ใช้ Git Workflow ในการทำงาน อะเนาะ ซึ่งถ้าหากใครไม่ได้ใช้ หรือยังไม่รู้ว่ามันมีขั้นตอนทำงานยังไงก็สามารถเข้าไปอ่านเพิ่มเติมได้จากด้านล่างนี้ได้เลยจ้า 👇

และถ้าหากใครใช้อยู่แล้วก็คงจะรู้ดีอยู่แล้วว่าหากเราต้องการเอาโค้ดที่เราได้ทำการสร้างขึ้นมาเอาเข้าไปใน branch master เราจำเป็นต้องทำการ PR (Pull Request) เข้าไปและในแต่ละ PR ก็จำเป็นต้องกำหนดผู้ที่จะมาแสดงความคิดเห็น (Reviewers) เพื่อทำการ Review Code ที่เรา PR ไป จากนั้นก็ขึ้นอยู่กับโชคชะตาว่าจะผ่าน หรือไม่ผ่าน 😎

แอบมองเธออยู่นะ จ๊ะ :)

ซึ่งในบาง PR อาจจะโดนให้ไม่ผ่านเพราะเรื่อง Format ของโค้ด เช่น Indentaion พัง หรือ ระยะห่างของ Operator ไม่ได้จัด ซึ่งดูแล้วอาจจะคิดว่า เป็นเรื่องเล็กน้อยแต่ลองถามตัวเองดูว่าจะยอมให้โค้ดที่ไร้ความสวยงาม หรือ ไม่ถูกตาม Format ของภาษาที่เขียนอยู่ ผ่านจริงหรอ? ความคิดเห็นส่วนตัวผมคิดว่าเรื่องพวกนี้มันน่าจะถูกจัดการตั้งแต่ระหว่างการทำงานไปด้วยแล้ว

คำถาม คือ ละเรื่องของพวก Format จะยึดตามจากไหนล่ะ? ก็ตอบเลยว่ายึดตาม Lint ของแต่ละภาษาครับ หวังว่าผู้ที่หลงเข้ามาอ่านคงเคยใช้ “ลิ้นนน” กันนะครับ แหม๋ๆ คิดลึกจังหมายถึงตัวผม… ในบทความนี้ผมจะยกตัวอย่างการใช้ Lint ของภาษา Kotlin นะครับ อันดับแรกก็ต้องไปดูแหล่ง Guideline Code Style ของ Kotlin กันก่อนว่ามีแนวทางไหนให้เราเอาเป็นที่พึ่งทางใจได้บ้าง

  1. จากทาง Android Kotlin Style Guide

2. จากทาง kotlinlang.org

ซึ่งทั้งสอง Guideline มีความแตกต่างกันอยู่นิดหน่อย เช่น เรื่องของ Indentation ในกรณีที่มี parameter หลายตัวจนทำให้เราต้องเคาะบรรทัดลงมาความแตกต่างก็คือ จาก Guideline Code Style ข้อที่ 1 จะมี Indentation เป็น 8 จากบรรทัดแรก แต่ข้อที่ 2 จะเป็น 4 เสมอ ดังภาพด้านล่างนี้

ข้อที่ 1 Android Kotlin Style Guide
ข้อที่ 2 kotlinlang.org

ชิปหายล่ะ!!! ละจะยึดตามไหนดีละ ก็คงต้องตอบว่าเอาที่สบายใจครับ ขึ้นอยู่กับความชอบส่วนบุคคลล้วนๆ เลยครับผม ซึ่งวันนี้ผมจะพามารู้ทำความรู้จักกับเจ้า Ktlint ซึ่งเป็นเครื่องมือในการช่วยตรวจสอบ Format โค้ดของภาษา Kotlin และมันยังมีดีตรงที่มันเอา Guideline ทั้งสองตัวมารวมกัน แต่จากที่ลองจะเน้นหนักไปที่ Code Style จากทาง kotlinlang.org นะครับ และอีกอย่างที่ผมชอบมากเลยคือ เราสามารถสั่งให้มัน แก้ไข Format โค้ดให้เราโดยโดยอัตโนมัติได้อีกด้วย โคตรคูล ☃️

มาลองเล่นกันเลยดีกว่า ในบทความนี้ขอยกตัวอย่างเป็นโปรเจ็ค Android นะครับก่อนอื่นต้องขอบอกก่อนว่าเจ้า Ktlint นั้นมีคนทำ Gradle Plugin ออกมาเพื่อให้เราสามารถตั้งค่าพวกไฟล์ Report หรือ การ Ignore Failures เพื่อต้องการให้มันเตือนเฉยๆ ไม่อยากให้ Error ณ ตอนนั้นเลยให้สามารถทำได้ง่ายขึ้น ซึ่งก็มีอยู่ 2 ด้วยกันได้แก่

ใครชอบ Plugin ตัวไหนก็เลือกใช้ได้ตามใจชอบเลยนะครับผม ส่วนตัวผมใช้ตัวที่หนึ่งนะครับ เพราะว่า ⭐️ เยอะกว่า เหตุผลโง่มาก มาเริ่มกันเลย ลุย!!!

ขั้นตอนแรก ให้ทำการนำ tag plugins ด้านล่างนี้ไปไว้ในไฟล์ build.grale ที่อยู่ในระดับ root โปรเจ็คหน้าตาก็จะออกมาประมาณนี้

buildscript {
ext.kotlin_version = '1.2.31'
...
}

plugins {
id "org.jlleitschuh.gradle.ktlint" version "3.2.0"
}

ขั้นตอนที่สอง (Optional) ทำการตั้งค่าให้กับตัว Plugin Ktlint ที่ไฟล์ build.gradle ในระดับ root โปรเจ็คเช่นเดิม ดังนี้

// configuration
ktlint {
// version ktlint [https://github.com/shyiko/ktlint/releases]
version = "0.21.0"

// enable debug mode
debug = true

// enable verbose mode
verbose = true

// enable android mode
android = true

// enable log in console
outputToConsole = true

// type file report ("PLAIN", "CHECKSTYLE", "JSON"
// and "PLAIN_GROUP_BY_FILE")
// you can add multi type file report because reporters is array
reporters = ["CHECKSTYLE"]

// enable feature ignore case failures
ignoreFailures = true
}

ทำการกด Sync Now ที่มุมขวาด้านบน รอสักพักเป็นวัยรุ่นอย่าใจร้อน พอ gradle ทำงานเสร็จให้ทำการดู tasks ของ gradle โดยใช้คำสั่ง ./gradlew tasks ก็จะเห็นว่ามี tasks เพิ่มเข้ามาได้แก่

จะเห็นได้ว่ามี tasks ของ gradle ที่เพิ่มเข้ามาอย่างชัดเจนได้แก่ group tasks ที่ชื่อว่า Formatting tasks ซึ่งเป็น group ใหม่และใน group tasks ที่ชื่อว่า Verification tasks ก็จะมี tasks ที่เป็น klint เพิ่มเข้ามาจากเดิม ซึ่งผมก็ไม่ขออธิบายว่า tasks ใหม่ที่เพิ่มเข้ามานั้นมีหน้าที่ทำอะไรบ้าง เพราะว่ามันก็มีคำอธิบายต่อท้ายไว้อยู่แล้ว

ขั้นตอนสุดท้าย มาทดสอบ Ktlint โดยให้ทำการสร้างไฟล์ที่ชื่อว่า UserData.kt เข้าไปในโปรเจ็คซึ่งจะมีโค้ดตามด้านล่างนี้

จากนั้นให้ทำการใช้คำสั่ง ./gradlew ktLintDebugCheck ถ้าหากใครทำตามทุกขั้นตอนอย่างถูกต้องก็จะได้ผลลัพธ์ ประมาณนี้

Ktlint ก็จะแจ้งเตือนออกมาว่าไฟล์ไหนที่บรรทัดไหนที่ไม่ถูกตาม Format ของ Ktlint และก็จะมีไฟล์ Report ออกมาซึ่งจะอยู่ที่ ../app/build/reports/ktlint/ktlint-debug.xml แต่อาจจะมีไฟล์ .txt หรือ .json อยู่ที่เรา Config นะครับ อันนี้จำไว้ก่อนนะครับว่าไฟล์ Report ของ Ktlint อยู่ตรงไหนอันนี้สำคัญ ***

*** ./gradlew ktlintDebugFormatเป็นคำสั่งเพื่อบอกว่า เห้ย นาย ช่วยจัด Format โค้ดให้เราหน่อย เมื่อทำการจัด Format เสร็จให้ทำการลองตรวจสอบ ktlint อีกทีก็จะไม่เจอ Error แล้ว เพียงเท่านี้โค้ดของเราก็ถูก Format แล้ว

Android Studio สามารถตั้งค่าการ Reformat Code ให้ตรงกับ Ktlin ได้ด้วยนะ

ละลายหมดเลยใจ ละลายหมดเลย ❤️

แต่กลับเข้ามาสู่ชีวิตจริงถ้าทุกคนในทีมทำแบบนี้ทุกครั้งก่อนที่จะ push code ขึ้นมาที่ Repository ก็ดีสินะ และไม่ว่าเราจะเขียน script ขึ้นมาสักตัวหนึ่งแล้วตะโกนออกไปว่าเห้ย พวกนายเวลา build app ให้ใช้คำสั่งนี้อย่างเดียวนะก็ตาม เพราะความผิดพลาดมันเกิดขึ้นได้เสมอ

เพราะฉะนั้นแล้ว เราไปทำการ Config ไว้ที่ตัว Continuous Integration (CI) จะดีกว่าไหม? ความหมายก็คือ ลืมก็ไม่เป็นไรหรอก เดี๋ยวไปเจอกันที่ CI แทนแล้วกันเนาะ และถ้าเจอ Error ก็จะไป Comment ที่ PR (Pull Request) ให้แบบ Automate ละกันนะจ๊ะ เพราะการที่เราเสียเวลา Review Code ที่ไม่ถูก Format นั้นมันเสียเวลาโดยใช่เหตุแทนที่จะไปโฟกัสในส่วนที่เป็น Business Logic แทน

มาถึงพระเอกของงานสักที โม้มาซะยาวเยียด เมื่อเราได้ไฟล์ report ของ ktlint หรือ lint ของภาษาอื่นที่เป็นนามสกุล .xml หรือ .txt แล้ว ตัวที่อ่านไฟล์ report ของเราแล้วนำไป Comment ใน PR ให้เราก็มีชื่อว่าเจ้า danger.system ก่อนจะไปดูขั้นตอนการตั้งค่ามาดูก่อนว่าเจ้า Danger ใช้กับ SCM (Source Code Management) และใช้กับ Continuous Integration (CI) ตัวไหนได้บ้าง

SCM ที่ danger.system support

ตัว Continuous Integration (CI) ที่ Danger ใช้งานได้ได้แก่

  1. Drone
  2. Semaphore
  3. CircleCI
  4. Surf
  5. Bitrise
  6. Codeship
  7. Xcode Server
  8. Team City
  9. Jenkins
  10. Travis
  11. VSTS
  12. Gitlab CI
  13. DotCI
  14. BuddyBuild
  15. BuildKite

ในบทความผมเลือกใช้ตัว SCM เป็น Github และตัว CI ก็เป็นเจ้า CircleCI นะครับ เหตุผลคุ้นมือดี ฮ่า ฮ่า ฮ่า

ส่วนของขั้นตอนการตั้งค่าเจ้า Danger ก็จะมีอยู่ 5 ด้วยกันขั้นตอนดังนี้

Step ที่ 1 : ทำการเอาเจ้า Danger เข้าสู่โปรเจ็คโดยจะมีด้วยกันอยู่ 2 ท่า คือ Include ผ่าน Ruby หรือ Java Script ผมขอใช้ท่าที่ทำผ่าน Ruby ละกัน ซึ่งเราต้องทำการสร้างไฟล์ที่ชื่อว่า Gemfile ในระดับ root มาไว้ในโปรเจ็คเพื่อทำการติดตั้งเจ้า Danger ก็จะมีคำสั่ง ดั้งนี้

บรรดทัดที่ 4 คือ ตัว Plugin ของ Danger ที่จะเอาไว้ทำการอ่านไฟล์ report ของ ktlint เพื่อทำการเอาไป Comment แบบ Inline Code ได้ถูกต้องนั่นเอง

Step ที่ 2: ทำการสร้างไฟล์ที่ชื่อว่า Dangerfile ขึ้นมาเพื่อกำหนดกฎเกณฑ์อะไรบางอย่างเกี่ยวกับตัว PR (Pull Request) และทำการเรียกใช้ Plugin ต่างๆ ที่เราได้ทำการกำหนดให้ติดตั้งในไฟล์ Gemfile ก็จะมีลักษณะดังนี้

มารู้จักคำสั่งของแต่ละบรรทัดกันแบบพอสังเขป สักหน่อยไปเลย

บรรทัดที่ 2 : จะทำการละเว้นการ Comment Code ที่อยู่นอกช่วงของ diff ของการ PR (Pull Request) นั่นเอง

บรรทัดที่ 5: จะเป็นการ Comment บอกใน PR ว่าตอนนี้อยู่ในสถานะ Work in Progress อยู่น่ะ ซึ่งคำสั่งนี้จะทำงานก็ต่อเมื่อเราทำการใส่ข้อความที่ Tilte ของ PR ที่มีคำว่า “[WIP] หรือ WIP ”

บรรทัดที่ 8-11: จะเป็นการ Comment บอกว่า PR นี้อยู่ในระดับไหน ซึ่งจะตรวจสอบจากจำนวนบรรทัดของโค้ดในการ PR เข้ามาซึ่งการกำหนดจำนวนของบรรทัดโค้ดก็ต้องขึ้นอยู่กับทีมนะครับ เพราะนี้เป็นเพียงแค่ตัวอย่างเฉยๆ

บรรทัดที่ 14–15: จะเป็นการเรียกใช้ Plugin ที่ชื่อว่า danger-checkstyle_format ที่ผมได้กำหนดไว้ในไฟล์ที่ชื่อว่า Gemfile ซึ่งจะทำการบอก path ของไฟล์ Report ของ Ktlint เพื่อที่จะให้ไป Comment ใน PR

Step ที่ 3: [Optional] ทำการสร้าง Account Github ขึ้นมาตัวหนึ่งเพื่อทำเป็น Bot Comment ใน PR ให้เรานะครับ หรือเราจะใช้ Account ของเราเองก็ได้นะครับตัวอย่างในบทความจะใช้ Account ที่มีอยู่แล้วนะครับ

Step ที่ 4: ทำการสร้าง Access Token ของ Github ของเรา และเมื่อได้ทำการสร้างเสร็จก็ให้เก็บเจ้า token ที่ได้ไว้ก่อนนะครับ เพราะว่าเราต้องนำเอา token มากำหนดค่าให้กับตัวแปรที่ชื่อว่า DANGER_GITHUB_API_TOKEN ใน Environment Variables ของ CI ที่เราใช้นะครับ

Step ที่ 5: ทำการตั้งค่า CircleCI ให้สามารถสั่งให้เจ้า Danger ทำงาน และทำการไปกำหนดตัวแปรที่ชื่อว่า DANGER_GITHUB_API_TOKEN ( วิธีการสร้าง env ของ CircleCi ) จากนั่นก็ให้ทำการสร้างไฟล์ที่ชื่อว่า circle.yml ในระดับ root ของโปรเจ็คของเราจะมีหน้าตาประมาณนี้

ว่าด้วยเรื่องของการตั้งค่าของ CircleCI กับ Github นั้นทำอย่างไรในบทความนี้ผมขอข้ามไปก่อนนะครับ เพราะแค่นี้บทความก็ยาวมากแล้ว เอาไว้จะทำบทความในการตั้งค่าของ CircleCI อีกทีนะครับแต่หลักๆ แล้วก็คือทำการติดตั้ง Environment เพื่อทำ การ build app android และ ทำการติดตั้ง Ruby ก่อนจะทำการติดตั้ง Package ที่อยู่ในไฟล์ Gemfile ของเรา

และเมื่อคำสั่งทุกอย่างผ่านเสร็จเรียบร้อยแล้วเราก็จะได้ไฟล์ Report ของ Ktlint มาจากนั้นก็สั่งให้เจ้า Danger ทำงานโดยผ่านคำสั่งที่ชื่อว่า bundle exec danger จากนั้นมันก็จะทำการเข้าไปอ่านคำสั่งจากไฟล์ Dangerfile ของเรานั่นเอง

ต่อไปก็ให้ทำการ push code ขึ้นไปยัง Repository ด้วยนะครับ กลัวผู้ที่หลงเข้ามาอ่านลืมเอิ่มม… แต่ต้อง push ไปที่ barnch อื่นนะครับ ที่ไม่ใช่สายงานหลักนะครับหมายความว่าต้องมี branch หลักอยู่แล้วซึ่งจะมีแค่ไฟล์ README.md อย่างเดียวก็ได้นะไม่ว่ากัน

มาถึงขั้นตอนสุดท้าย จริงๆๆ ล่ะ ครับท่านผู้ชม ให้ทำการลอง PR (Pull Request) เข้าไปใน branch หลักของท่านยกตัวอย่างเช่น

จากนั้นก็รอจนกว่า CI ของเราจะเป็นสีเขียว ตามภาพด้านล่างนี้

เห้ย… มี Warnings อะไรฟ่ะ อย่าเพิ่งตกใจไปนะครับ เพราะถ้าหากทำถูกต้องหมด
ทุกอย่างก็จะเห็นว่ามี Comment Code ขึ้นมาโดยอัตโนมัติซึ่งแจ้งตาม Error จาก Ktlint ของเราเลย OMFG!!! ดังภาพด้านล่างนะครับ

ก็ถือว่าเป็นอันเสร็จสิ้นพิธีกรรมการตั้งค่าการทำ Automate Code Review กันเป็นที่เรียบร้อยแล้วนะครับ และถ้าหากผู้ที่หลงเข้ามาอ่านยัง งง อยู่ว่าเจ้า Danger มันคืออะไร ทำงานยังไง มีข้อจำกัดอะไรบ้าง และมี Plugins อะไรให้เราเล่นบ้างก็สามารถเข้าไปอ่านเพิ่มเติมจากด้านล่างได้เลย (กลัวบทความจะยาวเกิน ขอโทษด้วยครัช)

แถม… สามารถเข้าไปดูตัวอย่างของผมได้จาก Repository ด้านล่างนี้ได้เลยนะครัช

สรุป

จากการได้ลองนำเอาไปใช้กับโปรเจ็คจริงที่เป็นโปรเจ็คเล็กๆแล้ว ส่วนตัวเลยคิดว่าเจ้า Danger นั้นเข้ามาช่วยลดเวลาในการ Review Code ลงไปพอสมควรทำให้คนตรวจสอบสามารถไปโฟกัสโค้ดที่เป็น Business Logic ได้มากขึ้น แต่ก็อย่างว่านะมันแค่ Format ของโค้ดถ้าเราทำตั้งแต่ระหว่างที่เราพัฒนาไปด้วย ก็จะช่วยลดความเสี่ยงลงไปพอสมควรเลยทีเดียว

แต่มันก็ไม่ได้มีเพียงแค่การจัดโค้ดให้ดูสวยงามอย่างเดียวนะ เพราะเราสามารถนำไปประยุกต์ใช้กับการทำ Code Analysis ได้อีกด้วย เช่น การตั้งค่า threshold ความซับซ้อนของฟังก์ชัน รวมไปถึง regex ของการตั้งชื่อตัวแปร และคลาสเป็นต้น แล้วให้เจ้า Danger ไป Automate Code Review ให้เรา เดี๋ยวค่อยไปเจอกันในบทความถัดไปแล้วกัน ก็ขอลากันไปก่อนหวังว่าบทความนี้จะเป็นประโยชน์ไม่มากก็น้อยนะครับ 🙏

Happy Checking 🤙

--

--