2017年8月6日星期日

QML Snapshot Testing與TDD的連㩗

到底應該怎樣做GUI的自動化測試呢?這個問題一直都困擾著我。

並不是不會做,而是怎樣做得有效率,基本流程有三個步驟,首先要模擬環境、然後模仿實際輸入,最後核對結果。

要是架構設計失誤,光是第一步的環境模擬就夠嗆了,模仿輸入及核對結果就是一項會隨test coverage要求上昇而變得更加吃力的苦力工作。

最慘的是每當UI設計修改,以前寫的test case就有可能要面臨推倒重來的困境。

在UI改動頻繁的項目,我甚至會直接放棄自動化的GUI測試,盡量簡化UI的元件,只把力氣放在程式邏輯及數據上,直至我見到Jest的Snapshot Testing

Jest - Snapshot Testing

有一種GUI的自動化測試方法會制作元件的Screenshot圖像,再跟之前的版本進行對比,若然二者不符測試就會失敗,要麼修改程式、要麼更新Screenshot。 

Jest的Snapshot Testing的概念也是一樣,但不弄screenshot圖像,而是把視覺元件轉換成一個像XML/HTML的文字描述的snapshot,然後作出比較。

這樣子就不用找地方存放圖像,可以直接把文字描述直接存放在版本控制內。



在見識到這種GUI自動化測試方法後,我就一直在想能不能拿到QML上用呢?會不會可以解決很多問題呢?

QML - Snapshot Testing

為了把Snapshot Testing帶進QML中,我試著做了這個項目。


QML Snapshot Testing
https://github.com/e-fever/snapshottesting


跟Jest的版本不一樣,文字描述並沒有使用XML的形式,改為使用像QML語法的表達方法,同時加入了GUI版本的”比較視窗”,可以提供更加詳細的資訊。




安裝及使用方法等就不在這裹談了,可以看Github的說明,這裹想寫的是有關於TDD的配合。

Test Driven Development

在Jest的FAQ提過TDD並不適合配合Snapshot Testing使用,主要問題是人手寫Snapshot file(即是那個UI的文字描述)太麻煩,Snapshot Testing的原意並不是提供設計指引,而是找出有沒有出乎意料的修改。


但QML的Snapshot並非完全跟Jest一樣,有二項很大的分別:
  1. QML版提供GUI的介面,不單提供Diff,還可以瀏灠完整版本的Snapshot 
  2. 與此同時,被截取Snapshot的UI元件依然可以運作,開發者可以手動輸入並用肉眼視察結果 

就著這二點的不同,要進行TDD式的做法並非不可能的事。

TDD的主要精神有2個 -「Write Test code first」、「Red-Green-Refactor Cycle」

我會用以下的例子說明如何利用Snapshot Testing並配合TDD的2個要求


任務:寫一個元件,最初會顯示”Ready?”,點擊後會變成”Go!"

工作一:Write (Failing) Test code first

