2016年4月28日 星期四

資訊架構學是什麼?

這邊試著用解構的方式來說明資訊架構 (information architecture) 這門學問。

設計活動就是在某些限制下,生出某個東西來達成某個目的的過程。

所以可以理解「設計資訊架構」的過程中,設計出來的某個東西指是「架構/結構 (architecture / structure)」、而且這個架構的改變對象是「資訊」(information),接著透過新產生的「資訊互動」達成我們的目的。

簡單說,資訊架構透過設計「結構」、讓人和「資訊」有不同的互動,來達成我們背後期望的目的。

舉例來說:
1. 程式碼的資訊架構
結構:檔案命名、目錄名稱、放的位置、如何引用、設計模式
資訊:程式碼
目的:讓程式碼容易被理解、容易修改、容易查找、容易維護

2. 網站的資訊架構
結構:搜尋列、標籤、sitemap、瀏覽列、超連結、分頁...
資訊:文章、圖片、服務、功能
目的:讓人能找到想要的資訊、讓購買率上升、讓使用者達成他想做的行為

3. 書本的資訊架構
結構:段落、內容的順序、章節、標題、註解
資訊:文字、圖
目的:讓人更能透過閱讀能理解內容

4. 愛買的資訊架構
結構:商品走道的規劃、服務台的位置、結帳的位置
資訊:商品、愛買提供的試吃服務
目的:賣出更多商品

5. 臥室的資訊架構
結構:物品的擺放位置 (櫥櫃裡、牆面)
資訊:物品
目的:主人想...

資訊是相對的
對不同的人,同樣的資料會是不同的資訊;在不同的環境(context)下,同樣的資料會是不同的資訊。資訊不光只有資料、在電腦科學裡,功能/函數也是資訊的一種。

設計的目的是多方向的
有設計者本身的目的、有對使用者的目的、有對其他關係人的目的。也就是說,只要是跟人相關的活動都要理解這些人想要的是什麼、目標是什麼。和使用者中心設計 (User-Centric Design) 一樣。

設計模式 (Design Pattern / Design Principle)
只要是設計就會有比較好的設計模式來增加設計的成功率。所以通常我們在資訊架構中所學的就是這些「架構的設計模式」,對不同的資訊、不同的目的、不同的人都會有不同的「架構的設計模式」。評估一個「架構的設計模式」的方式就是觀察資訊擺在這個架構下,資訊到底會有什麼不同,能達到什麼不同互動。

被架構後的資訊
資訊經過架構後還是資訊,資訊的不同點不外乎就這些:資訊容易不容易「理解、瀏覽、找到、關聯、傳遞、同步、容錯、不失真、記住、更新、處理、新增、刪除...」 根據不同的設計目的,設計不同結構,讓原來的資訊的這些面向變得不同,以達成我們的目的,這就是資訊架構學的使用方法。

Domain Knowledge
架構的設計模式太多了、資訊也太多種類、人也太多種,細節就看相關領域的書吧~ 只是時時記得,有「變動世界的架構」的選項,變動後一切就會變得不一樣。就像 google / facebook,完全改變了人們和資訊的互動方式、產生方式。

facebook的資訊架構
結構:News feed & notification 系統 & 好友列表
資訊:發文、按讚、分享、加入社群的行為、閱讀時間
目的:讓世界變得充滿萬惡的讚能量、讓人都只看到自己想看的

最後說一下,其實設計流程是結構的一種、結構也是資訊的一種,從資訊流動來看世界是不是越來越有趣了呢?下圖是資訊架構和其他領域的關係。
在使用者經驗分層中,每層都是息息相關的,如果哪一層壞了,整個就壞了。所以從上圖我們可以知道:要做好資訊架構,我們必須做好設計研究、對內容有了解、對功能有能力去實作;要展現好的資訊架構,我們必須做好互動、介面、資訊、視覺設計,不然光只有好的架構,使用者經驗不會好。所以... 工作的時間到了。

參考:
1. Eight Principles of Information Architecture, 2010 - Dan Brown
2. Information Architecture 100, 2013 - 長谷川敦士
3. The Elements of User Experience, 2010 - Jesse James Garrett
4. Information Architecture: blueprints for the web, 2009 - Christina Wodtke and Austin Govella

2016年4月10日 星期日

”redux.js --- 可預測的狀態容器“ 的 API 使用說明

