Skip to main content

Auto Code Review (Danger)

Code review

là một quy trình bắt buộc trong qui trình phát triển phần mềm chuyên nghiệp. Mục tiêu quan trọng nhất của code review là nâng cao code quality của dự án. Tuy nhiên đối với những team làm outsource hoặc khi tính chất của dự án “quick win” với deadline oriented. Thông thường cách tiếp cận của team trong code review chỉ là apply một số rule về coding convention và coding style để cho dự án chạy. Lý do thường thấy nhất đó là reviewer thường phàn nàn không có đủ thời gian để làm review một cách chuẩn chỉnh và qui củ, hơn nữa việc bỏ sót lỗi trong quá trình review là khó tránh khỏi (human mistake). Hoàn toàn hợp lý tuy nhiên chúng ta có thể có một cách tiếp cận tốt hơn bằng cách delegate việc review code style, code convention, và kết quả static analysis tool cho code review bot (Danger). Bằng cách này chúng ta giải quyết được 3 vấn đề chính:

  1. Reviewer chỉ cần focus vào review business logic, cái này giá trị hơn rất nhiều so với code style và code convention cũng như static analysis
  2. Độ chính xác cao, tất cả mọi quy trình đều được thực hiện một cách tự động
  3. Bot thực thi việc review và make comment trực tiếp vào pull request, giúp cho developer dễ dàng nhận biết và sửa lỗi hơn, tăng thời gian developement

Danger

Danger là một gem thông thường được exec vào giai đoạn cuối của CI, dựa trên kết quả của CI để automating code review
  • Danger runs during your CI process, and gives teams the chance to automate common code review chores.
  • This provides another logical step in your build, through this Danger can help lint your rote tasks in daily code review.
  • You can use Danger to codify your team’s norms. Leaving humans to think about harder problems.
  • She does this by leaving messages inside your PRs based on rules that you create with the Ruby scripting language.
  • Over time, as rules are adhered to, the message is amended to reflect the current state of the code review.

Setup

Gemfile

  1. Cài đặt bundler: $ gem install bundler
  2. Run bundle init để tạo Gemfile
  3. Add gem 'danger' vào Gemfile
  4. Một số gem cần thiết cho việc integrate static analysis tool
  5. gem 'danger-android_lint'
    gem 'danger-findbugs'
    gem 'danger-checkstyle_format'

Setup danger

Run bundle exec danger init để cài đặt.
Đây là một interactive command line sẽ thông qua giao diện console hướng dẫn các bạn các bước cần thiết phải thực hiện để cài đặt danger. Quá trình này khá đơn giản, được hướng dẫn chi tiết thông qua các comments và bao gồm những bước dưới đây
We need to do the following:
- [ ] Create a Dangerfile and add a few simple rules.
- [ ] Create a GitHub account for Danger to use, for messaging.
- [ ] Set up an access token for Danger.
- [ ] Set up Danger to run on your CI.

Integrate with CI (CircleCI)

Các bước ở trên khá rõ ràng để thực thi (nếu có vấn đề gì xin vui lòng comment bên dưới mình sẽ support cụ thể). Mình xin chỉ focus vào việc làm thế nào để integrate danger vào CI, về cơ bản Danger chạy trên kết quả của CI nên mình nghĩ đây là phần quan trọng và có giá trị nhất của Danger. CI mình sử dụng ở đây là CircleCI.
Hiện tại CircleCI 2.0 sử dụng Docker cho việt setup nên việc cài đặt là cực kì dễ dàng các bạn có thể tham khảo ở đây: https://circleci.com/docs/2.0/language-android/
Sau khi cài đặt CircleCI bước tiếp theo là làm thế nào để CircleCI có thể exec được danger. 

Config CircleCI

  1. Chúng ta cấu hình CircleCI "only build pull request" để giảm thiếu việc execute CI ko cần thiết, khi chưa hoàn thành feature. 
  2. Advanced Settings > Only build pull requests
  3. Token setup
  4. Project > Settings > Permissions > API Permissions> Create Token with scope "all" and a label like "DANGER_CIRCLE_CI_API_TOKEN".
    
    Project > Settings > Build Settings > Environment Variables. Add the token as a CircleCI environment variable, which exposes it to the Danger process

Integrate static analysis tool