大概是這個樣子。(程式代碼

tst_CustomItem.qml
import QtQuick 2.0
import QtTest 1.0
import SnapshotTesting 1.0

Item {
    id: root
    width: 320
    height: 240

    CustomItem {
        // Don't put this under TestCase object.
        id: customItem
        anchors.fill: parent
    }

    TestCase {
        name: "CustomItem"
        when: windowShown

        function test_CustomItem() {
            var snapshot = SnapshotTesting.capture(customItem);
            SnapshotTesting.matchStoredSnapshot("test_CustomItem_default", snapshot);

            mouseClick(customItem)

            snapshot = SnapshotTesting.capture(customItem);
            SnapshotTesting.matchStoredSnapshot("test_CustomItem_clicked", snapshot);
        }
    }

}

至於CustomItem的內容就先讓他一個預設的內容 - Item {}

這樣測試程式⋯⋯就完成了!

咦,不用測試顯示的文字嗎?

正常來說需要這個步驛,還要提供介面,告訢元件以外的人正在顯示的文字.
/// CustomItem.qml
Item {
    property alias displayText : text.text
    Text { 
        id: text
    }
}

但這個屬性本身僅僅是為測試提供服務,本身是沒有需要的。

在用了Snapshot Testing後就不再需要用到這個屬性,即管跑一跑以上的程式吧。




因為是第一次執行,並沒有儲存過任何snapshot,所以Snapshot.matchStoredSnapshot會彈一個”比較視窗"出來詢問,概然CustomItem還只是個空白的元件,當然回答”No”,測試程式回報失敗,我們寫了一個失敗的測試,第一項工作完成。

工作二:Red-Green-Refactor Cycle

現在測試程式亮紅燈,無法通過,開始寫CustomItem

import QtQuick 2.0

MouseArea {
    Text {
        id: text
        text: qsTr("Ready?")
        font.pixelSize: 28
        anchors.fill: parent
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
    }
}

再跑一次測試程式,同樣地停在相同的地方,但不同的是程式的視寫中顯示了”Ready?”的字句。




經過肉眼的判斷,程式符合預期,所以按下yes.


之後程式繼續跑,模擬滑鼠輸入後,又進行了一次snapshot test,基於MouseArea沒有實現所需的功能,故此元件仍然顯示”Ready?”,選擇”No”

再做一次修改吧,這次加入所需要的功能。

import QtQuick 2.0

MouseArea {
    Text {
        id: text
        text: qsTr("Ready?")
        font.pixelSize: 28
        anchors.fill: parent
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
    }

    onClicked: {
        text.text = "Go!";
    }
}

因為UI沒有修改,第一個Snapshot Test會直接通過,再次停在第二項測試。



這次沒錯了,所以按”Yes”,大功告成,可以commit push上伺服器了


任務三:UI規格修改

對開發者來說規格的修改是最為苦惱的, 改動太大或許會讓前功盡廢,其中受到影響最大的多數是自動化GUI測試。


假設現在要一項小的修改,文字要要改成大寫”READY!?” / “GO?”,所以CustomItem變成

import QtQuick 2.0

MouseArea {
    Text {
        id: text
        text: qsTr("READY?")
        font.pixelSize: 28
        anchors.fill: parent
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
    }

    onClicked: {
        text.text = "GO!";
    }
}
(註:其實用font.capitalization便行,但示範就裹就不用這個方法了)

再跑一次Test Case,因為Snapshot不符的關係,比較用的UI又再次彈出來詢問,當然全部都回答”Yes”。





在就這種小改動的情況下,用上Snapshot Test的測試項目甚至不用作出任何的修改,程式會自動找出被改動過的元件,經開發者確認後便自動修新,這大大滅輕維護的成本。

結論

當QML的Snapshot Testing配合TDD使用時,有一點跟傳統的做法不同,就是不用先寫預期的條件判斷,在開發的過程中改為經肉眼判斷是否正確,一旦確認正確,SnapshotTesting便會自動記錄在案,那些超煩人判斷條件都交由SnapshotTesting負責,變相減輕篇寫測試程式的工作量。


2017年4月8日星期六

20萬用戶成就達成!

Dualless的用戶數人數突破20萬了!太感動了,謝謝大家的支持!

2016年4月29日星期五

又來超糟糕的登入設計


我想差勁UX的極致表現就是懲罰用戶,用戶每次使用都會叫苦連天、氣得血氣上湧,其中一個例子是上一篇文章中「再見了,超糟糕的登入設計」中提過的一個超糟糕的登入設計,幸好對方已經放棄這個設計,用戶不用再受苦。

但最近從Facebook上的朋友處得知,有銀行採取了相若的登入設計。


圖片於2016年4月29日截取

首先輸入密碼必須使用虚擬鍵盤,然後大家有留意到數字盤的問題嗎?竟然不是常見的排位,是會隨機改變的!

而且 ---



用戶名稱要最少3個數字,以及採用大小寫英文字母!?用戶名也是密碼嗎!?

傳送門:
  1. 電子網絡銀行服務
  2. 點擊登入,選擇電子網絡銀行服務


2015年12月5日星期六

繼續站著工作 - 自己動手做standing desk (流動版)

上一次寫standing desk有關的文章已經是2年前,本身也用了相同的時間,別以為我會因此變得能站個8小時不停,那恐怕比坐8小時所造成的傷害更大,主要都是交替姿勢,時坐時站。

身體是否有因此變得健康呢,實在很難說,減肥的作用就肯定地說沒有效果,不過腰痛的問題就機乎不會出現。曾經試過因為運動而弄傷膝頭,坐了幾天,腰就開始酸痛。頸就沒法了呢,唯有多點轉動。

在上一篇文章中提過幾張可以在香港買得到電動昇降桌,價錢都比較高,或許大家都未必願意花那個錢吧?

不過有一個好消息,Ikea的Bekant昇降桌(油壓)已經來到香港了!價錢是HKD $1890。




不過最合用的地方應該是辦公室,在家的需求沒那麼大,但公司不配合就沒辦法。

Ergotron Workfit-s可能是個比較好的選擇。




如果閣下在辦公室也是用Laptop電腦的話,這裹有一個更划算的方法:




這個是Kickstarter的籌款項目,簡單來說就是一個portable laptop stand,但高度是為站立使用而設計的。

價錢只是USD $32 (連運費$40)

筆者的行動

不過集資期而過,而且預計出貨日期是2016年6月,作為Backer之一的筆者也覺得實在是太久了。

結果在無法等待的情況下,決定自己動手做了一個:


成品!!


跟13" MBA的比較

材料:
  1. 50.9 x 38cm的大硬卡紙二塊 HKD $15
  2. 少量黑色膠紙 $0
工具:
  1. 界刀一把 
  2. 60cm 鐵尺一把
成品呎吋:
  1. 摺疊狀態:23*38cm
  2. 打開狀態:23*23*30cm
用的材料只是硬卡紙,不過已經有足夠的承托力放置13” MBA,而且雙手可以壓在MBA上,本身也很穩定。

缺點是打開時不是那麼順暢,要一點技巧,摺就很輕鬆。


優點當然是價錢以及可以度身定做,事實上筆者自制的版本的高度就比Levi8 M為高,但又比Levi8 L小巧。

至於怎樣制作呢,首先建議大家跟video用A4紙試作一次: 




意外地簡單吧?

在正式制作前要先考慮一個問題 - 尺吋,你要多高呢?

假設你要做一個高度為H,你需要4張闊度為W、長度為L的紙。

他們之間的關係依從畢式定理:

W^2 + H ^2 = L^2

W的建議大少為23cm,這是跟MBA相應的大少。




步驟:

1) 在材料上按所需要呎吋畫上剪裁線