這邊只會透過理解 Redux 的 API來簡介如何使用 Redux。這邊假設讀者都知道 web 中 event / listener 的 pattern。

如果想要知道 redux 背後的實作細節、原理、動機、Flux、Design Pattern、如何和 UI App 做連結,請看 Dan 的 Redux gitbook、Redux tutorial on EggHead。


redux 是一個狀態容器 (state container / state machine)

狀態容器要提供幾個功能
1. 初始容器狀態 by Redux.createStore(reducer)
2. 取得現在的狀態 by store.getState()
3. 狀態改變時,通知相關的程式 by store.subscribe(listener)
3. 接收事件發生的通知、改變狀態 by store.dispatch(action)
4. 建立之後改變事件處理方式 by store.replaceReducer(reducer)
5. 由小的狀態容器組成全域狀態容器 by 只能透過 combineReducers 來組成 root reducer,再用它來建全域狀態容器

Flux 專有名詞:store、action、reducer。

store := 一個狀態容器
action := 一個像 Event 一樣有 type 屬性的 javascript object
reducer := 一個輸入 state 和 action、回傳新 state 的函數, (state, action) -> new_state

但 store 是 redux 中唯一一個狀態容器的名字。其實 API 等同於下方這樣子
1. by Redux.createStore(reducer) 等於 by Redux(reducer)
2. by store.getState() 等於 by Redux.getState()
3. by store.subscribe(listener) 等於 by Redux.addListener(listener)
3. by store.dispatch(action) 等於 by Redux.dispatch(action)
4. by store.replaceReducer(reducer) 等於 by Redux.replaceReducer(reducer)
5. by 無直接 API,只能透過 combineReducers 來組成root reducer,然後用 root reducer 來建全域 store

一個狀態容器 = 狀態 + reducer,但 reducer 中可以指定初始狀態、所以一個 reducer 其實可以定義一個狀態容器、等同於一個狀態容器,所以 API 等同於下方這樣子
1. by Redux.initContainer(reducer) 等於 by Redux(container)
2. by Redux.getState()
3. by Redux.addListener(listener)
3. by Redux.dispatch(action)
4. by Redux.replaceReducer(reducer) 等於 by Redux.container.replaceReducer(container.reducer)
5. by 只能透過 combineReducers 來組成 root reducer,再用它來建全域狀態容器 等於 Redux.combineContainer

把 combineContainer 用 addContainer 取代,API 可以改寫成這樣子
1. 初始容器狀態 by Redux()
2. 取得現在的狀態 by Redux.getState()
3. 狀態改變時,通知相關的程式 by Redux.addListener(listener)
3. 接收事件發生的通知、改變狀態 by Redux.dispatch(action)
4. 建立之後改變事件處理方式 by Redux.getContainer(name).replaceReducer(reducer)
5. 由小的狀態容器組成全域狀態容器 by Redux.addContainer(container)
6. 建立小的狀態容器 by Redux.container(name, initialState, reducers)


所以翻譯過後 redux api 的使用流程就會變成
let addReducer = (state, ADD_ACTION) => state++
let subtractReducer = (state, SUBTRACT_ACTION) => state--
 
counterContainer = Redux.container(
  'counter', 
  0, 
  [addReducer, substractReducer]
)

Redux.addContainer(counterContainer)

class CounterComponent {
  constructor(props) {
    this.stateChangeListener = (state) => this.setState(state)
    Redux.addListener(this.stateChangeListener)
  }
  componentWillMount() {
    this.setState(Redux.getState().counter)
  }
  onAddButtonClick() {
    Redux.dispatch(ADD_ACTION)
  }
  onSubtractButtonClick() {
    Redux.dispatch(SUBSTRACT_ACTION)
  }
  ...
} 



總結,可以看出來 redux 最大的特點就是用 reducer 來定義 container state 的處理範圍,不能用 event callback 的概念去理解它,一個 reducer 對應到“一組” state、多個 actions。

所以在 Redux 中 reducer 差不多是 container state scope 等價。也因此在 Redux 中 sub-container / sub-store 的名字完全被省略了,你只能用 reducer 的名字來找到他們影子。只要知道這個規則大概就能夠理解 Redux 了。

reducer := (state, action) -> new_state (你找不到 container 的名字、它被省略了)

老實說,我覺得這樣子的開發者經驗很不舒服 (bad UX)
---
不知道 re-frame 的 UX 會不會比較好?