2015/06/29

Scrum vs Kanban

Kanban vs Scrum 簡要說明並比較 scrum 以及 kanban,雖然兩者都屬於 agile managment 的方法,但在自由度的精神上,還是有些差異。一個 agile 團隊不會照單全收某個方法的所有工作指引,而是在透過討論與實際的驗證,決定該怎麼進行團隊管理,本文的作者認為可以整合 kanban 與 scrum 方法,調整為自己的團隊專屬的專案管理方法。

中文版 比較Kanban和Scrum

scrum

  1. 將所有成員分為數個 small, cross-functional, self-organizing teams
  2. 將整個專案切割為數個 small, concrete deliverables,並以 priority 以及預估的 effort 排序
  3. 將時間切割為 short fixed-length iterations (通常是 1~4 週),每一次 iteration 都能產出可 demo 可釋出的 code
  4. 持續跟客戶review release plan 並更新工作的優先順序,基本是以每一次 iteration 結束 release 的產出目標為基準。
  5. 每一次 iteration 之後,都要再 optimize process

kanban

  1. 將 workflow 以圖表視覺化
    切割工作項目,寫在卡片並貼在牆上
    在 workflow 中為每個工作 columns 命名工作階段
  2. 限制 WIP(work in progress),明確地限制每一個 workflow state 的 WIP 上限
  3. 估算 lead time(完成一個 item 需要的平均時間,也稱為 cycle time),持續改善 process 直到可以正確地估算 lead time

Agile 自由度

以下的圖表,將幾個管理方法放在 agile 自由度的光譜上度量,流程越複雜,細節越繁瑣的管理方法在左邊,輕量化,以軟體產出為主要目標,讓團隊更專注在專案開發上,減少專案管理 effort 的管理方法在右邊。

換句話說,Agile 就是讓團隊成員越自由,老闆不需要管什麼,就能自動把專案跟事情做好,但這應該只是理想,人與人之間還是需要一些溝通與資訊交換,才能確保軟體功能實作時,內部的資料邏輯與精神是一致的。

focus vs interrupts, repeatable vs exploratory innovation

Scrum 與 Kanban應用環境 文章中提到Scrum or Kanban? YES! 提出的一個比較的圖表。

二維的圖表可區分為五個區塊

  1. focus - innovation
    scrum
    同時需要專注在創新以及專案開發,並維持持續交付 deliverables
  2. focus - repeatable
    production line kanban
    例如生產線作業員、產品量產階段
  3. interrupts - innovation
    混合使用 scrum 與 kanban
  4. interrupts - repeatable
    support kanban
    例如客服中心、公司內部的 MIS,需要團隊持續維護,並作些微的調整與修改
  5. 中間
    kanban

類似的地方

  1. 都是符合 lean and agile 精神的管理方法
  2. 都使用 pull scheduling
  3. 都有限制 WIP (work in progress)
  4. 都利用 transparency 透明化來改善工作流程
  5. 都著重於儘早及經常交付可出貨的軟體
  6. 都是給 self-organizing team 使用
  7. 都要求把工作拆解成更小的工作細項
  8. 發佈計畫是根據資料(速度/前置時間)來持續優化

不同的地方

Scrum Kanban
timeboxed iterations prescribed (預先定義 itertation 的時間) timebox iterations optional (可區分 planning, release, process improvement 階段,且可以 event-driven 取代 timeboxed)
團隊 commits 每個 iteration 交付的工作量 commitment optional
velocity 生產率 作為流程改善與計畫的 metric Lead Time 生產週期 作為流程改善與計畫的 metric
cross-functional teams cross-functional teams optional 允許有 specialist teams
工作必須 break down 至 1 sprint 可完成的份量 沒有特定的 item size
burndown chart prescribed 沒有特定的 diagram
間接限制每個 sprint 的 WIP 直接限制每個 workflow state 的 WIP
estimation prescribed estimation optional
不能在進行中的 iteration 增加 item 只要團隊容量允許,就可以增加 item
由一個特定團隊維護 sprint backlog 數個團隊或多人共享一個 kanban board
有三個角色 PO/SM/Team 沒有預定的角色
sprint 結束後就重設 scrum board kanban board 是永久長存的 
預先定義 prioritized product backlog prioritization is optional