因為邊長最少要92cm (23 * 4),要買這樣的硬卡紙並不容易,可以斬成2份,又或者4份,之後在步驟(5)時用膠紙連著便可以。

2) 用界刀把不需要的部份裁走

3) 在需要摺合的位置上用界刀輕輕地畫上一刀,方便下一個步驟

不小心界破也沒關係,可以在步驟5中救回,但呎吋偏差太大的話就請重造吧。

4) 按線段摺合卡紙,二個方向都要摺一次。




5) 用膠紙進行連接及為接口進行補強



6) 摺成這個形狀




7) 雙手放在這個位置,然後翻開


這裹有一點小技巧,很難說明,請自行多嘗試幾次。

8) 完成!




受材料所限,展開的過程沒Levit8的影片般那麼輕鬆,要依一個正確的程序,材料方面也不算輕,跟Levit8相比有所距離,而且概不防水,外表也不特別討好,果然是商業的設計比較棒,當Levit8出貨之後我會建議大家去買一個回來更好,現在就先用手作品來湊著用吧。

就這樣無論在家又或者辦公室都有standing desk用了。!

家中其他的Standing desk組合:




放置流動設備的斜架


Laptop專用的區域

2015年11月25日星期三

再見了,超糟糕的登入設計

轉用SmarTone的服務有近一年左右吧,當初在建立了網上戶口後就跟自己說 - 「誰叫我登入SmarTone,我就跟他反面。」
 
因為那個登入系統實在太糟糕了,無法想像是什麼人、擁有怎樣的思路才可以設計出這種概不特別安全,又會充份懲罰用戶的登入介面。

今天SmarTone寄了一個電郵過來,說簡化了用戶名稱及密碼的要求:



很普通,沒什麼奇怪吧?

對,因為這才是正常的,是過去的SmarTone把東西設計得太變態了!

(1) 首先,用戶名稱跟密碼要求一樣:





這是搞什麼啊?為什麼用戶名稱要有大細楷及最少3個數字?用戶名稱本來是一種可以告知別人也無妨的東西,SmarTone當我們都是特工,連名字都不能告訢別人嗎?


(2) 虚擬鍵盤輸入?!




當時不能用實體鍵盤輸入,一定要用On-screen的虚擬鍵盤,而且你們有發現到嗎?

鍵盤上的數字不是按1-9,0這種順序擺放,而且每次輸入都會重排。

天啊!!這是什麼懲罰?

用滑鼠打虚擬鍵盤已經夠慘了,按鍵的位置還會改變。

