雜論 SNS 與入口網站的資訊架構設計 (1)

寫這篇文的時候,我正在設計一套 BBS。我希望這套 BBS 除了可以找回過去「只要有心(加上做了一些功課),人人都可以架一個 BBS 站」的樂趣,以及期許這樣的樂趣會喚醒人們對 SNS(社群網絡服務)其實可以不必那麼中心化 (centralized) 的認知,還有一點點練功的成份在。

呃,好吧,我承認,也許不只是一點點而已,我希望透過從做中學,瞭解一個基於 Web 技術的 SNS 該如何設計、實作以及營運管理。

因為這樣的動機,促使我整理對於「這個 BBS」應該如何鑑往知來的想法。所以本文會以時間為主軸,在這條線上看 SNS 與入口網站的資訊架構設計。

1995: BBS 以及絕大部分很靜態的 Web

1995 年,在電腦史上,或者不要那麼浮誇,至少在我的個人電腦利用史上,我覺得是很重要的一年。這年,當然地,Microsoft 的 Windows 95 在 PC 市場上取得了成功,積極意義上就是說,PC 市場上有了一個普及的 32-bit 作業系統,這使得 PC 用戶的電腦終於有一個能夠充分發揮硬體性能、且不會因為單一程式影響就動輒當機死透的多工、圖形化、多媒體使用介面。

為什麼這個需要在開頭大書特書?因為有了這麼一台具備圖形、多媒體處理能力(且足夠穩定了)的設備,可說是後來我們之所以可以體驗 Web 的一種基礎建設。

(這裡不免要再大膽不怕羞地提一次,當時我是 Windows 95 競爭對手、IBM OS/2 Warp 3.0 的狂熱愛用者,以現在的流行語來說,就是個腦殘粉。)

約莫同時,Internet 開始普及到民間,在這之前,數據機 (Modem) 的功能多是玩家用在架設與連接 Dial-up BBS,這種 BBS 跟現在大家用的 Telnet 式 BBS 不太一樣,信件、討論文章為了要節省撥接的電話費,所以通常是用「快信軟體」下載到自己電腦上後再閱讀,同時將您的回應上傳,形成一種「信包交換網路」。

而因為「時間就是金錢(電話費)」、「空間也是金錢(那時主流規格硬碟容量約莫是 540MB~1GB 之間)」的緣故,Dial-up BBS 很注重「言之有物」,不歡迎「灌水」、不需要的「引言」需要刪除。這樣的文化,其實也影響了早期的 Telnet BBS。

回到正題。也就是說,在 1995 年,如果您用約二~四千元台幣買了一台當時主流規格 14.4K 或 28.8K Bps 的數據機,再跟 ISP 業者租用他們的上網服務,或是極其有幸,透過學校電腦教室、宿舍提供的網路連線,就可以「上網」。

為什麼要提這件事呢?這件事的隱含意義是:無論用數據機、網路卡還是什麼我這個鄉下人沒見過的黑科技,在當時終於可以讓一台 PC(當時咸認最具代表性的「資訊設備」)不再只是一座孤島,讓用戶有了線上連結、在上頭可以資訊交流、發展社交,如此的可能性。

而當用戶連上網,或撥進 BBS 後,呈現在其面前的,是由「信區」、「新聞群組」、「版面(看板)」為單位,組織而成的一種資訊架構,透過這樣分門別類、按圖索驥的方式,用戶被動去適應這樣的主題分類,或是積極一點去申請一個主題區,但無論如何,用戶是圍繞在「主題→主題分類」這樣的框架下進行資訊交流。

同時,在 Web 這邊,我們回顧以前的蕃薯藤或是 Yahoo! 的分類目錄設計,一樣也是讓服務提供者決定了主題、分類體系,來引導我們尋得或整理相關的資訊。

