發表文章

目前顯示的是 一月, 2014的文章

初次使用 paper prototyping 做使用性測試

圖片
雖然時常看到有人推薦用紙筆畫 app 介面做使用性測試, 但是要自己動手畫重覆的東西, 實在是提不起勁。前陣子聽阿修介紹 Paper Prototype, 也有同事動手畫了幾頁, 實際跟著流程走一次, 感覺還不錯。剛好我有在 iPad 裡裝 POP, 當場用 POP 結合同事做的紙張雛型, 互動效果出乎意料的好。 最近想幫爸媽做一款「待做事項」的軟體, 順便練習從頭開發一款 app 要經過的流程。中午花了大概一小時畫草稿加上用 POP 制作雛型, 過程滿順暢的。下面是部份原稿和 POP Android 版的畫面。 和爸媽分別測試後有找到一些小問題, 不過確定大方向應該可行。後來找我哥測試, 原以為應該會更順暢, 但是因為我哥使用 iPhone, 我是針對 Android 畫的草圖, 結果不容易融入情境。再加上我哥不是我的目標對象, 主要操作流程和他的期望不同, 也影響測試的流暢度。 歸納一下目前對使用 POP 做 paper prototyping 的看法。 目的: 做使用性測試。了解使用者是否了解如何操作。功能是否有滿足使用者的需求。 注意事項: 需要篩選目標使用者。 測試前要做情境描述, 使用者才能進入狀況 (看著草圖想像要做的事)。 盡量觀察使用者的反應, 少開口提醒。 優點: 制作速度快, 適合早期討論, 甚至能在開會中當場做。 易於專注在操作流程, 不會討論配色、字型、畫面排版等細節。 任何人都可以製作, 工程師和設計師以外的人也可藉此展示自己的想法。 限制: 只適合能融入情境的使用者。也許可透過幾次體驗後克服。 還是有可能插題討論圖示, 所以也不能畫得太糟。 總結來說, 現在我覺得用 POP 做 paper prototyping 滿快的, 但若是只用紙張互動, 一來我做得比較慢, 二來使用者也比較難聯想。我自己不適合用純紙張版本的 paper prototyping。 附帶一提, 做得過程中要自己用紙筆畫出概要, 才留意到一些 Android UI 的小細節。還有實際測試流程不像影片裡那樣順。看了再多資料, 還是得親身走一遍才行。

C++ 下 thread-safe 的 lazy initialization