ktlint

  1. Tạo file ktlint.gradle trong thư mục gradle với nội dung như sau
  2. Apply to app build.gradle (Module: app) apply from: '../gradle/ktlint.gradle'
  3. Config Ktlint in Dangerfile 
    # ktlint 
    github.dismiss_out_of_range_messages 
    checkstyle_format.base_path = Dir.pwd 
    checkstyle_format.report 'app/build/reports/ktlint/ktlint-checkstyle-report.xml'
    1. Config CircleCI để chạy ktlint gradle task (danger use report from ktlint)
      - run:
          name: Ktlint
          command: ./gradlew ktlint

    Detekt

    1. Add apply plugin: "io.gitlab.arturbosch.detekt" to build.gradle(Module: app)
    2. Config Dangerfile để nhận report từ detekt
      # detekt 
      checkstyle_format.base_path = Dir.pwd 
      checkstyle_format.report 'app/build/reports/detekt/detekt-checkstyle.xml'
    3. Config CircleCI để chạy detekt gradle task 
      - run:
          name: Detedanger-checkstyle_formatKt
          command: ./gradlew detektCheck

    Findbugs

    1. Tạo file findbugs.gradle trong thư mục gradle với nội dung như sau
    2. Add apply from: '../gradle/findbugs.gradle' to build.gradle(Module:app)
    3. Cấu hình Dangerfile cho findbugs 
      # Findbugs
      checkstyle_format.base_path = Dir.pwd 
      checkstyle_format.report 'app/build/reports/findbugs/findbugs.xml'
    4. Config CircleCI để chạy findbugs 
      - run:
          name: Findbugs
          command: ./gradlew findbugs

    Config to Run danger in CircleCI

    - run:
        name: Bundle Install
        command: bundle check || bundle install
    - run: bundle exec danger --verbose
    - store_artifacts:
        path: "app/build/reports"

    Result

    Comments

    Popular posts from this blog

    Follow Law of Demeter!

    Việc code bẩn code rác là khá phổ biến đối với lập trình viên, mà để thay đổi nó chúng ta cần phải có thời gian luyện tập, mình sẽ thông qua series các bài viết chia sẻ kinh nghiệm việc mình luyện tập và apply việc refactor code làm cho code đẹp hơn. (Trong series này mình sẽ sử dụng ngôn ngữ Ruby để làm ví dụ) Ở phần 1 này mình sẽ đi vào nguyên lý đầu tiên  Follow Law of Demeter . Để hiểu xem cụ thể Low of Demeter (LoD) là gì chúng ta sẽ đi vào một ví dụ cụ thể. Giả sử chúng ta có 3 class là Address, Customer và Order class Address < ActiveRecord :: Base belongs_to: customer end class Customer < ActiveRecord :: Base has_one: address has_many: orders end class Order < ActiveRecord :: Base belongs_to: customer end Vì  Ruby  cho phép chúng ta thông qua quan hệ của các đối tượng để truy cập đến các thuộc tính và phương thức của những đối tượng liên quan. Để hiển thị địa chỉ của khách hàng cho 1 đơn hàng, chúng ta thông thường sẽ xử lý

    Testing like a boss

    Manual mobile app testing là một công việc không hề dễ dàng, nó đòi hỏi QA/Tester phải giành nhiều thời gian và công sức để có thể verify/qualify được hết tất cả các test case. Đặc biệt khi những yêu cầu như pixel perfect hay khi dữ liệu được combine từ nhiều nguồn khác nhau (API/Cache/Local Database/Sharepreferences), thì thời gian mà QA/Tester bỏ ra để có thể đánh giá được chính xác "development progress" là ko hề nhỏ. Tôi có thể kể ra một số câu hỏi thường gặp khi manual testing mobile app  1. Liệu 2 màu ( ▲ )( ▲ )   (implementation/specs) có thực sự giống nhau? Hãy chỉ ra mã màu của chúng? 2. Textsize là bao nhiêu? Typeface là gì? TextColor, HintColor giá trị như thế nào? Làm sao để trả lời đã tuân theo design specs hay chưa? 3. Khoảng cách giữa 2 view là bao nhiêu pixel? Có đúng specs ko? 4. Làm sao có thể biết được trong một màn hình, dữ liệu lấy từ đâu? (API/Cache/Local Database/Sharepreferences) 5. Làm sao có thể xoá local storage khi cần thiết? 6. Kiể