那麼,如果您的興趣是所謂的「次文化」、「惡趣味」、不見得在這個分類法下找的到一個歸屬的呢?又或者,您根本不想「被分類」,上網只是想要有個地方裸奔、自言自語呢?BBS 裡可能有些站台可以申請「個人版面」或您乾脆架個「個人站」,Web 也可以有業者提供的免費空間,您就自己架個獨特的網站吧!

大致上說來,當時的網路,是很強調「主題分類」這個框架的。我覺得箇中原因之一是,當時還缺乏一個夠強大、很會爬的搜尋引擎,好讓用戶跳脫被設定的分類體系、自行決定「要找什麼」;另外一個原因,就是適應人類其實很喜歡翻目錄、型錄的天性。

解決在 Vim NERDTree window 裡誤切換 buffer 的問題

這篇是承自之前提過的問題,今天終於花了一點時間,看了一下 NERDTree 的 source code 找出解法。

在自己的 .vimrc 裡新增這麼一段自訂 function:

function! LeaveNERDTree()
  if winnr() == g:NERDTree.GetWinNum()
    wincmd p
  endif
endfunction

大概的邏輯是這樣:

  1. 如果目前所在視窗的號碼等於 NERDTree 的視窗號碼
  2. 不管怎樣,跳開就對了,cursor 就是不要在 NERDTree 裡面

然後就可以套用到自己切換 buffer 的快速鍵上:

nnoremap <silent> <F3> :call LeaveNERDTree()<CR>:bprev<CR>
nnoremap <silent> <F4> :call LeaveNERDTree()<CR>:bnext<CR>

短短幾行,解決了長期以來的、常常為了自己操作錯誤而惹得很毛的問題,怨自己當初為什麼沒仔細去看 source code?

Game & Watch EG-26: EGG

昨晚,幫老婆找出童年時玩過的掌上型電玩「接雞蛋」,前因是我跟強者我同事 hSATAC 借 PS Vita 玩,被她看到又再問了一遍:「有『接雞蛋』嗎?」這是她不曉得第幾次提到「接雞蛋」了。心想平常不碰電玩、最多只玩手機休閒遊戲的她,看到別人在玩掌上型電玩就會聯想到「接雞蛋」,就像提到電視遊樂器就有很多人聯想到「超級馬力歐」那般懷念的經典?

用 “Game and Watch Egg” 去搜尋,因為這類液晶電玩,任天堂的 Game & Watch 當然是最知名系列產品,其次應該是 CASIO。

先問是不是就是影片中的這款:

老婆猛點頭說對,看來沒有比我也很懷念的 Game & Watch MW-56: MARIO BROS. 難找。

於是再往 Google Play 上找看看有沒有 clone 這款的遊戲,果然有,而且還不少人做!而 MW-56 這款搬貨工馬力歐兄弟卻沒人 clone,我難過。

看了一下維基百科才明白,原因是 EGG 這款當年在蘇聯有仿製品,所以可能是「國際」(←又是大叔的雙關語冷笑點)知名度最高的一款 Game & Watch,也解釋了為何 Google Play 裡找到的仿製遊戲面板是俄文。

頭一次見到老婆玩遊戲玩得這麼開心,比上次「打飛機」還開心。其實不管是「接雞蛋」還是「搬貨工」遊戲規則都很簡單,變化只在速度與偶爾的例外攪局,就能帶給人樂趣,在這個凡是遊戲都要 3A 級才上得了市面、看得上眼的時代,其實回頭想想,我們在追求無止盡的聲光效果進化時,是不是先問問「我這樣玩得開心嗎」?

之前在巴哈姆特裡不時有針對「任飯」「你們說任天堂作品的『遊戲性』較高?什麼叫『遊戲性』?你們自己都說不上來!」這樣的攻擊。我現在想想,「遊戲性」其實就是一種 UX(用戶體驗),或許 UI 有 guideline 可以遵循,但是光跟著 guideline 做,不代表你就能營造出讓人覺得 “Awesome!”, “Incredible”, “Wonderful” 的 UX。

嘗試做一個 envchain 的仿品 (6)