《clang 避免 non-local static 物件初始化順序的方法》提到可用 static local variable, 然後用 method 傳回的方式避免產生 global static variable (藉此避免不同編譯單元的初始化問題)。以下是一個例子:const struct Point* center() { static Point* s_center = CreateCenterPoint(); return s_center; } 但是, 在 multi-thread 的環境下, s_center 可能被初始化兩次。假設 CreateCenterPoint() 會傳回不同的值, 或是外界可以改變取得的 Point, 有兩份 Point 會造成問題。 好消息是:gcc 預設有幫 local static variable 加入 thread-safe 的保護。 若 compiler 有正確實作 C++11, 在 C++11 的規範下, 有保證靜態變數的初始化是 thread-safe 的。 所以情況比想像中的安全。 不過, 其它 lazy initialization 的實作方式有可能出錯。更一般化的 lazy initialization 會用 Double-Checked Lock Pattern, 但是這個作法有不易察覺的漏洞。 直覺的作法如下:Singleton* Singleton::instance() { if (pInstance == 0) { // 1st test Lock lock; if (pInstance == 0) { // 2nd test pInstance = new Singleton; } } return pInstance; } 注意初始化 singleton 是三個步驟組成的: 配置一塊新記憶體 初始化新記憶體 將新記憶體的位置指向目標指標 (即 pInstance) compiler 有可能更動三者的順序。最壞的情況下, thread A 執行了 1, 3, 還沒執行 2, 這時 thread B 發覺 pInstance 不是 0, 於是回傳尚未初始化的 pInstance。解法是要使用 memory barr…

尋找 memory error 的強力工具: Address Sanitizer (ASan)

官網有很詳細的介紹, ASan 可以偵測出以下的問題: Use after free (dangling pointer dereference) Heap buffer overflow Stack buffer overflow Global buffer overflow Use after return 都是出錯時很難察覺, 之後會造成奇異的行為, 或是讓程式掛在莫明奇妙的地方。 clang 3.1 和 gcc 4.8 開始內建 ASan 的功能。號稱執行速度平均慢兩倍, 比起 Valgrind 的 20 倍, 實在相當誘人。這裡有說明 ASan 怎麼做的。這樣在 Linux 上也有不錯的 memory error detector 了。不知什麼時候能追上 OS X 的腳步。 除了 Chromium 有用之外, Firefox 也有使用

clang 避免 non-local static 物件初始化順序的方法

C++ 沒有定義 non-local static 物件在不同編譯單元 (translation unit) 之間初始化的順序, 所以要極力避免 non-local static 物件相互間的存取。 今天試用 clang 編譯程式, 發覺它有個不錯的選項: -Wglobal-constructors。用這選項編譯, 遇到有 non-local static 物件會依賴其它函式 (包含 constructor) 設值時, 會輸出 warning。 這裡引用 Address Sanitizer 提供的例子: $ cat a.cc #include <stdio.h> extern int extern_global; static int __attribute__((noinline)) read_extern_global() { return extern_global; } int x = read_extern_global() + 1; int main() { printf("%d\n", x); return 0; } $ cat b.cc int foo(); int foo() { return 42; } int extern_global = foo(); $ clang++ a.cc b.cc && ./a.out 1 $ clang++ b.cc a.cc && ./a.out 43 $ clang++ a.cc b.cc -Weverything a.cc:6:5: warning: declaration requires a global constructor [-Wglobal-constructors] int x = read_extern_global() + 1; ^ ~~~~~~~~~~~~~~~~~~~~~~~~ 1 warning generated. b.cc:3:5: warning: declaration requires a global constructor [-Wglobal-constructors] int extern_global = foo(); ^ ~~~~~ …

使用 CSS position 組合 div 的佈局小技巧

圖片
這篇談的方法在舊的瀏覽器大概會出包, 沒有實際研究。跨瀏覽器的議題太複雜, 希望在我不得不面對這議題前, 跨瀏覽器的痛苦可以減少很多 (大概要等 Windows XP 絕跡吧)。 以下圖為例, 這篇討論兩個使用 CSS position 的小技巧。 使用 relative position 重疊版型 上圖的書本和內文, 實際上是兩個 div 組成的, 還原後如下圖: 組合的方式如下: HTML<div class="wrapper"> <div class="content"></div> <div class="book"></div> </div> CSS.wrapper { height: 750px; overflow: hidden; } .content { height: 500px; position: relaltive; z-index: 1; } .book { height: 700px; width: 500px; position: relative; top: -600px; } 數據是我大概填的, 示意用。 幾個要點: .book 用 position: relative 從原有的位置往上移到 .content 做為背景。 為了讓 .content 在上方顯示, 設 z-index: 1。由於 z-index 只有在 non-static position 下才有效, 所以改一下 position。 .book 使用 position: relative 往上移後, 仍會在原位置留下空間, 就像 visibility: hidden 一樣。為了避免占用原位置的空間, 限製 .wrapper 的 height。 這樣做的好處是內文和背景分離, 兩者各自依需求配置 div 結構, 不會互相影響。不然要顧及內文的排版而調整背景書本的 div, 切版型會滿辛苦的。 缺點是必須限制高度, 不像一般網頁彈性地隨內文增加而自動增加高度。 使用 absolute position 疊出下方的書緣 下方展開後, 中間長這個樣子, 我隱藏了左側一個 div, 方…

Ubuntu 安裝 package 出現 conflicts 時的解法

這篇只討論我自己常遇到的一個情境: 明明只是升級某個套件或加裝相關套件, aptitude 卻發瘋似的說有些相關套件的相依版本不合, 要移掉一大堆套件才能繼續。解法是下指令時同時安裝目標套件和 aptitude 抱怨不合的相依套件。 實例如下: $ sudo aptitude install git-svn [100%] Reading package lists ... The following NEW packages will be installed: git-svn libsvn-perl{a} libterm-readkey-perl{a} The following packages will be upgraded: perl perl-base perl-modules 3 packages upgraded, 3 newly installed, 0 to remove and 793 not upgraded. Need to get 10.3 MB of archives. After unpacking 4,449 kB will be used. The following packages have unmet dependencies: libperl5.14 : Depends: perl-base (= 5.14.2-6ubuntu2.1) but 5.14.2-6ubuntu2.3 is to be installed. Internal error: the solver Install(libc-bin:amd64 2.15-0ubuntu10.5 <libc6:i386 2.15-0ubuntu10.5 -> {libc-bin:amd64 2.15-0ubuntu10.5 libc-bin:i386 2.15-0ubuntu10.5}>) of a supposedly unresolved dependency is already installed in step 153 Internal error: the solver Install(libc-bin:amd64 2.15-0ubuntu10 <libc6:i386 2.15-0ubuntu10 -> {libc…