Reference

Scrum vs. Kanban:軟件開發新方法大比拚

Scrum 和 Kanban 的比較

從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup

硝煙中的Scrum和XP

看板管理

Kanban, Flow and Cadence

看板和Scrum——相得益彰

Kanban vs Scrum

Intro to Kanban in Under 5 Minutes (What is Kanban, Learn Kanban)

Scrum和Kanban比較的結論

2015/06/22

Introduction to Play Framework

Introduction to Play Framework for Scala developers 這個影片,由建立 Play Framework 專案開始,解釋初始專案的內容,在 trace 的過程中,連帶將如何使用 Play Framework 的概念一併提供給讀者。

啟動 play framework web server

在「命令提示字元」裡,切換到 scala-play 的目錄,然後鍵入指令 activator run ,就能啟動 play framework web server。瀏覽器瀏覽網頁 http://localhost:9000/ 就可以看到 play framework 的測試網頁。

網站首頁

  1. 首先我們先看 conf/routes 這個設定檔,這裡面針對 / 這個 URI,設定是由 controllers.Application 這個類別的 index 這個 method 負責處理。

    設定檔 /conf/routes

     ## Home page
     GET     /                           controllers.Application.index
    

    在 app/controllers/Application.scala 這個 controller 中,會看到處理 index 的 Action

     package controllers
    
     import play.api._
     import play.api.mvc._
    
     class Application extends Controller {
    
       def index = Action {
         Ok(views.html.index("Your new application is ready."))
       }
    
     }
    

    瀏覽器首頁最上面的 "Your new application is ready." 文字,就是從這裡列印到網頁中的,但實際上,Ok 裡面還是呼叫了 view template 的程式,後面的部份是傳送給 view template 的文字參數。

    在 play framework web server 啟動的狀態下,如果我們修改了 app/controllers/Application.scala 的內容,網頁會自動重新編譯,並輸出到瀏覽器上。同樣地,當原始程式編譯產生錯誤時,網頁也會自動顯示錯誤點,而且未來在實際上線時,可以將顯示錯誤點網頁的功能關閉。

  2. view template
    app/views/index.scala.html 最前面的 message 是收到的參數內容,也就是上一個步驟傳送進來的 "Your new application is ready.",接下來的 template 引用了兩個參數,並傳送至 app/views/main.scala.html。

    play20.welcome 是一個內建在 play framework 的 template ,裡面是 play framework 的 document 網頁。

     @(message: String)
    
     @main("Welcome to Play") {
    
         @play20.welcome(message)
    
     }
    

    app/views/main.scala.html 的一開始,定義了兩個參數,分別是 title 以及content html。

     @(title: String)(content: Html)
    
     <!DOCTYPE html>
    
     <html lang="en">
         <head>
             <title>@title</title>
             <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
             <link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
             <script src="@routes.Assets.versioned("javascripts/hello.js")" type="text/javascript"></script>
         </head>
         <body>
             @content
         </body>
     </html>
    

    將 app/views/index.scala.html 裡面的 @play20.welcome(message) 改為 @message,瀏覽器上就只會剩下 "Your new application is ready." 的文字列印在畫面上。

     @(message: String)
    
     @main("Welcome to Play") {
         <!-- @play20.welcome(message) -->
         @message
     }
    

如何測試 play framework

test/ApplicationSpec.scala 是直接發送 http request,然後以 http response code 確認是否正常。

    import org.specs2.mutable._
    import org.specs2.runner._
    import org.junit.runner._

    import play.api.test._
    import play.api.test.Helpers._

    /**
     * Add your spec here.
     * You can mock out a whole application including requests, plugins etc.
     * For more information, consult the wiki.
     */
    @RunWith(classOf[JUnitRunner])
    class ApplicationSpec extends Specification {

      "Application" should {

        "send 404 on a bad request" in new WithApplication{
          route(FakeRequest(GET, "/boum")) must beSome.which (status(_) == NOT_FOUND)
        }

        "render the index page" in new WithApplication{
          val home = route(FakeRequest(GET, "/")).get

          status(home) must equalTo(OK)
          contentType(home) must beSome.which(_ == "text/html")
          contentAsString(home) must contain ("Your new application is ready.")
        }
      }
    }