最近這幾天,下班後沒什麼動力,而且胃病又找上門,更是折磨人,還是沒有什麼明顯的進度。看了一下 dbus-rs 給的範例裡滿滿的 unwrap(),很好奇這方法是何作用,便搜尋了一下:

To “unwrap” something in Rust is to say, “Give me the result of the computation, and if there was an error, panic and stop the program.”

原來是一個錯誤處理用的便捷(且看來有點暴力?)方法。

嘗試做一個 envchain 的仿品 (5)

今天沒有什麼特別的進度,就是慢慢地把 Ruby PoC code 往 Rust 改寫而已。因為想要採行 TDD,所以按照  convention 為專案加上 tests/ 目錄,測試程式就可以放在裡面。過程當中因為同檔名程式的關係在鬼打牆,還以為怎麼程式就是無法跑出預期的結果。

同時把 rustfmt 架起來,仿照 gofmt 自動在我用 VIm 儲存 Rust 程式時自動排版程式碼。

嘗試做一個 envchain 的仿品 (4)

剛剛試了一下 writePassword(),沒問題,可以用 key-value pair 的方式儲存想要保密的資料:

require 'dbus'
require 'pp'
 
session_bus = DBus.session_bus
 
kwalletd_service = session_bus["org.kde.kwalletd5"]
kwalletd_object = kwalletd_service.object "/modules/kwalletd5"
kwalletd_object.introspect
kwalletd_interface = kwalletd_object["org.kde.KWallet"]
handle = kwalletd_interface.open("kdewallet", 0, "Ruby D-Bus Client").first
pp kwalletd_interface
 
kwalletd_interface.createFolder(handle, "envpick", "Ruby D-Bus Client")
pp kwalletd_interface.folderList(handle, "Ruby D-Bus Client")
 
kwalletd_interface.writePassword(handle, "envpick", "key-0", "value-0", "Ruby D-Bus Client")
kwalletd_interface.writePassword(handle, "envpick", "key-1", "value-1", "Ruby D-Bus Client")
pp kwalletd_interface.entryList(handle, "envpick", "Ruby D-Bus Client")

完全符合我的需求。

嘗試做一個 envchain 的仿品 (3)

ruby-dbus 去戳 D-Bus,可以順利解出 KWallet 的…binary 資料?

require 'dbus'
require 'pp'
 
session_bus = DBus.session_bus
 
kwalletd_service = session_bus["org.kde.kwalletd5"]
kwalletd_object = kwalletd_service.object "/modules/kwalletd5"
kwalletd_object.introspect
kwalletd_interface = kwalletd_object["org.kde.KWallet"]
handle = kwalletd_interface.open("kdewallet", 0, "Ruby D-Bus Client").first
pp kwalletd_interface
pp kwalletd_interface.folderList(handle, "Ruby D-Bus Client")
pp kwalletd_interface.entryList(handle, "Network Management", "Ruby D-Bus Client")
pp kwalletd_interface.readMap(handle, "Network Management", "{????????-????-????-????-????????????};802-11-wireless-security", "Ruby D-Bus Client").first

翻了一下網上資料才知道是這個原因:[Bug 256155 – KWallet’s readMap is not friendly to non-C++ applications],昏倒,這同時解釋了為什麼 kwallet-query 這專用工具可以解出 human readable 的密碼,而泛用工具不行。

以上只是想要瞭解 KWallet 的操作,為之後的 coding 鋪路,實務上應該還有路可繞。為了泛用性,最多就是不要用 map 而已。

嘗試做一個 envchain 的仿品 (2)

在 qdbus 上面試著操作 KWallet 資料,撞了不少牆。參考 [Learning on the Job: Accessing the KDE Wallet from the Cmdline] 這篇,目前還是不曉得怎麼用 qdbus 取出 NetworkManager 儲在裡頭的 Wi-Fi 密碼,當然在 KWallet Manager 裡頭是沒問題的,用