大家記得建立帳戶時有一個慣例是什麼嗎?

就是輸入密碼二次。

用這工具輸入2次最少有3個數字的密碼?




在錯誤輸入了數次後,還會出現:






在經過無數嘗試、失控地拍了三次檯面,總算成功地建立了帳戶 -之後一年我都沒有再登入過。

SmarTone終於放棄這些懲罰用戶的措施,實在是一件令人感到高興的事 -----但我記不了自己的帳戶名稱,你可以幫我改回一個正常的名字嗎?

2015年10月10日星期六

Dualless - 10萬用戶達成紀念

自從在2012年發佈Dualless自來,經過3年多的時間,就在昨天用戶的人數終於突破10萬了!

特此一貼以示慶祝,並且想向各位支持者說一聲:「謝謝!」

記得在最初發佈時,就想著做一個實驗,就是在不費力氣宣傳的情況下,用戶數會怎樣增長呢?

在3年後達到這個數字應該不能說很好,但也不算太差吧。

不過最初獲得2千用戶時就費了近半年的時間(當時估計有一半用戶來自越南),當初就因此太過灰心而放棄實驗,雖然還有更新,但不再關心用戶數。

現在回想起來,花費的時間總算沒有白費。

p.s Dualless的source code已經由Launchpad搬了去Github.



2015年10月10日的螢幕截圖

2015年6月29日星期一

Side Project : Team Color - 在試算表上研究顏色

在做正式產品時總是想做點side project,這大概是多想法的人的宿命吧?希望大家都不會變成這樣子就好了...


雖然現在公司的成員都是香港人,但基本上以remote team的方式運作,有時候想要一個問題的答案並不是立即便知道。

你說用Instant Messenger不就行了嗎?那麼你可以在05:00立即回應嗎?你可以在跟男/女朋友獨處時也回應嗎?

實在太多老闆認為Instant messenger就代表要立即回應,殊不知只會令員工更加討厭公司的事務。

所以一個knowledge base對remote team是很重要的,有問題先在裹面找,找不到再來發問。

在我們開發時其中一樣需要記錄的是色版,一個程式在什麼地方該用什麼顏色,這是設計師的工作,但設計與開發並不一定是同步,開發者有時候要在設計師回覆前工作,而設計師在思考用色時又需要參考原來的色版,以避免每次都用不一樣的顏色,做出不一致的設計。

最初我們用Google Spreadsheet記錄,不過開發者沒有只看Hex Color便知道顏色的能耐,故要求設計師要把Cell的背景色設定到跟內容一樣,但因為色版改了很多遍,變成了壓惡性工作。


最終的解決方法是寫Add-on,在用戶輸入十六進位的顏色代碼後就會自動把背景顏色變成該顏色.

就這樣啪啪啪的輸入:

#
#F
#FF
#FFA
#FFA5
#FFA50
#FFA500 [Enter] 立即變色


然後我們把這個視為side project放了出來,並取名為 Team Color

TeamColor的功能:
  1. 輸入16位的顏色代碼後,背景顏色會自動轉成該顏色
  2. 支援3/6/8位的16進制碼,8位為ARGB碼
  3. 提供Custom Formula用來處理顏色(e.g colorRgb, colorArgb , colorSetOpacity , colorRed  , colorSetGreen etc) 詳細請看說明文件
  4. 反轉文字及背景色

可以在Google Spreadsheet上玩漸變色啊


在試用後能給我們意見回饋及星星嗎?如果想到有趣的use-case,不妨分享一下~


相關文章
  1. 擴充Google Docs的應用(1) - 在試算表中建立連結
  2. 程式師的修練場 - 建立自己的Junkcode及測試程式庫




2015年2月1日星期日

#github 我都只是fork別人的project,你fork我又何苦呢

以上標題沒什麼特別意思、動機,只是有天隨便在Facebook上說的話,怎料大家的回應都很"奇妙"(笑)




2014年6月25日星期三

近況

很久沒空更新了,若說近況如何,我覺得這張圖就能解釋。


註:

  1. Testing的東西不一定只是code,還有不同的生活方法
  2. 作為fans向遊戲的SAO虚空斷章讓我感到很滿足。

2014年2月1日星期六

讓Github幫你管理放在Amazon S3的網站 - 網站更新的自動化部署