利用 browser 測試網站

    import org.specs2.mutable._
    import org.specs2.runner._
    import org.junit.runner._

    import play.api.test._
    import play.api.test.Helpers._

    /**
     * add your integration spec here.
     * An integration test will fire up a whole play application in a real (or headless) browser
     */
    @RunWith(classOf[JUnitRunner])
    class IntegrationSpec extends Specification {

      "Application" should {

        "work from within a browser" in new WithBrowser {

          browser.goTo("http://localhost:" + port)

          browser.pageSource must contain("Your new application is ready.")
        }
      }
    }

打開一個新的 「命令提示字元」,切換到 project 目錄,輸入 activator test

> activator test
[info] Loading global plugins from C:\Users\yaocl\.sbt\0.13\plugins
[info] Loading project definition from D:\projectcase\trunk3\play-scala-intro\project
[info] Set current project to play-scala-intro (in build file:/D:/projectcase/trunk3/play-scala-intro/)
[info] Compiling 2 Scala sources to D:\projectcase\trunk3\play-scala-intro\targe
t\scala-2.11\test-classes...
[info]
[info] IntegrationSpec
[info]
[info] Application should
[info] - play.api.libs.concurrent.ActorSystemProvider - Starting application default Akka system: application
[info] - play.api.libs.concurrent.ActorSystemProvider - Shutdown application default Akka system: application
[info]   + work from within a browser
[info]
[info] Total for specification IntegrationSpec
[info] Finished in 14 seconds, 734 ms
[info] 1 example, 0 failure, 0 error
[info]
[info] ApplicationSpec
[info]
[info] Application should
[info] - play.api.libs.concurrent.ActorSystemProvider - Starting application default Akka system: application
[info] - play.api.libs.concurrent.ActorSystemProvider - Shutdown application default Akka system: application
[info]   + send 404 on a bad request
[info] - play.api.libs.concurrent.ActorSystemProvider - Starting application default Akka system: application
[info] - play.api.libs.concurrent.ActorSystemProvider - Shutdown application default Akka system: application
[info]   + render the index page
[info]
[info] Total for specification ApplicationSpec
[info] Finished in 447 ms
[info] 2 examples, 0 failure, 0 error
[info]
[error] Failed: Total 3, Failed 0, Errors 0, Passed 3
[error] (test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 90 s, completed 2015/6/11 下午 01:53:07

如果測試時發生錯誤,修正程式後,可直接執行 "activator test-quick" 快速重新測試 failed tests

Data Persistence

在測試影片中說明的 sorm : scala 使用的 ORM framework,一直發生一些問題,在 play framework issue #4342中提到,sorm 原本是以 scala 2.10 編譯的,可能因此沒能正常地支援 2.11,最後建議嘗試使用 Anorm 或是 Slick

根據上述文章的建議,我們就測試了 Anorm 的方案。

activator computer-database-scala 的 project template 設定過程如下:

  1. activate new play-scala-db computer-database-scala
    以 computer-database-scala 這個 template 建立一個新專案 play-scala-db

  2. cd play-scala-db
    切換到 play-scala-db 目錄

  3. activator eclipse
    建立 eclipse project settings

  4. activator run
    啟動 play-scala-db project

  5. 瀏覽器連結到 http://localhost:9000/ 可看到以下的畫面

這個 project template 是個傳統的 CRUD 頁面,Model 利用 Anorm 存取 DB,有使用 twitter bootsctrap 產出頁面以及分頁功能。project 設定檔 conf/application.conf 裡面預設是使用 h2 memory database。

2015/06/15

如何建置 scala, play framework 的開發環境

傳統的 Java Web Project 也就是 Java EE (Enterprise Environment) ,其中包含了 JSP/Servlet以及 EJB,後來在肥大的 EJB 失敗後,網頁專案開始 POJO (Plain Old Java Object) 化,就是盡可能地不做太多的物件封裝,這個階段,產生了很多的網頁 MVC framework,而 play framework 是以 scala 與 java 撰寫的 web application framework,他的本質也是提供一種 MVC 的框架,但實質上,他還承襲了 scala 非同步的特性,提高了網頁服務的可用性,他也更進一步地完全跳脫了 Java EE 的網頁標準,我們要做的不再是 JSP 以及 Servlet。

構建可伸縮系統 Scala vs Java 這篇文章,以 Java/Tomcat 與 Scala/Play 這兩種 web framework,建立了簡單的購物 web project,並以 JMeter 進行效能的量測,從該文章的結論中我們得知,當系統在穩定運作的過程中,兩個 framework 的效能表現並沒有什麼差異,而當預先定義的 search 後端服務發生問題時,尤其是使用 proxy 連接到 seach service 時,網站的其他功能例如 Payment、瀏覽目錄的網頁也同時受到影響。但是用 Scala 建置的 service 可在 search 發生問題時,不影響到其他的服務項目。原因是因為 Scala 天生的非同步特性,讓 Programmer 能很自然地寫出非同步 IO 處理的程式碼,如果要使用 Java 達到同樣的功能,也能夠做到,但是我們會發現很多不自然的 callback 程式碼,programmer 需要耗費大量心力,去維護非同步的程式碼。

play framework wiki 中,提到了一些使用 Play framework 的 reference sides,例如比較有名氣的 Linkedin、Coursera。

要建置 play framework 的開發環境,需要安裝下列的工具

  1. JDK 8
    到 Oracle 下載 JDK並安裝,安裝後設定環境變數
     JAVA_HOME=C:\java\jdk1.8.0_45
     PATH=%JAVA_HOME%\bin;%PATH%
    
  2. scala 2.11.6
    下載 scala-2.11.6.msi 並安裝,安裝後設定環境變數
     PATH=C:\java\scala\bin;%PATH%
    
  3. sbt 0.13.8
    下載 sbt-0.13.8.msi 並安裝,安裝後設定環境變數
     SBT_HOME=C:\java\sbt
     PATH=%SBT_HOME%\bin;%PATH%
    
  4. Eclipse Luna + WTP

  5. Scala IDE 4 + Play Support in Scala IDE
    在 Eclipse 的 Help -> Install New Software 增加一個網址 Scala IDE - http://download.scala-ide.org/sdk/lithium/e44/scala211/stable/site ,然後就能安裝 Scala IDE 與 Play Support。

  6. Play Framework Activator
    typesafe-activator-1.3.2-minimal.zip

     PLAY_HOME=C:\java\activator-1.3.2-minimal
     PATH=%PLAY_HOME%\bin;%PATH%
    

要建立一個 scala play project 可以遵循以下的步驟

  1. 啟動「命令提示字元」切換到 eclipse workspace 的資料夾,鍵入指令 activator new
    因為運作環境是使用類似 maven 的 ivy2,第一次執行會等很久,等到 script 把 jar 都存到 C:\Users{user.home}.ivy2\cache 的目錄中。
    第二次執行 activator new 之後,就不需要再等待下載 jar 了,在 script 裡面選擇 6,就會建立 play-scala project template,然後輸入 play-scala 作為 project folder 的名稱。
    ```
    D:\projectcase\trunk3>activator new

Fetching the latest list of templates...

Browse the list of templates: http://typesafe.com/activator/templates
Choose from these featured templates or enter a template name:
1) minimal-akka-java-seed
2) minimal-akka-scala-seed
3) minimal-java
4) minimal-scala
5) play-java
6) play-scala
(hit tab to see a list of all templates)

6
Enter a name for your application (just press enter for 'play-scala')
play-scala
OK, application "play-scala" is being created using the "play-scala" template.

To run "play-scala" from the command line, "cd play-scala" then:
D:\projectcase\trunk3\play-scala/activator run

To run the test for "play-scala" from the command line, "cd play-scala" then:
D:\projectcase\trunk3\play-scala/activator test

To run the Activator UI for "play-scala" from the command line, "cd play-scala"
then:
D:\projectcase\trunk3\play-scala/activator ui

```
  1. 建立 eclipse project settings
    切換到 play-scala project 目錄中,然後利用 sbt 建立 eclipse project settings

    D:\projectcase\trunk3\play-scala>sbt eclipse
    [info] Loading global plugins from C:\Users\{user.home}\.sbt\0.13\plugins
    [info] Updating {file:/C:/Users/{user.home}/.sbt/0.13/plugins/}global-plugins...
    [info] Resolving org.scala-sbt.ivy#ivy;2.3.0-sbt-fccfbd44c9f64523b61398a0155784d
    [info] Resolving org.fusesource.jansi#jansi;1.4 ...
    [info] Done updating.
    [info] Loading project definition from D:\projectcase\trunk3\play-scala\project
    [info] Updating {file:/D:/projectcase/trunk3/play-scala/project/}play-scala-buil
    d...
    [info] Resolving org.scala-sbt.ivy#ivy;2.3.0-sbt-fccfbd44c9f64523b61398a0155784d
    [info] Resolving org.fusesource.jansi#jansi;1.4 ...
    [info] Done updating.
    [info] Set current project to play-scala (in build file:/D:/projectcase/trunk3/p
    lay-scala/)
    [info] About to create Eclipse project files for your project(s).
    [info] Updating {file:/D:/projectcase/trunk3/play-scala/}root...
    [info] Resolving com.fasterxml.jackson.datatype#jackson-datatype-jsr310;2.5.3 ..
    [info] Resolving jline#jline;2.12.1 ...
    [info] Done updating.
    [info] Successfully created Eclipse project files for project(s):
    [info] play-scala
    
  2. 打開 Eclipse ,以 Import Existing Project 的方式,將 play-scala import 到 workspace 中

  3. 在剛剛的「命令提示字元」裡,切換到 scala-play 的目錄,然後鍵入指令 activator run ,就能啟動 play framework web server
    ```
    D:\projectcase\trunk3\play-scala>activator run
    [info] Loading global plugins from C:\Users{user.home}.sbt\0.13\plugins
    [info] Updating {file:/C:/Users/{user.home}/.sbt/0.13/plugins/}global-plugins...
    [info] Resolving org.scala-sbt.ivy#ivy;2.3.0-sbt-fccfbd44c9f64523b61398a0155784d
    [info] Resolving org.fusesource.jansi#jansi;1.4 ...
    [info] Done updating.
    [info] Loading project definition from D:\projectcase\trunk3\play-scala\pr
    oject
    [info] Updating {file:/D:/projectcase/trunk3/play-scala/project/}play-scal
    a-intro-build...
    [info] Resolving org.scala-sbt.ivy#ivy;2.3.0-sbt-fccfbd44c9f64523b61398a0155784d
    [info] Resolving org.fusesource.jansi#jansi;1.4 ...
    [info] Done updating.
    [info] Set current project to play-scala (in build file:/D:/projectcase/tr
    unk3/play-scala/)

--- (Running the application, auto-reloading is enabled) ---

[info] p.a.l.c.ActorSystemProvider - Starting application default Akka system: a
pplication
[info] p.c.s.NettyServer$ - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)
```

  1. 瀏覽器瀏覽網頁 http://localhost:9000/ 就可以看到 play framework 的測試網頁

2015/06/08

Perspectives On Agile Software Testing 展望敏捷軟件測試

ThoughtWorks 在 selenium 誕生十週年的時候,發布了一份 56 頁的文件 ebook: Perspectives On Agile Software Testing,除了因為 webdriver 的自動化解決了網頁測試的問題,重要的是 Open Source 的策略,讓 selenium 有無可取代的地位。

Test Pyramid

測試金字塔 TestPyramid 是 Martin Fowler 提出的測試架構,他認為測試應該由底層的程式元件 Unit,到 Service Level,最後是 UI 測試,像金字塔一樣由基礎往上堆疊。

糟糕的測試模式,是像冰淇淋 ice-cream cone 一樣,太過於重視 UI,End User 測試,忽略了底層的 Unit Test,這也是一般的軟體專案最常見到的狀況。

另一種 ani-pattern 是開發跟 QA 單位兩個單位平行運作,這會造成 Service Level 的重複測試,以及 UI 測試混亂的狀況。

ThoughtWorks 認為 Test Pyramid 應該是像這樣的圖一樣,上下夾擊的測試模式,但這必須讓開發與QA團隊,兩個單位能夠充分合作的條件下,才能完美執行的測試策略。

Agile Tester 的工作能力

  1. Business dimension
    要有良好的溝通能力,能從客戶端取得與業務問題最重要相關的測試重點。要知道如何產出能讓客戶接受專案產出結果的測試項目。
  2. Technical dimension
    測試者必須要有良好的技術背景,還要有良好的 programming skill,事實上,測試者跟開發者的基本程式設計的技能,應該是一致的。
  3. DevOps dimension
    測試者必須要有將日常測試自動化的能力,還要能整合各種不同的測試工具。

看到這邊,其實都是在談一個軟體團隊的最佳狀態,除了要有能力強大的工程師之外,還要有無所不知的測試員。但其實一般的團隊,並不一定都能有這樣的工作環境。

因為市場決定了產品,市場決定了專案的規模,還不能被證明是有市場的產品,沒辦法取得最佳的人力資源進行開發,更別說有個法力高強的測試員了,基本上,能配置測試員就已經是還算不錯的情況了,到最後如果產品賣得好,程式也已經做完了,該被測試出來的問題都已經解完了,然後會是下一個產品循環。

Behavior Driven Development BDD

關於 BDD,可以參考以下這些文章

  1. 行為驅動開發 wiki
  2. TDD vs. BDD

簡單地說,BDD 可說是專案 stakehodlers 使用的 TDD,強調用 domain language 撰寫,而非程式設計師實作的測試項目,這會讓測試者能以專案 domain 為焦點,撰寫業務相關的測試項目。

說真的,我並不熟悉 BDD 的實作方式,重點是這種測試的面向出現的時機,確實解決了專案使用者能夠進行自動測試,累積測試案例的一些問題,他們不在只是看著一大本測試案例文件,然後手動一項一項進行測試的測試員。

但要說 BDD 真的能完全取代人工測試的部份嗎?這個其實跟機器人是不是能取代人力應該是類似的問題,所有人都會回答:「不可能!」但能被取代的是無法跟著時代進步的人力,而不能被取代的,是可以更新自己的能力,操作這些新測試工具的人力。

但也要注意,BDD 測試因為多了一層自然語言的設計與解析,增加了開發的成本,在使用時必須要了解,BDD 雖然是 domain expert 的最佳測試與驗證的工具,但 BDD 還是需要程式設計師去實作翻譯與解析的程式,只要是程式都有可能會出錯,也會產生 bug。

Mobile Testing 要注意的事項

Mobile Web Testing

  1. Responsive web design
  2. Multiple Browsers
  3. Simulator/Emulator vs real devices
  4. single page or pageless design
    這跟 browser history 有關係,如果使用者點了上一頁,會不會造成問題
  5. Testing number of requests and data transfer
    確認 server 有沒有提供 js minification, gzipping, lazy loading 或使用 application cache for local storage,這些會影響 client 端能不能順暢地使用網頁
  6. Automation

Mobile Application Testing

  1. customer do not compromise on design
    測試者必須以代表真實使用者的感受,對 APP UI design 提供建議。
  2. Developement framework impact on testing
  3. Native vs hybrid approach
    APP 裡面有沒有包含 WebView 會影響實際使用上的感受。
  4. Device vs simulator dilemma
  5. Performance matters
  6. Information is power, how to get it?
    收集並分析使用者的使用狀況。
  7. Testing third party integration and location services
    整合 FB API 或是 Location Service API,開發時可用模擬的方式實做,但在真實的環境中測試,結果跟想像的可能大不相同。
  8. Test automation
  9. Continuous integration and build distribution
    自動且持續的整合與建構

創造力與測試

我們再來看一篇文章:創造力與測試:可否共存?,內容討論到 Agile Tester 該有的基本能力。

文章中提出了一個 Thinking Tester 的名詞,其代表的意義,就是更高等的測試員基本能力要求,從公司的角度來 說,我們該用更好的人力去進行測試模式的設計與開發,而 Agile 工作團隊,並沒有規劃單獨的測試人員,也就是說,我們需要能夠在功能實作與測試兩者能力都能兼具的工程師。

就一個成熟的軟體團隊來說,會有多個開發人員,系統在基本的開發人員自行測試驗證之後,就會進入第一個階段的整合,這時候,不同開發人員開發的功能模組就會有互相呼叫與搭配使用的情境。

或許我們可以讓工程師開發程式之後,互相交換進行功能測試,這種方式既可以避免工程師測試自己寫的程式產生了測試盲點,也可以運用另一個工程師實做程式的經驗與能力,進行系統驗證與測試。

文章中提到,傳統的測試工程師所作的事情,就是一再地重複與重複進行測試案例,在幾次的循環過後,慢慢地就會覺得工作能力遲滯,沒有進步,這也間接造成行政與管理團隊會認定,測試工程師的工作不需要過於高階的人力這樣的狀況。

該怎麼作,沒有絕對的對錯,要怎麼保證軟體品質,各有各的見解與方法,也只能慢慢地根據自己團隊的狀況調整策略與方法了。

Reference

書評 - 《展望敏捷軟件測試》

2015/06/01

放「乖乖」還不夠的服務維運管理

軟體系統服務的維運管理,在台灣最常見的,就是請到「乖乖大神」出面,因為一般伺服器都是透過燈號,來辨識主機的運作情形,綠燈代表正常,紅燈則是故障燈號,這是軟體系統維運人員某個不成文的信仰。

當線上的服務不正常地離線後,我們最常見到的答案就是「駭客攻擊」,因為類似的服務競爭對手很多,如果官方承認是內部管理不周,沒有忠誠度的客戶,或許就可能鳥獸散,或發生使用者集體位移的狀況,都可能會影響到公司的營運。

大概是被駭客攻擊的新聞太多了,使用者很習慣接受這樣的理由,甚至有可能連開發的工程師,在系統上線一段時間之後,再遇到自己系統當機的情況時,第一時間,也會認為自己的服務被攻擊了。

大家猜測,責任在駭客身上,這是再直接不過的事情了。就系統開發者來說,不管任何時候發生問題,絕對不能一開始就下定論,首先要檢查的是系統的 log,要想的是有沒有任何造成當機的原因。

還記得遠通 ETC 的事件嗎?回想一下這個新聞 政院踢爆 全因APP設計不良 eTag遭駭 攏係假 當時因為 ETC APP 上線後,瞬間過多 APP 向 Server 查詢餘額,造成系統的當機,而這瞬間過多的 server request,是 APP 設計不良造成的,而且由於 APP 還得經過兩週的審核程序才能更新,當時立委每天都得質詢修正的進度,相信不管是每一個承辦單位,都承擔了很多壓力。不過幸好 ETC 是個獨占事業,不管如何,他們都撐過了系統上線那一段混亂時期,現在已經進入了穩定的營運期。

5/28 發生了 中國最大的線上旅遊網站攜程網當機,疑遭駭客攻擊 的事件,而且到了晚上八點,系統都還沒有恢復正常。

系統掛點,第一時間收到的解釋,就是駭客攻擊。針對這個問題,由於沒有正式的官方說明,各方的臆測很多,可以看一下這些連結。

服務中斷、瘋傳數據庫遭刪除 攜程網堅稱數據庫安好

ezTravel 最大股東中國攜程網,系統疑似遭到內部物理刪除

攜程癱瘓續:藝龍旅行網也沒法訪問了

從攜程網的故障中我們應該反思什麼?

攜程網癱瘓超8小時,可能故障原因分析

深入解析和反思攜程宕機事件

看著這樣的事件,我們可以知道什麼,學到什麼?

  1. 線上服務最重要的是資料的完整性
    客戶最在意的,就是自己的權益,不管發生什麼事情,都必須要讓客戶的資料完整地復原回來,這或許不是賠錢就能解決的問題。

    實務上資料備份有三道防線,第一個是 HA,再來是異地備援,第三是磁帶備份,這三個部份都是分開管理的,基本上很難同時被刪除,但比較難達到的是系統還原的程序。

  2. 系統還原需要有演練的程序
    一般系統常常會因為成本的考量,而放棄了備援的機制,甚至有了備援,卻沒有測試環境可以進行系統還原的驗證,這一切都是機器與人力成本的問題,而同時又是很難合理說明的必要花費。

    磁帶備份只要有磁帶機就能作,但是誰能保證備分出來的資料,可以還原回去?用什麼方法還原回去?這是個謎!

  3. 維運人員要如何避免人為疏失
    要說駭客攻擊造成資料遺失很容易,但真正比較有可能發生的,是內部員工疏忽,造成系統資料被刪除。

    這是推動 DevOps 的最佳理由,讓維運作業,加上系統工程的管理,可以降低發生錯誤的機會。

  4. 線上服務的架構複雜
    現在的系統設計時,常會考慮到混搭的作法,最基本的資料庫選擇,就有 NoSQL 跟關聯式資料庫兩大派別。而且最麻煩的是,不同的系統有不同的優缺點,也因此在系統發展的過程中,各式各樣的程式語言,作業環境,常會出現混搭的狀況。

  5. 重構時,要勇敢去刪除不必要的東西 -> 這只是口號
    軟體系統的進入發展與維護期,會增加一些新的小功能,當開發人員、管理人員、維護人員異動之後,新的人員會調整與修改系統,真正熟悉這個系統實作的人就消失了,整個作業環境,就只會逐漸地疊床架屋,系統之間的依賴關係,只會越來越混亂。

    重構時,要勇敢去刪除不必要的東西,這是最好的方式,但也是一種不負責任的說法,因為這樣的說法,並沒有完全考慮到現場實作人員的狀況。

    假設我們是開發人員,接收了一個既有產品或服務的更新或維護的工作,首先我們能得到的既有的文件,再來是前一個負責人員的幫助,要知道更深入一點的問題,就只能去查看程式碼,或實際發布看看。

    有時候,即使是出自自己開發與設計的產品,在經過半年或一年的維運期之後,如果突然要改什麼新功能,也不能保證會不會影響就的功能,這時候,也只有唯一一個選擇,就是避開舊的程式碼,把新功能疊加上去。

    很抱歉,在這裡只能提出一個理想化的口號,完全沒有實際上可行的作法。

  6. 我們缺少的維運管理工具
    DevOps將顛覆未來IT人角色 文章中提到,DevOps其實是針對雲端運算環境,提出來的一個概念,我們需要一個快速且穩定的開發、測試以及釋出軟體服務的方法。【知識庫】Github上推薦的12款DevOps開發工具 列舉出來的也都是針對雲端運算的維運工具。

    在這裡,有個想法,就是我們需要一種工具,可以將維運的文件與維護的script整合在一起,在管理時,可直接點擊 script 然後就遠端執行並取得結果。文件與 script本身要有版本管理的功能,才能在維護團隊之間共享維運知識。

    如果是修改設定檔,可以即時將設定檔取回,修改並存檔後,即時同步到遠端,重點是要有新舊設定檔的備份。

    另外,我們還需要知道,透過這個工具,每一個維護人員在這個機器上做過什麼事情,改過什麼設定,每一台機器的執行結果都能記錄下來。

    在有多台機器的服務環境上,一個產品會部屬在多個雲端機器上,這時候可能要面對版本同步的問題,或許一個指令同時在多個 server 執行會有幫助。

    puppet 的用途,看起來是要用 DSL 程式設計的方式,快速地將每一台機器的安裝設定做好。對於一般企業內部的服務管理來說,看起來有點大材小用。

    這個工具的想法與概念還沒有一個比較確切的藍圖,還只在紙上談兵而已。

最終官方在微博發布了正確的資訊:5月29日1:30分,經攜程技術排查,確認此次事件是由於員工錯誤操作導致。由於攜程涉及的業務、應用及服務繁多,驗證應用與服務之間的功能是否正常運行,花了較長時間。攜程官方網站及APP已於28日23:29全面恢復正常。對用戶造成的不便,攜程再次深表歉意。

攜程網 微博
攜程網 404 事件:員工錯誤操作,刪除伺服器原始碼