kwallet-query -r "{????????-????-????-????-????????????};802-11-wireless-security" -f "Network Management" kdewallet

也可以取出密碼,但是用 qdbus 就是卡在最後不曉得怎麼把

qdbus org.kde.kwalletd5 /modules/kwalletd5 org.kde.KWallet.entryList [handle] "Network Management" "Testing"

得到的 entry 去推出 key-value。無論是用 org.kde.KWallet.readMap 抑或 org.kde.KWallet.readMapList 都得不到我預期的回傳結果,目前只能先猜是我不知道怎麼用這工具的問題。晚一點可能可以來試試用 Ruby 去戳 D-Bus。

嘗試做一個 envchain 的仿品 (1)

前幾天在公司跟同事聊「果黑」、「果粉黑」話題時順道聊到的:「Linux 上似乎還沒有一個像 envchain 這樣使用系統內建密鑰管理系統(如 OS X Keychain, GNOME Keyring, KWallet)來維護環境變數的同質產品,看是不是可以用 Rust 刻一個?」於是這幾天就在做一些基礎研究。

其實 envchain 程式最關鍵處,就是從 Keychain 取出來環境變數,然後在呼叫 execvp() 執行程式時加上這些環境變數,原理不難懂。

我自己使用的桌面環境是 KDE Plasma,所以預設的密鑰管理系統就是 KWallet。一開始直接去 Google 搜尋 “KWallet API”,心想大概就是要用 FFI 之類的去 call C ABI 來解,雖然很硬斗,但是也還能接受。

再找了一下既有的 Rust crates 資源,以及瞄了一下 KWallet 的 package 內容檔案列表,發現其實不用這麼硬幹,透過 D-Bus 的介面就可以操作 KWallet API。

我的自炊(書籍電子化)經驗

由於書架滿了,且我沒有錢買間大房子,所以才決心買了這組「自炊」工具:

  • Brother ADS-2000 雙面文件掃描器
  • GREENON Meteor A3專業級裁紙機

加起來共一萬五千多,雖然要價不斐,但還是比起某些大大買的、更強大的組合要便宜個至少五千,也比買一間房子便宜

Brother ADS-2000 原本是看中它的可以直接插 USB 儲存裝置、直接掃成 PDF 功能,但是我手邊的任一 USB 碟它都不吃,我只好當作沒這個功能,退而求其次,回到連接電腦的方式來進行掃描作業。

GREENON Meteor 則比我預期還要好用,但是拆書的時候,還是得先用美工刀先將書不斷對切到約十張左右的小份,才能去裁邊,這是省不下的細工。

Brother ADS-2000 有提供 Linux 驅動程式,但是只有 *.rpm 與 *.deb 的套件格式,於是我還是上 AUR  去找好心的大德已經包好的 brscan4,順利在我的電腦上驅動這台掃描器,且 XSane 連它的雙面掃描功能 (Duplex) 都有對應支援,可以完整發揮它一次饋紙就掃雙面的功能,這台在 Linux 上功能也不打折,價格也頗實在,我很滿意。現在買還送標籤機跟印表機,真是吃撐我了,家裡都沒空間了還送我這麼多東西。

掃描好的影像檔,再送到 Scan Tailor 去處理校正歪斜、裁去白邊、去雜點、調整輸出濃淡後,輸出成 *.tif 檔。

接著再用

tiffcp -a scan-*.tif book.tif

將多個 TIFF 檔合併為單一多頁 TIFF 檔,

tiff2pdf -z -o book.pdf book.tif

將這個單一多頁 TIFF 檔轉為 PDF 檔,就大功告成。

如果沒有雙面文件掃描器與裁紙機的輔助,只用傳統平台式掃描器與美工刀,我看一本紙本書轉成電子書的工作大概要花上好幾天,且很可能這些人工繁雜到會讓你想半途而廢,所以如果要搞自炊,請至少一定要買一台雙面文件掃描器,它會讓整個作業不只變快,也減少失誤。