用版本控制軟件(Version Control System)來管理網頁並非什麼稀奇的事情,概能容許多人同時修改,又可以追蹤變化,除了這些優點外,配合自動化部署(Auto Deployment)系統更可以自動把內容上傳到網站,大大簡化繁複的部驟,減少出錯的機會。

這裹我會用Tinyboy開源3D打印機計劃的網頁做例子,講解怎樣用Github及Travis-CI來管理網頁的發佈,設定好後絕大部份的發佈工作都可以經Github的介面完成,不用裝FTP,也不用碰網頁服務器,而且所有發佈都有記錄可尋,隨時都能回復(Rollback)到舊版本

理論上以下的框架也可以應用到其他軟件的自動化部署上,需要的是只是按個別需求客制化。

預覽流程


一般來說開發者/設計師都能在自己的電腦內查看及修改網頁內容,不過有時難免會大意弄錯,所以讓其他人檢查及回饋意見也很重要。那些Reviewer卻未必像開發者/設計師般精通技術,可以自已下載最新版的網頁,故此一般都會上傳一個預覽的版本供他們觀看。

把這個過程自動化可以節省不少力氣,不用重覆“修改->上傳”的步驟。





流程
  1. 開發者/設計師利用Git把最近的修訂推到Github
  2. Github會通知Travis-CI進行自動化的部署
  3. 及後Travis-CI再把內容上傳到Amazon S3檔案伺服器,該伺服器提供http://www2.tinyboy.net 預灠網站的內容
  4. Reviewer在不同設備、瀏灠器上查看 http://www2.tinyboy.net
  5. 然後回饋意見給開發者/設計師,讓他們再重新修改

Travis-CI

Travis-CI是一套為Github而設的Continuous Integration(CI)系統,每當收到新的commit就會自動執行測試程序,若成功則進行部署動作,過程中發生任何錯誤都會用電郵告知。 


Amazon S3

S3是Amazon提供的檔案伺服器,功能繁多,包括存放靜態網頁,因為價錢划算加上有API支援,這使得S3很適合用作自動化部署系統的一部份。

以美國東岸N. Virginia計算,少於1TB的情況下,每GB的儲存費用是USD $0.095,流量則是USD $0.12/GB,每1000個請求是USD $0.005,而且使用越多單價越平,加上Amazon經常派Coupon,基本上可以不太花錢就能擺放靜態網頁。 



正式版本的發佈 - Pull Request

預灠版本是為了收集意見及測試之用,過程全自動,並不存在任何審批的流程。但正式版並不一樣,總不能把未檢查的內容向公眾發佈,故除了各位Reviewer外,通常也會有一個至數位Gatekeeper存在,由他們操刀釋放正式版本。

S3並不支援FTP上傳,必須配合專用的工具,這使得Gatekeepr必須懂得使用這些工具,也需共享[密碼],前者要求用戶學習,然後後者又要擔心不小心讓密碼外流,出了事也沒有方法追查成問題所在。

最理想是用戶本身有自己的帳戶,然後上傳又能留下記錄追查,在這些要求下,github是個不錯的選擇。



流程
  1. 當Developer / Designer希望發佈正式版時,他們在Github上向Release分歧提交一個Pull request的伸請
  2. Gatekeeper在Github的介面上批準這個伸請
  3. Github從Master分歧中把修訂整合到Release的分歧
  4. Github通知Travis有新的修改
  5. Travis把內容上傳至www.tinyboy.net的S3 Bucket
在這流程中應用了一個Github的功能 - Pull Request,平常在軟件開發時會有機會出現不同的分歧,這個機制可以讓Github幫你進行分歧內容整合的動作,並且在網頁上留下記錄。

基於這個特性,也可以用作正式版的發佈之用。首先在這個項目中有二個分歧,一個是master,平常工作的地方,任何修改都會自動上傳到預覽網站。

另一個分歧是release,平常不會修改,當需要發佈正式版時,就會向這個分歧提出一個Pull Request。

Gatekeeper只要查看這個Pull Request的細節便能得知有什麼地方被條改了,Github的介面甚至能顯示圖檔在修改前後的變化:



確認一切妥當,只需要按下這個按扭便能發佈:


參考文件



2013年11月1日星期五

不明白Facebook的苦心就不許使用Facebook啊

Facebook一直在說要讓全世界都能找到你("Who can lookup your Timeline by name"),這次的改動不再是突然而來,而是有所準備而來,大概是以前被人罵了太多遍吧。

不過我沒有興趣去理解,因為這本來就是強逼性的行為,理解了又如何?可以反對嗎?可以伸訴可以反對,那才有了解的意義。所以間中彈出來叫你去了解的提示全都被我無視了。

到了昨天,由不定期的提示變成固定、除非你表示"OK , I Understand"否則繼續下去。

那又如何?繼續被我無視。

然後到了今天,終於不許我用Facebook。


除非按下"OK , I Understand",不然就無法使用Facebook,唯一例外是Mobile版本。

為了先向其他用戶傳播這個消息,我安裝了User Agent Switcher的插件,扮成Android貼文,那時大概是14:40左右。

一小時回來,發現這個漏洞已經被堵了,只要你的browser曾經用原來的agent設定連上,後來再改成Mobile也沒用。

看來Facebook已經下定鐵心,逼用戶“了解”,即使根本無法了解。包括以沉默對抗的權利都會被剝奪

2013-11-01 16:14 在Desktop browser裹用m.facebook.com可以跳過限制

2013年9月28日星期六

開始站著工作 - 自己動手做Standing Desk

[關於流動的standing desk組合,請參閱新文章:繼續站著工作 - 自己動手做standing desk (流動版)]
不知是因為年紀日長、還是缺少運動,這年間感覺到專注力、健康等都有所下降,在這時留意到越來越多人站著寫程式,聽說比起坐下來健康。


實際使用後覺得這方法真的非常之累,一小時是極限,之後坐下來就不想再動。

但在這過程中卻不怎樣會分心,異常地集中令效率提昇,至於要休息的問題反而是好事,有效地提醒自己要改變姿勢,及令眼晴休息。(比軟件有效)

那時候的Standing desk:


這是用現有的實惠(PriceRite)鐵架組裝的,只是改變層板的高度遷就自己而已。高度上挺不錯,可是很貴,而且有一個致命的缺點 - 不穩定

只是打字產生的震盪就會令Monitor產生搖晃,變相令眼晴更容易疲勞,就算是Ikea的鐵架也有同樣的問題,看來是這材料先的天性的問題。

選項有二:
☐ 買現成可昇降的桌子
☐ DIY - 繼續自己組裝傢俬
Freemax TCT-G3


Freemax的TCT-G3 Desk是一張很讚的人體工學桌,有三種姿勢任君選擇,在陣列室使用過非常之滿意,不過加上螢幕掛架就要近HKD $8000,價錢有點難以抉擇,而且我要先把家中的L型書檯拋了才容得下,工程過於浩大。

Ergotron Workfit-s



Ergotron's Workfit-S可以加在原有的電腦桌上,價錢也沒有TCT-G3那麼昂貴,不過來貨等候時間很長。

DIY
同時我也在找有沒有其他比較便宜的方案,在網上最多人的做法是用Ikea的LACK角几改造:


這個做法概便宜又方便(HKD $79.9一張),可是遇到一個問題,原來放鐵架的地方並沒有桌子,要先買一張桌子後再放這個LACK角几,如果桌子下面的空間只能放雜物的話,那會相當之浪費。

最後的解決方法還是用了LACK角几,但不是一張,而是2張:

最底一層放雜物,中間放打印機,上面則是工作的空間,讓空間的使用效率大大提高。

用2張LACK角几充當儲物空間,是頗出名的Ikea Hack,一來便宜,二來輕巧(LACK角几是非常之輕的)。

然後在上面再放床頭几(RAST BDS TABLE),在組裝時底板不要上足三口螺絲,並讓底板拉出一點,從側看會呈現一個L的型狀,之後再放一塊木板提供Keyboard及Mouse的活動空間便大功告成!

在Keyboard板及Lack角几之間有一個空位,可以放入雜誌、常用文件等東西。

中間可以放書本或文件架、在使用電腦時參考紙本的內容。

材料
  • RAST BDS Table 52x30 129.90
  • LACK Side Table (55x55cm) 79.9 * 2 = 159.8
  • EKBY LAIVA SHELF 24x59 $39.9
  • 幾口鋼牙螺絲
總造價:$329.6

規格:
Keyboard離地高度 : 97cm
Monitor離地高度    : 130cm

相關閱讀:

  1. 繼續站著工作 - 自己動手做standing desk (流動版)


Creative Commons License
本網誌Ben Lau製作,以共享創意署名-非商業性-相同方式共享 3.0 香港 授權條款釋出。