發表文章

目前顯示的是 2011的文章

【Startup 談心酸】 當革命情感對上體制

我總認為,當別人問起職業,回答『Startup(新創)』是一件很自傲的事。雖然公司不大,但是從兩手空空開始,完成理想的感覺真的是棒呆了!你必需經歷『養活自己』、『勒緊褲帶』、『想破腦袋』還有『革命不怕失敗』的種種過程,最重要的是,伴隨而來的『人的問題』,很有可能成為最後一根稻草,壓垮我們。但每當跨越過每一個階段,彷彿就吃了甜美多汁的果實,相當有滋味。

常聽到有人說:『先不談成功與否,Startup能做超過一年,就相當不容易了。』,其實是事實,從創業中敗陣下來的人不在少數,敗陣的原因更不勝枚舉,有人是受不了壓力,有人把持不住Cash Flow(現金流),有人經營心態不正確,或是 idea 失敗等等。但是,這些原因真的都比不上『同伴』所造成的打擊。

如果你不是一個人創業,而是三五好友有志一同,那我要恭喜你,畢竟要能找到方向相同,又有足夠能力的人一起是非常困難的。但是,我也要為你感到遺憾,因為『人的問題』會帶來更多波折和困難,造成創業失敗的比例更高。『同伴』是個雙刃劍,雖能共患難,有革命情感,但也會因決裂而一夕之間毀滅。

這裡有一個朋友的小故事,相當常見,或許大家都很熟悉其中情節:
有一群人在學校就是好朋友,而所會的技術也讓他們相當出類拔粹,於是,他們孕釀出創業的想法。為了小試身手,這些人開始共同接一些小案子,並培養革命情感。看似一切很美好,但在過程中問題出現了,有人怠惰(或是能力不足)造成其他人負擔增加,又或者是因此造成案子無法順利結案。好不容易,其他隊員們跳出來『Cover』,讓一切過了關,客戶也付了錢。 然而,問題才正要發燒,在分配利益時,有人開始提出不滿:『為什麼出包的同伴,可以拿的錢和沒出包的人一樣多?為什麼救火的人,幫出包的人完成不是自己的大部份工作,卻只拿到原本的待遇?』此外,對工作的分配也頗有微詞,有人認為自己做的工作,相對困難許多,應該分到更多的錢。更誇張的是,每一個人都生怕別人多拿或是拿的比自己多。 還好,為了讓大家不要決裂,盡可能滿足大家的要求,有人跳出來處理這件事,除了自己掏腰包,甚至動用了原本大家講好要保留下來的『公基金』。然後發現,雖然大家都同意切出一部份成為公基金,但心中仍然認定這公基金有一部份是屬於自己的,隨時都可以要回去,有人更不時想動用或拿回這個錢。一旦動用公基金,就會牽動到大夥的神經,引發更多莫明其妙的問題。 問題並沒有因為時間…

從 Linux Kernel 出發看!探討 Process 組成結構!

對所有電腦使用者而言,執行一支應用程式就像吃蛋糕一樣簡單。對於程式開發者而言,寫支 Hello World Program 並跑起來,也是三十秒內可以完成的事。但是,這樣容易的動作,其實底層有著複雜的機制,否則短短十行程式碼的 Hello World 能夠動起來,真的是奇跡了。想要知曉程式是怎麼被作業系統執行,要追溯到 Process 的機制,在研究過 Linux Kernel 的 Process 相關機制後,一切就將明朗。

註:在本篇文章內,都將會假設 binary program 已經被作業系統解析並放到記憶體執行,說明只著重於 Process 的部份 。雖然 Process 與 binary program 和其載體息息相關,但本文不會討論 ELF 的細節,有興趣的讀者可以自己去尋找相關文件閱讀。

若你是程式開發者,對『Process(程序)』一詞應該不陌生。嚴格來說, Process 就是處於執行狀態的程式,如果參考一些原文書或英文文獻,它們也許會這樣定義:『Process is a program in execution』。所以我們可以認定,Process 的組成,是擁有著『程式執行檔的 binary code + 記錄資料的記憶體』。

本文將 Process 分成內外兩個角度來探討:
從 Process 內部,程式執行的觀點 從 Process 外部,也就是作業系統的觀點 
程式執行的觀點

單純以 Process 內部的角度來看,Process 就是一般的程式碼被放到記憶體執行。曾於舊文『Linux 下程序的記憶體映射』略為提及,一支程式擁有著數個 segments(區段),並仰賴著這些 segment 來持續運作。大致上來說,每個 segment 有不同的用途:
Code Segment - 存放主要程式Data Segment - 存放已被初始化並賦予值的全域變數BSS Segment - 紀錄尚未被賦予值的全域變數Stack Segment(Stack/Heap) - 紀錄 Process 在執行時動態註冊的變數包括 function 中的 local variable
對程式本身來說,會動態並隨機使用的是 Stack Segment,程式向作業系統(OS) 要記憶體空間後,就可以在 Stack Segment 讀寫該記憶體空間。而實際上 OS 底層的…

如何在 Debian 建置 NodeJS + Express 環境

截至目前為止,只有 Debian Sid(unstable) 提供 Nodejs 和 Express 套件可讓使用者直接安裝。但是,在 Server 的環境之下,一般都使用 Debian 5.0/6.0 (Lenny/Squeeze) 穩定版的系統,因此沒有套件可以直接安裝,唯一的方法就是自己下載編譯 Nodejs。還好自己手動安裝的過程並不困難,幾個步驟就可以完成。

安裝 Nodejs

更新系統並安裝編譯 Nodejs 所需的套件:
sudo apt-get update sudo apt-get install git-core curl build-essential openssl libssl-dev
從 Git Repository 下載 Nodejs 原始碼:
git clone https://github.com/joyent/node.git
進入 Nodejs 原始碼目錄,並切選擇我們要的版本(截至本文,0.6.6 是最新版):
cd node git checkout v0.6.6 # Note: 可以使用 git tag 看到 Nodejs 所有的版本列表
編譯並安裝 Nodejs (預設會裝到 /usr/local/lib/node):
./configure make sudo make install
如果安裝過程中沒有任何問題,就可以使用 node 指令查看 Nodejs 的版本了:
node -v
手動設定公用的 Nodejs Module 路徑:
echo "NODE_PATH=/usr/local/lib/node_modules" >> .bashrc # Note: 如果想讓所有 Server 上的 user 都套用設定,可以放在 /etc/profile

安裝 Express Web Framework

使用 npm 安裝 express(使用 -g 選項會安裝到公用的目錄 /usr/local/lib/node_modules):
sudo npm install express -g
Express 通常預設使用 jade template engine,也需要手動安裝:
sudo npm install jade -g
安裝完成後,就可以立即測試 nodejs + express:
mkdir te…

Nodejs + Express 的 Route 流程規劃

如大多數人的習慣,往往我們都把 Route 的路徑都定義在 app.js 當中。Express 所提供的眾多範例程式中,雖然有將 Route 抽出來放在 routes 目錄下的實作方式,但也太簡單,只支援一層的設計。這意味著,如果 routes 之下有更多子目錄,放著更多的 route 設定,都是不會被讀取的。

這邊做了簡單的修改,利用遞迴的做法,掃描所有的子目錄,然後去載入所有的 js 檔案以擴充 Route 的設定。

以下是 route.js 的程式碼:
var vm = require('vm'); var fs = require('fs'); module.exports = function(app) { var dir = __dirname + '/routes'; var context = { app: app, require: require }; var newContext; /* Initializing Context */ for (var key in global) context[key] = global[key]; newContext = vm.createContext(context); /* Loading all routes */ loadRouteDir(newContext, dir); }; function loadRouteDir(context, path) { /* Scanning files */ fs.readdirSync(path).forEach(function(file) { loadRouteFile(context, path, file); }); } function loadRouteFile(context, path, file) { var fullpath = path + '/' + file; fs.stat(fullpath, function(err, stats) { if (stats.isFile()) { /* Loading route */ var …

Openmoko 永遠活在我們的心中

圖片
還記得 2006 年 12 月業界出現了一個瘋狂的想法:『Openmoko 的開放手機』,但就在 2011 年 12 月滿五年,這家公司(Openmoko, Inc) 也將劃下了一個圓滿的句點。

回顧過去,Openmoko 不只是單純的軟體層面開放,而是連硬體設計的細節都公開。這對當時的大環境,高端手機技術和 Know-how 都被嚴密掌握在特定公司的時局下,無疑是個瘋狂的舉動。想當然,Openmoko 花了大量錢財與人力物力,還有國內外社群的力量,終於做出了自己的第一代手機原型(參考圖 Neo 1973),爾後又開發出第二代硬體加強版的機種(參考圖 Neo FreeRunner)。

還記得,當時大多數人都還是使用功能手機(Feature phone),智慧型手機(Smart Phone)也還停留在被難用 Windows CE 稱霸的時代,誰也還沒有想到未來會有 iPhone 和 Android Phone,對絕大多數人而言,手機是個神祕且只有少數人可以參與開發的領域。有趣的是,Openmoko 除了做開放的手機之外,也對應用程式(Apps)安裝於手機上的想法有了初步的構想,而這些想法,都觸動了不少軟體開發者和投資人的目光。

雖然直到最後,Openmoko 的手機還不足以讓一般消費者順暢使用,但許多構想,無論是開放手機,有擴充性的應用程式平台,還是使用 Linux 開發前衛的智慧型手機,都確實已深埋在不少人心中。世界各地的 Hacker 和高手,無一不想擁有這樣一台的開放手機。

Openmoko 也在教育界扎根,除了提供開發的教育訊練外,也去拜訪了許多大專院校,讓許多原本沒有機會碰到手機開發的學生和技術人員,有機會一睹這神秘的領域。然後,也有不少學校買了 Openmoko 的手機,做為開發教學使用,直至今天,這些手機還是相當好的開發教材,甚至,也已經有不少教授在這上面開發了一系列教材。(如:淡江大學資工系已經將 Openmoko 手機當成 C 語言教學和相關基礎技術的實作平台)

隨著 iPhone 的問市,Google Android 的出現,Openmoko 逐漸失去了媒體焦點,也有不少不為人知的事情,讓公司逐漸縮編並轉型(之後轉做過 WikiReader),以致現在的人,多半都只是耳聞,漸漸忘了當時 Openmoko 花大錢招頂級人才,遍布全世界的開發者和分公…

Android 問題百出之 2.3.x 的 JavaScript Interface

有鑑於 Android 問題太多,只好定了個系列標題『Android 問題百出』當開頭,並將碰到的問題和解決或避開的方法記錄在內。話說回來,筆者個人其實相當討厭 Android,自 Android 出現以來,從未真的投入其中並賺過什麼錢,會接觸,多半是興趣玩弄或是幫一些朋友的公司臨時打工救火。不過,既然是救火,任何千奇百怪的問題或狀況都會遭遇到,甚至還得『限時』解決別人解決不了的問題。

這次碰到的問題就是 Android 2.3.x Gingerbread 缺少 JavaScript Interface 的實作,如果你的應用程式有自己實作 API 供 JavaScript 程式使用,那這些 API 將會完全失效。而這樣的問題,對於使用 Web 技術(HTML5 + Javascript)的應用程式來說,相當嚴重。

話說 Android 在 2.3 版本之後,採用了 V8 做為 JavaScript Engine。在快速掃過 Android 關於 WebView 和 WebKit 的程式碼後,發現不幸的是『Google 再次未將程式寫完』。但這一次,不只是功能未完成,而是將原本可以用的功能(在 Android 2.2),變成不能用。這讓筆者非常不能理解,為何 Google 換了 V8 Engine 後,明知功能沒有改完,卻仍將這部份實作隨新版 Android 釋出?然後,絕大多數廠商,在毫無感覺之下,直接繼承了這樣的 Bug。

對硬體裝置的廠商來說,重新實作這個 JavaScript Interface 支援是最佳的解決辦法,髒一點的方法是將 V8 改回舊的 JSCore。但很可惜的是,就算有人改好了,也沒有廠商願意釋出這部份的程式碼。(所以才會不停有人願意花大錢找筆者這種臨時救火工呀。)

此外,如果你是一般的應用程式開發者,因為動不了底層,則完全無解。但是,這邊有個 Workaround,可以暫時代替 JavaScript Interface,讓應用程式開發者可以避開這問題(以下假設自定的 JavaScript Interface Class 為 myAPI)。

定義將會用到的變數:
/* Define private variable */ private static WebView mWebView; private static myAPI mJSIF; p…

NodeJS + Express 實作檔案上傳

Express Web Framework』是基於『Connect Middleware Framework』所開發,大部份的常見功能,藉由 Connect 本身支援或 Connect 的第三方(Third-party)模組,就可以實作出來。如果要實作檔案上傳的功能,可以使用第三方模組『connect-form』來達成。

直接透過 npm 安裝需要的模組:
npm install connect-form
在 app.js 中實作:
var express = require('express'); var form = require('connect-form'); var app = module.exports = express.createServer(); app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(form({keepExtensions: true,uploadDir: __dirname + '/uploads'})); app.use(app.router); app.use(express.static(__dirname + '/public')); }); app.get('/', function(req, res) { res.send('<form method="post" enctype="multipart/form-data">' + '<p>Image: <input type="file" name="image" /></p>' + '<p><inp…

在 NodeJS + Express 使用 Cookie-based Session

開發網站的人應該對 Session 都不陌生,主要是用於 Client 與 Server 之間的溝通和狀態記錄。底層的實作細節本文就不多說明,若仍不理解他的用途,只要知道它可以讓你在不同頁面之間傳遞資料,像是登入狀態等。

一般標準的『Express』利用『Connect Middleware Framework』(之後簡稱 Connect)中的模組來實作 Session 的,而預設的方法是使用 MemoryStore 的方式,也就是將 Session 資料存放於記憶體上。若你開發的是中大型的網站,也可以使用 Connect 的第三方模組『connect-redis』,利用『Redis』這樣的 Key-Value Database 來存放 Session 的資料。這些在 NodeJS + Express 的各類開發文獻中相當常見,你可以從許多網站上找到使用方法。

不過,也許你仍不滿足,希望使用近年來興起的 Cookie-based Session,Connect 也有第三方模組『cookie-sessions』可以使用。

可以直接使用 npm 安裝:
npm install cookie-sessions
在你的 app.js 這樣使用:
var express = require('express'); var CookieStore = require('cookie-sessions'); var app = module.exports = express.createServer(); app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser()); app.use(CookieStore({ secret: 'FredChien' })); app.use(app.router); app.use(expr…

千萬別相信 Android 上的應用程式

或許有些過於危言聳聽,但我們確實得正視這樣的議題:『資料無故從手機中消失』。這是可能發生的問題,原因在於 Android Dalvik VM 的 Garbage Collection 機制太過強大,如果程式開發者在寫程式的過程中都沒注意到這問題,那這肯定是個不定時炸彈。

話說,寫過 Android Application 的人應該都很習慣了變數宣告後,用完了就不管他,彷彿系統會有無限量供應的記憶體一般。不過,這對『慣C』一族來說,永遠是種荒繆的事,實在無法想像『憑什麼』不用釋放記憶體。其實說穿了,這一切是 VM 裡面的 Garbage Collection 在『Hold 住』場面,他會自動將目前 Reference 數量稀少的記憶體回收,以避免系統記憶體被用光後又不釋放。而所有回收的動作,有一系列『聰明』的演算法,有興趣的人可以自己去找相關資訊閱讀。

但是別以為 Garbage Collection 可以聰明到百分之百準確知道,什麼東西回收後是對系統或是應用程式無傷的,因為這就算要人腦來判斷,也一定會犯錯。更者,也別以為 Garbage Collection 不太會動當前正在跑的程式,因為只要符合條件,就算是你程式當前不斷在用的變數,也可能消失被回收,導致程式錯亂,就像被鬼憑空抓走一般。

如果你認為這只是理論,那你就錯了,這問題實際發生在最近筆者幫忙救火的案子裡。詳細情況是,這是瀏覽器相關的案子,當時我們宣告了幾個 Private 變數,然後使該變數在使用者操作觸發後,會被設定了一些數值供接下來的許多運算使用。一般情況下,我們實作的程式都很正常,不過,一旦開到比較複雜或充滿 JavaScript 的網站後,我們的程式彷彿就開始像中邪,完全不照我們的想像去執行,無論怎麼找問題,也找不出個所以然。

由於問題的發生是過程中變數無故被歸零,而我們又確定沒有任何一段自己的程式會讓他歸零,所以只剩下一種可能:『Garbage Collection 為了因應 WebView 過多的需求,而把變數給回收了。』

最後,我們將這變數設為 static 以解決這問題。不過,雖然用 static 暫時解決了問題,那也只是減少變數不被回收的機會,並不是最妥當的做法。

後記

別小看這問題,其實在 Android Framework 中也處處藏滿類似的問題,只是不知道什麼時候會爆出來而已。而這次…

自認帥氣的 WebSocket 簡單命令處理模型

最近參與的一個 Project,需要在 WebSocket 下實作許多機制,這著實讓人傷透腦筋。又由於 JavaScript 完全是非同步(asynchronous)的設計概念,若遇到必需等待 Server 回應後才能繼續執行的工作,處理起來可是一件異常麻煩的事。雖然很熟悉運用回調函數(Callback Function)和暱名函數(Anonymous Function)來做,但一層包一層的設計,總讓人覺得進入無限階層的夢境地獄,什麼時候醒來都不知道。

這是筆者要達成的需求:『發送自己定義的命令去 Server,然後等待 Server 回應,一旦收到 Server 回應就可以繼續往下處理。』

一般的情況下,多數人都會這樣做(這理使用 Socket.IO 來建立 WebSocket,並和 Server 要當前時間為例):
/* Define handler to receive response from server */ socket.on('Clock', function(data) { /* Do something */ alert(data); }); /* Send command to server */ socket.emit('Clock', 'Time');
可是,並非每次對 Server 的請求,都希望透過 alert() 跳出結果,我們有時只是想要利用 Server 給的時間做一些其他處理,雖然是下同樣的命令,但後續處理完全不一樣。於是,筆者,設計了這樣的方式,簡單的去處理這種問題:
var command = { 'Time': [], 'Date': [] /* You can define more commands */ }; socket.on('Clock', function(data) { if (command[data.command].length) { for (var index in command[data.command]) command[data.command][index](data.result); …

使用 Jade 快速製作 HTML Template

如果你用 NodeJS 和『Express Web Framework』來寫網站,又參考官方給的範例程式,『Jade』應該是你首選的 Template Engine。不過 Jade 相當容易,如果你已經很熟悉 HTML,學習它不會是件難事。

Jade 用來表示每一個 HTML Tag 的格式:
<tag>(<attributes>) <inner content>或是<tag>(<attributes>)= <inner content> ex: img(src='/images/logo.jpg') ex: a(href='http://www.mandice.com/') Mandice ex: title= This is Jade Example
使用縮排描述巢狀結構( 如同 Python):
Jade 語法: html   head     title= This is Jade Example   body     Hello World 結果: <html>         <head>                 <title>This is Jade Example</title>         </head>         <body>Hello World</body> </html>
賦予 Element 一個 ID 有兩種方式:
div(id='element1') 或是 div#element1
引入並使用另一個 Jade 檔案:
div#element1= partial('another.jade')
賦予 Tag 有多個 Attributes 有兩種方法:
使用『,』連接多個 Attribute: img(src='/images/logo.jpg', title='This is a Logo') 使用換行連接多個: img(         src='/images/logo.jpg'         title='This is a …

我如何看待 NodeJS

圖片
其實,這是篇推薦文,但推薦的角度和坊間很多人不一樣,所以這也是為什麼標題下『我如何看待 NodeJS』。

誠如大家所知,『NodeJS』原先被開發出來的目的,是為了解決 Web Server 效能的問題,其採用 Google Chrome/Chromium 使用的『Google V8 Javascript Engine』做為直譯器引擎。最特別的是,NodeJS 讓開發者完全可以用 JavaScript 來開發整個伺服器端的所有程式,這意味你可以不用再使用 Python、PHP、Perl、Ruby、ASP 等其他的語言,只需要學會 JavaScript 就可以將網站通通搞定。也因為幾乎所有的 Web 開發者都熟悉 JavaScript,NodeJS 很理所當然的成為一個 Web 圈內受很多人擁護的新技術,在各大 Cloud Hosting 也都開始有支援。

當然不只是如此, NodeJS 也吸收了各方面的經驗,提供應用程式框架(Framework)讓開發者可以快速開發。平心而論,比其他的語言更能兼固快速開發和效能的問題。

談到這裡,還是僅止於坊間多數人介紹的內容,筆者認為,如果只是這樣,也未免小覻了 NodeJS。

事實上,NodeJS 就是 Original JavaScript Without Browser + Libraries,在舊有的 JavaScript 抽離瀏覽器後,再上加上更多 System-level Library 的支援。這讓我們可以重新看待 JavaScript 這個語言,因為它不再只是限於『特定領域』使用,而是提升至『System Level』。

我們可以這樣認定:『JavaScript 已經可以和 Python 相提並論』。因此,使用 JavaScript 寫一支系統應用程式或是桌面應用程式,已經不再是夢,而是伸手可及。如果你有印像,HP WebOS 就是率先引入 NodeJS 的先行者,讓原本被視為 Web 技術的 JavaScript,跳出舊有框框,進入桌面系統的領域。

目前,NodeJS 仍持續發展中,許多函式庫支援也被慢慢的被實作出來。有時為了效能考量,我們也可以自己使用 C/C++ 為他開發更多 Library/Module。可以期待,未來 NodeJS 將會更為強大。

使用 NodeJS + Express + Socket.IO 實作 WebSocket 服務

一直處於假標準狀態的 HTML5,過程中一直有變化,讓人無法放心使用。不過到了今年,HTML5 總算進入了準決賽的階段,大部份功能已經確定下來,其中 WebSocket 就是最讓人關切的項目之一,因為這意味著未來 Web 不再只是單次性的觸發服務,而是可以讓使用者端與伺服器長時間處於連線狀態,並進行即時性的資料傳交換。

關於 WebSocket,彷間許多隨 HTML5 起舞的人,其實都說明不夠清楚,多半只強調能達成 TCP Socket 形式的連線,和無所不能的優點。其實,WebSocket 並非是我們所知的原生 Socket ,而只是一種架構於 HTTP Protocol 上的延伸定義,所以換句話來說,不能直接拿來連線到非 HTTP 以外的通訊協定。

至於它的做法,就是在瀏覽器向伺服器要資料時,在 Request Header 裡加上『Connection:Upgrade』來告訴伺服器:『我要改變連線形態』。然後伺服器會依照瀏覽器給的 WebSocket 相關標頭(header)和交握用的金鑰(Key),進行認證和改變處理方式。進入 WebSocket 連線的客戶端,就有如在使用 TCP Socket 或 Telnet 一樣,可以隨意在任意時間點傳送資料給伺服器處理,伺服器也可以在這連線下即時回應。所以就某方面來說,這剛好可以含蓋並取代過去 Web 1.0 的 Refresh Page 和 Web 2.0 後的 Long-polling 技術。

寫過網路程式的人都知道,如何定義 Protocol 才是傷腦筋的事,開啟了一個『類 Socket』意味著我們又回到了過去的年代,要自己解決 Protocol 的定義。不過也已經有現成的 Library 可以使用,許多問題我們已經不用擔心,本文將提到的 Socket.IO 就是其中之一。此外,由於 WebSocket 需要 Client/Server 同時實作,所以,這些 Library 多半都包括了兩部份的實作。

Server 端,使用 NodeJS + Express web framework + Socket.IO(0.8.6):
/* Module dependencies */ var express = require('express'); var io = require('sock…

偏好的 JavaScript Class 實作『基本款』

最近有一些想法,便和伙伴在空閒時間寫一些 Prototype 的專案,既然是嘗試形態的專案開發,就不必考慮穩定性和熟悉度,也不用顧慮失敗的問題,可以盡情玩弄新的,或是過去不常使用的技術。所以,這次使用了 nodejs + express + HTML5 來開發,大玩 JavaScript。JavaScript 雖然看起來像 Java,但畢竟它不是真的 Java,很多功能考量以易於使用為優先,所以並不嚴謹,一些功能也因此被拿掉。畢竟,當初被設計出來只是為了讓『網頁動起來』,並沒有考量太多。但是隨著需求大增,而現在我們所看到的 JavaScript ,已經是一層層為了需求而疊出來的產物,其不旦保留與舊的 JavaScript 相容,又要擴充物件導向的現代化語言特性,這也是為什麼使用起來總是沒有一個固定的模式。筆者過去總苦惱 JavaScript 的寫法變化太大,在過程中跌跌撞撞,雖寫了不少 Code,但總是覺得不順手,非常想尋求一個 JavaScript 設計模式的『基本款』,也希望和開發伙伴們有共同遵循的標準,讓專案更容易維護。 經過和隊友們的一番討論,總算有一些結論: /* Example Class */ var Example = function() { /* Private */ var Status = 0; var doms = { object: false; }; var subObject = false; /* Constructor */ subObject = new OtherClass(); doms.object = document.createElement('div'); /* Public */ return { setStatus: function(_status) { Status = _status; }, getStatus: function() { return Status; }, getDOMs: function() { return dom…

程式開發者之不要過度依賴別人解決問題

常有人說,資訊產業變化太快,如果不及時跟上,馬上就落伍了。事實上不全然如此,應該說在這產業是不進則退,至於要不要跟著潮流走,不一定。其實講明了,電腦科學並不是真正的科學,而是種社會學,由於大家的方向和需求多半是一致的,可以很容易預測到未來需要用到的各種技術,或是常有別人已經完成的工具或技術可直接使用,而且研發新技術也不需要像真正科學一樣,我們不需要長篇幅的理論基礎,只要能解決當前問題即可,如何不斷的解決需求和問題才是我們所在意。

在之前舊文『程式開發者之萬事起頭難』有提過,開發軟體相當依賴經驗。所以,不管是如何找到解決問題的辦法,都必需要經過實作執行然後吸收,並轉化成程式人員的經驗才有意義。也因此,只要能獲得新的經驗,拓展視野,什麼方法都可以。不過,筆者認為『追著最新的外來技術』和『自己發展技術』兩種途徑最為重要,而且缺一不可。如果用武俠小說的角度來說,就是招式和心法的配合,增加內力的累積。
自己發展技術就不用多說,我們能從實地的演練,獲得大量經驗和想法,而且會得到實務考量的觀念。比較需要注意的是『追著最新的外來技術』,因為很多時候,我們面對這些技術的態度,會讓自己無法分辨自己所得到的是『招式』還是『武功』。
或許很多人以『學了很多招式』而自豪,但面對真正的需求和挑戰時,便無法應對自如,招式套不上去,此時才抱怨『書到用時方恨少』,殊不知是學習新知的態度有問題所造成。因為缺少了質的招式,並不具有太大的意義,而且永遠要追求更新更有用的招式,才不會有招用老的一天。可是,一旦碰到 Google 大神或書裡沒有答案,就完蛋了。記得,學會很多招式或工具,只是『幫助提升工作效率』,相當於大學生會剪剪貼貼罷了,缺少深入的理論和資訊定位分析,或沒有學習問題的根本,並無法累積解決問題能力。
所以時時都要準備哪一天『如果沒有 Google』,也不要再只是窮追新的 Library 或 open source project。導致一旦沒有其他人供獻這些東西,自己便沒能力完成專案。雖然說要全部都懂是很困難或不可能達成,但要盡量做到,才能得到屬於自己的關鍵技術。以前人說的:『站在巨人肩上』,指的就是追到最新技術後,再發展技術,如果只是使用而沒有再發展,就等於沒有進步可言,遲早會被騎在更高巨人身上的人所打敗。
程式人員要盡可能快速從『請 Google 幫忙』職業學校畢業,才能當一個稱職的開發者。

程式開發者之傻傻搞不清楚技術定位

常聽到有人說專案選錯技術而失敗,或是造成什麼嚴重問題,其實這其中,是有很多原因導致選錯技術。不過,對於初入這行業的人來說,所知所見不夠廣,是最主要的問題。

使用正確的解決方案能讓軟體專案或是產品專案更加順利。所以開發前要做足功課,通盤的瞭解和業界各種大小的動態都不能放過(相信身為程式人員,看英文資訊的能力應該不必擔心),哪怕該技術存在的領域可能與我們當前熟悉的領域相差十萬八千里遠。因為如果視野太狹窄,就看不到更好的技術方案,更沒有機會觸類旁通。有了足夠資訊,如同有了一張地圖,也就有跡可尋自己不足之處和其解決之道。

有了地圖,便要開始認清方位,身為程式開發者,懂一項技術的優點和極限是絕對必要的,所以一定要了解一件事實:『懂一種技術能做些什麼,並不代表了解該技術只能做些什麼。』瞭解透徹,才能正確的選擇解決方案和確實將目標達成。

搞清楚各種技術的定位後,便要應用在一個專案開始前,使用所知去選擇解決方案。記得過程中要隨時保持所選擇的技術,在緊急時刻可替換的彈性。專案開始後,切勿將陌生領域的東西寫得太過死硬,要可以容易被切割獨立。因為若是在開發過程中,才發現原先使用的技術可能並不適合在目前的用途上時,可以用另外的技術來彌補或替換。除非,有時間上的壓力或限制,硬是使用不適當的技術完成任務是容易有後遺症的,而且容易傷害到使用者體驗。更重要的是有很大機會達不成目標的標準。

此外選擇技術的評估,除了應該先有通盤知識為基礎,應該以客觀或是跨時代的角度來做,而不是以自己手上的電腦硬體,或是自己目前正習慣使用的平台或喜好的技術為準。一旦專案有挫折或失敗,才來說當初選錯平台,實在是浪費時間。而且,還可能錯上加錯,因為不是選錯平台而是選錯技術的可能性更大。

要知道,這個時代是多元的,只熟悉或知曉單一方向技術,是無法有太多創意和實作能力的。解決問題的方法並不需要貫徹技術到底的決心,只要選擇適當即可。

程式開發者之萬事起頭難

接觸程式開發也已經十五年有餘,雖然不算多,但也算經歷過不少風雨。於是趕在二十五歲結束前,開始記錄起『程式開發打字工』的種種心得。之後,如同數學家的二十五歲大限,希望『程式開發打字工』將成為興趣與次要的工作,不敢說可以完全放下,但必要動手做時也會不假別人之手。

首先談到開發一個新的專案,俗話說萬事起頭難,我們馬上會碰到千頭萬緒襲來。而且我們什麼都想做,什麼都想完美,往往還沒開始就已經結束了。此時心神不定,煩燥之時若螢幕上閃過X浪或 Facebxxk 的身影,再來個香蕉動新聞,一整天馬上就過去。

寫程式很重要的的一個原則就是:『不要想一次都要做太多功能。』尤其是在初次接觸的領域。因為,光是計劃架構和細節就會先消磨掉大半熱情。甚至開始實作以後,你會因為到處要留後著而難以前進,把自己陷於無法動彈之地。一但沒有動力,也沒有前進的路,該專案將胎死腹中。

如果有足夠的時間,專案初期不斷打掉重練,是可以接受的。因為這比起日後累積太多量後,才發現不適合再打掉重練而來得好。也不會因為在錯的基礎上開發,而降低開發效率,甚至寫出問題重重的軟體。

至於『如何才叫太多功能』,這依每個人而定,經驗多寡決定了一個人能快速設計多大規模的架構,並且能在該架構下工作而不會自亂陣腳。同樣類型的程式,如果你有過去的實作經驗,這次肯定有思緒改進或是延用。反之,如果沒有過去的經驗,很難做太長遠的細節規劃,你能靠的只有『過去學會的程式技巧』和『類似經驗』,盡力設計一個勘用的架構罷了,然後經過提早發現問題提早重新來過,盡可能補完整個專案所需。

當然,除了程式技巧和相關知識,經驗是不通用的,如果碰到不熟悉的專案,還是得從頭累積經驗,從小規模的設計一步步前進。記得不要貪多,一個功能一個功能確實完成,『慢慢來,比較快』。

Apple 大軍壓境,電腦王國準備好了嗎?

如果沒意外,Apple 將以低價重回戰場,掃蕩剩下的反抗勢力,用升級版的硬體,鞏固現有的防線。那麼,過去的電腦王國,準備好應戰了嗎?顯而易見:『還沒。』

我們可以期待,接下來手機裝置的局面很可能是三分天下:『Apple、Nokia、Moto』,他們分別背後擁有強悍的軟體公司或團隊支援。雖然 Google 目前沒有說要開始親自投入戰場,但是品牌和代工合體後的 GMoto(Google + Moto Mobility),難保有一天不會自己殺出條血路。就算是台灣當前的對手 - 『韓國』, Samsung 也擁有著自己的軟體系統。那麼,電腦王國怎麼辦?身為電腦王國的國民,不免擔憂起這樣的局面。

舊時代王者的現實

郭董已經證明,鐵血毛利之下除了逼人跳樓之外,缺少政府『幫助』後,現在才正要開始體現代工產業下應有的利潤和風險。在這薄利又不景氣的時代,比誰和銀行借的錢多,已經不管用了。

缺少商業模式的資訊產業

如果有夠大的商業模式或願景為前提,就算是當年 PC 時代的『大補帖』歪風,都能有掀起錢潮的機會。任何點子和創意,都足以大舉刺激商業發展。

今天,拼命的生蛋和不停的脫皮,算斤兩的生意,卻已經變成主流。

硬體廠商心中的不平衡

還記得當年 PC 獨霸的年代,微軟一舉跳上枝頭,收盡一切好處。硬體廠商雖然拼命做,扛下所有生產風險,但每台電腦所獲得的利潤逐年降低,直至今天這『毛利』的勢態後咬牙苦撐。反觀微軟靠著數不清的五毛光碟片,賺得荷包滿滿。現在殘存的硬體廠商,誰不恨得牙癢癢?所以只要有機會解決微軟,讓原本應該進微軟進自己口袋,何樂而不為?

此外,Apple 以一家非硬體製造商的身份,用 iPhone/iPad 打下一片江山,讓所有人失了面子也失了市場。沒有一家廠商不這麼想:『既然 Apple 可以從一家軟體(或稱為系統整合)的公司,跨足到完全不相干的手機產業,那麼,身為硬體製造商的我們,為什麼不能跨界成為 Apple 呢?』

於是,成為『類 Apple 公司』變成這些傳統 PC 製造商的夢。

Android 滿足了硬體廠商心中的不平衡

終於有機會可以自己掌控作業系統,不用再給微軟或任何系統軟體業者半毛錢。各家廠商無一不開始宣布自家有完整的系統技術團隊,可以針對作業系統做任何改進和維護。對硬體商來說,有了一個可以佔有的作業系統後,這不就代表:『我也是 Apple 了嗎?』

於是,喊出各種軟硬…

改善 QML 圖型渲染效能

雖然 Nokia 擁抱了 Microsoft,但不可否認,其旗下的 Qt Framework 經過十載演進,也有 Open Source 出來,實在是個好東西。因此,筆者認為 Nokia 的決定並不會影響我們繼續使用 Qt 的意願,長期在 Linux 下並以 Qt 為基礎的 KDE 桌面環境,就足夠證明了 Qt 尚未死。

而最近筆者使用 QML 實做了一些應用程式,發現圖型渲染效能並不是非常好。猜想是和 Android 有相同的問題,於是著手將程式改用 OpenGL 來繪圖,果然,效能立即獲得大幅度改善:
int main(int argc, char *argv[]) { QApplication app(argc, argv); QGLWidget *glWidget; QGLFormat format = QGLFormat::defaultFormat(); /* Create OpenGL Widget to render QML */ format.setSampleBuffers(false); glWidget = new QGLWidget(format); glWidget->setAutoFillBackground(false); /* Create QDeclarativeView to open QML file */ QDeclarativeView *viewer = new QDeclarativeView; viewer->setViewport(glWidget); viewer->setSource(QUrl::fromLocalFile("main.qml")); viewer->show(); return app.exec(); }

Flat Project Demo - An OS for Tablets 平板作業系統

圖片
無奈,前些日子在 COSCUP 2011 因為 Lightening Talk 時電腦出現異常,展示以失敗告終,耿耿於懷。於是趁著這次中秋假期,將 Flat Project(詳細說明請見前文:Flat Project - 從山寨做起,親手打造炫麗的平板系統)開發至一半的測試影片準備好並上傳至 Youtube。但錄影效果不佳,還請包涵。


主要實作了 3D 視窗管理器(Window Manager+Compositor),如果不熟 X11 架構,也可將它視為 Android 上的 SurfaceFlinger,更多深入的技術細節也已經在 COSCUP 2011  Unconference 議程做了粗略說明。藉著這個成果,可輕易將各式應用程式(Firefox+Google Map+OpenGL Application)畫在我們的 3D 物件上,因此可以運用 3D 技術對應用程式做各類特效或翻轉,在本例中,仿 iPad 的『程式啟動/關閉』和『按兩下 Home 鍵』的效果就是這樣完成的。

此外在影片中可以看到,我們也實作了桌面程式選單和原生的 Google Map 應用程式。

後記

目前除了正在補上整個環境所需的元件外和完善架構外,完美結合和運行原生的 Android 應用程式也是長期的目標。期望以過去的成果(見舊文:Android is Working on X)為基礎,讓 Android JVM 可以被移植並整合進來,使 Flat Project 可以執行各式 Linux/Meego 應用程式外,也可以跑 Android App。

發瘋的 Qt QWS TTY Keyboard Driver

最近接了一個小案子,主要是協助客戶將 Qt 應用程式從舊板子移植到新的硬體上,由於硬體是 Third-party 做,當然所有的驅動程式也是由別人處理,我們並不經手,只和硬體廠商密切合作。

這次我們碰到了一些 Keyboard 問題,一開始是 Linux driver 缺少 input_sync() 的操作,導致 Qt 無法正確辯別按鍵的『壓放』。接著碰到個更棘手的問題,就是 Qt 送到應用程式的 Key 事件(Event)有很大機率會送錯。這將導致按鍵所觸發的結果,有很大的機會我們無法預期。檢查過 evdev event 和其發出來的 keycode,我們確定了 Linux Driver 是正確的,判斷應該是 Qt 的問題。

經過一番檢查後,發現是因為 Qt-Embedded 預設使用 TTY Driver(qkbdtty) 去驅動鍵盤,大部份情況下不太會有問題,但因為我們走的是標準的 Linux evdev (/dev/input/eventX),如果很快速或多重觸發鍵盤按鍵,就有可能讓 Qt 的 TTY Driver 取樣和解析出錯誤的 Event 值。最快的解決辦法就是捨棄 Qt TTY Driver,然後改用 Qt  LinuxInput Driver(qkbdlinuxinput)。

不過 qkbdlinuxinput 並不處理 VT,這是與 qkbdtty 最大的差異,此舉會造成板子上的 Console 不正常切換,Debug 用的 Console 會因此壞掉。筆者在此對 QWS Keyboard Driver 做了些修改,讓 tty driver 使用 linuxinput driver 的方式去解析 keyboard event,並保留 VT 的處理機制。

Patch 檔案連結如下:
http://fred-opensource.googlecode.com/git/patches/qkbdtty_qws.patch

開啟網路蟲洞穿越時空,活用 SSH Tunnel VPN

最近去了一趟上海考察,尋找創業發展的機會,但機會暫且不論,此行確實深深體會在中國的網路世界非常不一般。中國和諧的社會實在不容許影響善良風俗的事情存在,許多外來的邪惡,一一被偉大的長城擋在外面。不過,道高一尺魔高一丈,很多人很聰明,懂得翻牆方法,進出自如,多數人使用 Reverse SSH Tunnel(有興趣可參考筆者舊文『Reverse SSH Tunnel 反向打洞實錄』)建立一個臨時的 Proxy Server,讓網頁連線繞道而行。

不過,使用 Proxy Server 的方式只能讓特定的通訊協定能夠不受防火牆的阻擋,如果說要全面性的逃脫網路限制和監控,就要靠 VPN(Virtual Private Network)的方式。VPN 是什麼?簡而言之,就是與遠端的網路環境建立通道,使電腦彷彿真實身處於遠端的內部網路一般。所以 VPN 一旦建立成功,除了可以存取遠方的內部網路,當然亦可以將遠端網路當為中繼站再連到網際網路,換言之,就是可繞過防火牆的一切限制。至於 VPN 的建立方法有很多種, 但都不在本文範疇,這邊要說明的是如何用 SSH Tunnel 建立 VPN。

設定必要的環境變數後,直接執行以下的 Script,就可以和遠端 Server 建立 VPN 連線:
#!/bin/bash # Local Network NETWORK=192.168.16.0 GW=192.168.16.1 # Server IP Address SERVER=123.123.123.123 # Server 對外的 Interface SERVER_IF=eth0 echo "Creating Connection" ssh -w 0:0 -f $SERVER "ifconfig tun0 10.0.2.1 netmask 255.255.255.252 pointopoint 10.0.2.2 ; echo 1 > /proc/sys/net/ipv4/ip_forward ;/sbin/iptables -t nat -A POSTROUTING -o $SERVER_IF -j MASQUERADE ;route add -net $NETWORK gw 10.0.2.2 dev tun0" …

新鮮果汁吧!果汁桌面環境(Juice Desktop Environment)!

圖片
筆者喜愛喝果汁,故為這個新的 Project 取了 Juice 這樣的名稱,意旨一個自己喜愛的桌面環境。在前些日子,因為放棄了 GNOME 而轉向使用 Enlightenment(以下簡稱E17),雖然各方面還算不錯,但在新版 Package 的更新上實在是缺少人在維護。因此,若是使用 Debian 官方版本的 E17 Package,功能非常少,而 E17 官方的 Repository 版本又太舊。其實,原本希望能幫忙打包,但因為種種因素而做罷。

既然本身需求不高,就發揮今年貫徹執行的土砲精神,在空閒時間動手開發一個合用的桌面環境。目前,已經釋出其中一個 Dock/Panel 元件『JuShelf(Juice Shelf)』的初步版本,也已經有實作模組(Module)機制,和一種 module。下面是畫面截圖(Screenshot)和最新的展示影片:



畫面中展示的是 Launch module,能提供圖示讓使用者點擊並啟動應用程式。其中的特效設計是放大圖示然後傾斜,帶有相當的趣味性。

目前仍然待完成的模組:

工作視窗清單(taskbar)系統狀態顯示區(systray)時間顯示(Clock)
後記
目前 Juice 本身還沒有 Project 網站,只是以個人動機為出發點,若是日後有較完整的開發成果,會再補上。此外,Juice 初期打算使用 Compiz 或 Mutter 做為視窗管理器(Window Manager),以及配合一基本的 GNOME 小元件(如同筆者前些日子在整合 E17 和 GNOME 一般)。

針對『電子紙』優化 Qt 繪圖事件

最近手上有一些電子紙的案件,指定使用 Qt 做為圖型平台。與一般裝置不一樣的地方,電子紙的更新頻率很低,平均下來每秒頂多刷新一次,相對於 LCD Panel 的每秒 60 次起跳,實在低的可憐。對於專職繪圖的 Qt 而言,要如何壓低刷新的頻率和確認畫面繪圖完成,最後再推入 Display,便是一個重要的課題。

壓低更新頻率比較單純,透過修改 Framebuffer Driver 就可以達成。此外,也必須利用 setUpdatesEnabled() 和 update() 盡量避免 Qt 連續多次的繪圖需求,合併一次送入 framebuffer,這樣可以減少 Qt 來不及畫完和畫面閃爍的問題。

到此為止只是改善顯示效果和基礎的建置,真正要完成完美的一次推送,通常需要使用電子紙驅動程式所提供的額外 API,它同意我們自己決定何時將 Framebuffer 的資料推送到紙上。

至於何時該將畫面推送至電子紙上?這時需要針對 QApplication 做一些修改,監聽和自己創造一個新的事件:

const QEvent::Type UpdateScreenEvent = (QEvent::Type)1234; bool Application::notify(QObject *obj, QEvent *e) {      if (e->type() == UpdateScreenEvent) {           if (updateScreen) {               EPaperDriverCtrl *ctrl = (EPaperDriverCtrl*)EPaperDriverCtrl;               ctrl->pushFBtoPanel();               updateScreen = false;           }             return true;       } else if (e->type() == QEvent::Paint) {           updateScreen = true;           QApplication::postEvent(this, new QEvent(UpdateScreenEvent));       } …

Flat Project - 從山寨做起,親手打造炫麗的平板系統

已經過了近兩年,至今仍然沒有一台 PC 廠商做的平板電腦能勝過 iPad,精緻度估且不論,其速度與流暢度,相較之下只能堪稱工程機的程度。其實真正原因不在於這些廠商行銷廣告中的 CPU 『數量』,而是 Android 系統軟體本身處處存在了一些效能上的問題,重點是這些問題不是工程師所在意的,而且吃力又不一定討好,沒人會拿飯碗去賭。另一方面,Android UI 設計永遠就像工程師自我良好的作品,單獨看每一個元件都很漂亮,可是拼裝起來後感覺就是盤剩菜剩飯,就算換了 UI,也不過只是換了封面罷了,換湯不換藥。

Open Source Project 的開發,最困難的就是修改機制,在很多時候,我們只有能力挖肉,沒能力整骨,畢竟整個 Project 不是我們自己寫的。當然,也因此很多設計是無法加上去的,就算加上去也無法好用。就像現在廠商所提倡的軟硬體垂直整合,雖然我們已經有了硬體與軟體的溝通,但在應用軟體到軟體系統之間,其實更需要有好的垂直整合,否則出現斷層後,就像現在 Android 平板總是說不出的有問題。也難怪有人在罵大多數場商只是把 Open Source Software 隨便放到硬體上就拿出來賣,根本不用心。

我們何不來自己動手寫一個平板系統?

運用現成的 Open Source Project 為基礎,以 iPad 為學習目標,重新打造一個平板用的作業系統。重要的是,品質要能出貨,又有好的擴充性和可用的底層機制,而不只是用套軟體拉一拉 UI 就完事。

Mandice Flat Project( http://code.google.com/p/flat

[Flat Project] 就是一個這樣的產物,目標是自己動手打造一個開放的平板環境。(目前已經釋出程式碼的子項目是 GrandPa(視窗管理器),是一個仿 iPad 視窗行為的 3D Window Manager。)

Flat 的起源,[Mandice] 是這幾年間與不少大大小小廠商合作過案子,已有不少經驗和成果。所以在今年的 [COSCUP 2011] 活動,筆者一時興起,便把過去案子所開發的各種元件抽出來再開發並陸續釋出,這就是 [Flat Project] 的由來,當然已經移除不應該公開的商業部份。

後記

順帶一提,今年度 COSCUP 2011 的 Unconference Session 筆者有講如何…

MongoDB 快速筆記

這幾年 Web Service 的龐大需求,對資料庫的要求是快速且吞吐量大,因此業界開始流行 NoSQL,它省略最花時間的資料庫操作和複雜的結構,用最合人類使用需求的方式在儲存資料,其帶來的好處,當然就是能提供極速的反應和龐大的資料吞吐量。目前最廣為人知的就是 BigTable,Google 提供全世界快速搜尋和各種線上服務,靠的就是這 NoSQL Database。

其實 NoSQL Database 的選擇非常多,但本文只是記錄 MongoDB 的操作筆記,因此就不詳述。 有興趣的人,可以去查閱網路上更多的資料。
選擇 Database: use my_database
利用 root 新增 Database 的管理帳號: # 切換到 my_database use my_database # 先用 root 帳號認證 db.getSisterDB("admin").auth("root", "rootpassword"); # 新增 frankie 帳號 db.addUser("frankie", "fredpassword");
新增 Database 的管理帳號: # 切換到 my_database use my_database # 先用 frankie 帳號認證 db.auth("frankie", "fredpassword"); # 新增 zombie 帳號 db.addUser("zombie", "zombiepassword");
插入新增資料(Insert):
# 插入一筆新資料到 users Collection (相當於傳統 SQL 裡的 Table 角色) db.users.insert({ username: "fred", password: "12345678" }) # 含當前時間 db.users.insert({ username: "fred", password: "12345678", created: new Timestamp() })
查詢(Query): # 查詢所有 us…

不想用傻逼 GNOME3 !好牛逼的雜牌軍替代方案 E17+GNOME/XFCE/Fluxbox Component!

圖片
好不容易,Linux 桌面經過十多年的演進,GTK+ 和 GNOME 總算進入了 3.0 的時代,向來最愛仗著『使用者之名』做盡任何事的 Ubuntu,也推出了他們的 Unity 介面,試圖重新打造桌面使用者的習慣。可惜的是,這些新的桌面設計雖然帶來了完全不一樣體驗,卻也造成不少使用者操作思維的混亂;更可怕的,這些標新立異的改變,將原本『好不容易』成熟穩定下來的桌面系統,在短時間內,又再次推向重新建立習慣和軟體崩潰的循環地獄。

網路上一篇討論文章『Linux的桌面為什麼這麼傻逼』(這篇文章是有心人翻譯的,內有原文連結),對 Linux 桌面環境有很獨道的見解和體驗,其批判性的強烈言詞,可以感覺到這些年作者的沉痛經歷。

就某方面來說,筆者相當讚同該文的論調,本身就長期使用 Linux 桌面,不時因為各種桌面系統的問題,親自動手去做程式開發或調整,可以說該文道盡筆者心聲。不過最近這一兩年, GNOME 已經可以算是很好用的桌面環境,程式也很穩定,周遭初入 Linux 的朋友們也都可以輕易上手。但高興沒辦法太早, GNOME 3.0 在此時投下了一顆超級炸彈,其更新除了讓許多元件壞東壞西,使用操作和程式開發上完全讓人覺得陌生。

喔不!我不要再經歷一次『桌面環境的黑暗時代』。我只想穩穩定定且不要有意外的使用著我的作業系統,所以我也拒絕 GNOME3 和 Unity。在一切混亂的情況下,Enlightenment(簡稱 E17) 帶來了一線曙光。

我對桌面環境的要求其實不高:
可用性高,穩定度和使用性最好不要與 GNOME 2.0 有太大的差異。速度快漂亮又炫麗(最好能夠有 3D 桌面的支援,這讓我覺得我的系統比 Windows 高級)省系統資源畫面易客製化(如果能讓我看起來更像個專業宅男 Hacker更好)
經過一些拼裝和調整後,這是用 Enlightenment + GNOME Component + Thunar File Manager(XFCE) 組裝的桌面環境其最後樣貌:

Debian 使用者,可以照下面步驟拼裝出同樣的桌面環境(當然畫面上的元件排版要依各自喜好自行調整): 去 http://packages.enlightenment.org/ 尋找和系統相對應的 Repository(筆者將以 Debian Sid 為例)在 /etc/apt/sources.lis…

『假新鮮人』獻給『真新鮮人』的話

畢業潮近了,學校又將放出一大群新鮮的人才,而每年這個時候,我總會有許多感觸。過去,是看著年紀相仿的朋友投履歷找工作,近距離觀察新鮮人準備進入職場;現在,則是看著後輩跌跌撞撞,撞出許多可歌可泣的新鮮事。

一切都很新鮮,我們年少時對未來都有憧憬,畢業後準備進入職場,更是抱有許多夢想。有人想努力內求更上一層樓,有人想賺錢獨立,各有各的目標和想法,人生方向就因此不同。這些美麗的夢,就像小學生寫作文題目『我的座右銘』,開學時人人都可以把自我期許講得頭頭是道,但每當學期末拿模範生或各種獎項的人數來看,便知道起而行的人寥寥可數。

以年紀來說,我應該算是社會大學的新生,但因為在學時就已經開啟了接案生涯,對社會種種並不陌生,所以嚴格說起,我是『假新鮮人』。這些社會經歷,雖微不足道,卻也讓我開了一些眼界。因此這篇文章,其實是獻給過去十幾歲的自己,也是算一種反省式的認罪,更是對生涯的交代。

我承認,當年。
許多案子總讓我提不起興趣,做起來總拖泥帶水。能夠最後一天做完,我絕不會提前兩天開始做。一旦工作做不完,最好不要讓我抓到別人的把柄,因為我將有藉口全身而退。累一天,就好像累一個星期。別人會如何我不在乎,我在乎的是自己的信用和利益。因為你們講的問題或臭蟲我都看不到,所以我給的成果完全沒問題。心裡總是想:『上頭賺很多在口袋裡,應該分我吧。』管你再急,只要我現在情緒不好,我就不鳥你。我做到這樣就夠了,反正我東西交了差已經丟了出去,剩下是你們家的事。不管我做對做錯或做得好不好,只要有做就沒有對不起任何人。網路神通廣大,讓我得到一堆人云亦云的知識,所以總是任意亂入別人的話題講些人云亦云的假知識。 我不管其他人說什麼,我認為該這樣做就這樣做,哪怕造成別人的困擾。只要老闆沒發現,就算我在混,時間也算是賣給老闆。如果有事情會需要讓我在私人時間做,那就一定是老闆的問題。總覺得自己做的事最關鍵也最重要,所以自己做一件事抵別人做十件。我只要做完了事,不管過程或結果有沒有造成別人不便或損失,都不是我的責任,所以賠錢也不干我的事。但是,給我的錢是萬萬不能少。同時,我總有藉口和說詞。
無論工作有多少,只要不想做就說:『是你們沒評估好我的能力,工作太多或太難,所以我達不成。』『因為我東西有在最後一刻給了出來,所以 Project 有任何延誤也不干我的事。』『我已經很努力做了,請不要再亂給我壓力。我需要有休息時間。』『我…

不要小看華人呀,Android App 的逆向工程!

還記得在某次的 COSCUP 與 Google 的龐教授,交流了一些 Android 方面的意見。由於他專精於 Compiler,我們也對 Dalvik Virtual Machine 的部份有些許的討論。當時感到非常榮幸,也覺得驕傲,因為這樣發光於全球的 Project ,也有華人在其中,更難得的是就在眼前。

最近空閒時間在研究一些 Android 的實作,煩腦之際,於 Google Code 發現了一個對岸朋友針對 apk 的逆向工程研究,有對 Dalvik VM 做了一系列的研究和說明,並開發了一支 apk 反組譯工具 [dex2jar]。如其名,該工具能將 DEX(Android apk 的格式)還原成 Java class 檔案,但更有趣的是,反向工程後的結果,不單只是 Binary 或 Bytecode,而是有『相當完整』的 Java 原始程式碼。

此外,在該 Project 的 Wiki 上,作者用『中文』記載了 [dex2jar] 的設計細節和反向工程所遭遇的問題,並寫了相應的解決手段,對技術有興趣的人可以去看看。 :-P
後記
如同該 Project 首頁所標註,還是請玩家在把玩這支程式時要『遵循 Google 相關協議與相關法律法規』。

Python之我見

圖片
對一個『慣C』人來說,[Python] 實在是讓人無法去接受的程式語言,無論是效能、速度還是所吃的系統資源,都讓人不滿意。但以一個類 Script 語言來看待它,又是個極度強大又好用的東西,開發時程也比其他傳統語言短相當多,開發完成之後,也有相當大的再擴展和加速的空間。所以,若是開發出來的東西,沒有絕對強烈的『即時』和『精巧』需求,用純 Python 來寫,會相當合理。


應用需求導向

若您是熟悉 Windows 的開發者,可將 Python 視為 [Visual Basic],是一個著重於『立即應用』的存在(當然在本質上不相同,後者相對簡陋且更著重於【可視化程式設計】)。他們最相似之處就是開發模式,因為長久下來,已經有太多人為 Python 寫出無數的模組、功能,以致開發者只需要懂得引入和使用這些模組,就能達成所有能想到的功能,這點與 Visual Basic 的『控制項』開發模式沒什麼不同。

在今天,由於太多人的貢獻成果,使 Python 開發者幾乎無所不能,再者,其已經跨足了許多平台。對開發者而言,同一支程式,只要注意引入模組是否能跨平台(大多數功能多半都有解決方案),就能輕易寫出能運行於不同平台上的應用軟體,稱之跨平台的 Visual Basic 可不為過。
但如同許多前端網頁開發者隨處濫用 JavaScript + HTML,濫用 Python 的人也有不少。由於 Python 過於易用,許多人在開發上只求達成功能,忘了效率的考量(這觸動了『慣C』人最大的忌諱),過去一些比較著名的例子就是: emesene(Linux 上常見的 MSN 軟體) 和 iBus(輸入法系統架構),速度慢或吃光系統資源還不打緊,甚至是造成系統鎖死當機的狀況。

獨特的語言特性
說到 Python 語言本身,它有極為結構化的設計,又支援各種先進的開發模式,物件導向等技術當然不會少,以致使用 Python 來開發大型專案是非常可行的。若要舉個實例,大概就是 Google 的各項網路服務。
Python 擁有獨特的語言規則,像是捨棄『{};』等包裝語法,並強迫對齊等設計。這使得開發者不得不簡化和編排自己的程式,不能再寫出長又難以維護的程式碼。當然,這會讓已經習慣傳統語言規則的開發者,會有困擾和不習慣,需要一些時間適應。不過,一旦接受了 Python 的設計習慣,便可輕易的使用。

適用範圍
很明顯,Py…

ibus-chewing 單純注音模式 - OSDC.tw 2011 Lightening Talk

為了注音輸入法,您是否長久以來也仍在使用 SCIM?每次裝好 Linux 的第一件事就是刪除系統預設輸入法,我們彷彿是外星人一般,一點都沒享有人權。感謝 OSDC.tw 2011(活動期間 3/26 ~ 3/27) 提供好吃的食物和舒適的場地,在活動這兩天筆者花了一點功夫做 patch,修掉了 ibus-chewing 單純注音模式的一些 Bugs,現在基本上 ibus-chewing 單純注音模式已經可用,我們可以丟掉 SCIM + 爛注音 Table 了!

以下是 Lightening Talk 的簡報檔:


後記
由於簡報格式的關係,暫時無法轉成 PDF 輸入,所以目前使用錄影的方式公開,待轉檔程式開發完成再來釋出 PDF 檔。

Linux Kernel Sendfile() 的提升 Server 效能之路

Apache 和 Samba 這類伺服器,主要以傳送檔案資料的工作為主,他們最常做的工作不外乎是開啟檔案(Open)、讀取(Read)、寫入網路連線(Write to Socket)。但是以 Kernel 的角度來說,這樣一個讀取檔案資料和傳送出去的流程相當繁複,並擁有最少兩次的 Kernel/User Space 資料搬移, 導致同一筆資料需要經過兩次多餘的複製。舉例來說,若一個檔案有 1MB,則 Linux Kernel 需要多做 2MB 的記憶體複製,使得效能經常消耗在這種地方,尤以 CPU 不夠快的平台上狀況特別明顯。

而過去曾有 khttpd 這樣的實作,讓 Linux Kernel 自成一個小型的 Web Server,提供一個極有效率方式的讀取靜態網站頁面和 Server 服務,其加速的方法,便是於 Kernel Space 讀取檔案並直接從網路連線送出資料,目的也在於減少 Kernel/User space 之間不必要的 context switch。

想瞭解 User Space 和 Kernel 的資料搬移狀況,我們可以來研究應用程式在讀取和傳送網路資料的流程,經簡化後大致上是(以下簡稱 User Space 為 US,Kernel Space 為 KS):
[US] open()[KS] do_sys_open()[KS] do_filp_open() - 找到檔案,並從所在的檔案系統取得 struct file[KS] Return File Object[US] malloc() - 準備一塊記憶體當 buffer[US] read(file, buffer)[KS] vfs_read(file) - 標準 VFS 的檔案讀取 API[KS] file->f_op->read() - 使用資料所在的檔案系統(filesystem),其提供的低階 read 操作[KS] copy_to_user(buffer) - 將檔案資料從硬碟讀出來後,複製一份到 user space 的 buffer
接著是將讀到的資料透過網路傳送出去:
[US] write(Socket, buffer) - 將 buffer 內資料傳送出去
[KS] copy_from_user(buffer) - 將 user space 的 buffer 複製回 k…

在 Linux Kernel 中取得目錄中的檔案清單

寫一支程式在 User Space 下列出目錄中的檔案清單相當容易,我們可以用 readdir() 去一項項取得檔案內容,事實上, readdir() 是由 Linux Kernel VFS(Virtual Filesystem) 所提供的 API,真正的實作在檔案系統的核心模組(Kernel Module)中。然而因為 Kernel readdir() 的相關實作牽涉到 Kernel/User space 的資料交換問題,所以如果我們是在撰寫 Kernel 的驅動程式,當然就不能使用這系列的 APIs。不過也因為所有的資訊都存在於 Kernel 的資料結構中,我們可以直接從記憶體中的 Linked list 中快速取得檔案清單。

在取得某個目錄下所有檔案資訊前,要先得到該目錄的敘述 struct dentry,VFS 用 struct dentry 的串聯組合來描述整個檔案系統的目錄結構,檔案清單則被保存在 dentry 中的 Double Linked List,因此其實只要知道如何使用 Kernel 提供的 Double Linked list,就能得到該目錄下所有的檔案資訊。而這邊要注意的是 Kernel 提供的一個通用 Linked list 結構(struct list_head),用來統一整個核心的 Linked list 操作機制,這檔案清單的 Double Linked List 就是使用這通用的結構。

這裡是 Linux Kernel 2.6.37 中 dentry 的資料結構(定義在 linux/dcache.h,其中較不重要的部份以『...』做省略,此外,某些定義與較早版本的 Kernel 有所差異,將在文章最後補上說明):struct dentry { ...省略 struct hlist_node d_hash; /* lookup hash list */ struct dentry *d_parent; /* parent directory */ struct qstr d_name; struct list_head d_lru; /* LRU list */ /* * d_child and d_rcu can share memory */ …

我想做什麼?What Do I Really Want to Do?

近來,承蒙一些事業天使(Business Angel)關愛,極為客氣且專程邀我交流意見,長輩們不因我是個年輕小夥子,可能存在著年紀上的宏溝,而難以互相溝通,反之相談甚歡。但研究未來趨勢,研究目前機會,進而相互觸發的火花,卻比不上過程中簡單又普通的一個問句,其當頭棒喝讓我這些日子來不斷自我問之。

你想做什麼?

就是這短短五個字,令我當下訝然失聲,換來多天無法平靜,連睡夢中也在試圖尋一條明確的出路,直到驚醒。

經這麼多年時日蹧蹋,倒也不是心中無腹案,無法當場說得天花亂墜,而是發自內心回應這五個字的,是一個大藍圖,一個難以說明完整的藍圖。確確實實,我相信著心中那一齣對未來的憧景,那一套事先設計過的必經過程。現在的我,沒辦法三言兩語說明清楚,也沒辦法完整交代想成就的大事。只是因為有些事『微不足道』,有些事又大的『虛無飄渺』,而我手上只有一張地圖,貫串頭尾。靡靡道來,不免枯燥無味。

或許不少人會嘲弄,請我多方學習演講技巧、說話技巧、表演技巧,學習將最精華的部份講到別人心崁裡。但別人感興趣的可能只是我計劃中的一小部份,那並不能代表我真心想做,試問如何能夠欺己欺人?再說,我也不是要騙人當『金主』,用不著這樣做了。


革命事業

若真的要下一個總結,描述我想要做的事,那我會說:『革命,革我自己的命。如果要走十一步才能到目標,那我一定不會省掉第一步,也不會直接跳第十步。』

這世界上有太多事不一定是走對的路,多半彎彎曲曲又碰碰撞撞邁向終點,隨著大家起舞,多半也能走到終點,只不過時間也會浪費很多,我只想少做錯事,直接往正確的路走去。但這些所謂未來必定的方向,太直接走去,過程中必定也是眾人所指,在大家眼中你不過就是不循大家規矩的革命份子。


驚天動地的未來

我就是要得到驚天動地的未來,但我不會放棄眼前的現實,你們或許聽過很多突然發光的點子,但也聽過更多被風熄滅的燭火。我寧可多下苦功找遮避,點火不會為風所動。


天使投資人

我並不妄想得到錢就能馬上發光,而是一直在煩腦怎麼把各種資源換成太陽,讓它永續不滅。換句話說,只要能協助我的人,就算出力不出錢,也是我的天使投資人。當然,我也不怕成為自己唯一的天使。


人生不後悔的一次嘗試

我有我想走的路,無論會不會成功,其他人看不看好或能否理解我,唯一試試看的機會就是現在。

撰寫跨平台程式需注意的 I/O 和 Offset 問題

對於檔案操作,坊間已經有太多 Hello World 程式示範過無數次,往往運用簡單的 lseek() 、read() 和 write() 已滿足大多數需求。但在 ARM 與 x86 架構之間,便有些微妙的差異,讓 Hello World 級的範例程式處處失效。的確,很少人真的動手寫一支程式去處理大型檔案,更少人會將這類程式移植跨平台使用。

若發現原本在 x86 上可正常使用 write()/pwrite() 等方式寫入資料,但交叉編譯(Cross-Compile)至 ARM 後,始終無法如預期讀寫資料,那意味著你可能掉進 offset 的陷阱了。

說起來這問題牽涉到 off_t 變數形態的記憶體使用長度,並可分為三個面向探討『Kernel』、『glibc』、『應用程式(Application)』。理論上 Runtime 時,三方對檔案操作的 offset 定義應該是要一樣,但事實上不然,只有在 x86 平台上比較統一。在 ARM 等這類平台,由於各家廠商在製作 BSP 各自定義,各程式和往往預設使用上不盡相同,更主要原因是因為多數應用程式都是從 x86 移殖過來,和 ARM 平台上 32-bit 的預設處理方式會格格不入。

在 x86 架構上(測試環境為 Debian Sid、 Intel Platform),通常 off_t 被定義為 unsigned long long (無號最長整數),總長度是為 8 Bytes(因長度等同 off64_t,下文將 64-bit 的 off_t 以 off64_t 稱之),在此環境下的 gcc+glibc 會自動使用 off64_t 形態做為 offset 處理參數,當然在編譯程式時也會自動使用相對應的處理函數,實作和定義可參考 unistd.h。

而在 ARM 的環境上,卻不一定如此,在某些平台和 BSP 中,off_t 預設就會被定為 32-bit 長度,會造成一些可能發生的問題。

一個例子,若是有寫過 FUSE(Filesystem in User Space) 程式,並移植到 ARM 的經驗,就有機會發現系統上 off_t 定義的大混亂。起因是 libfuse 使用 off64_t 與 kernel/Application 溝通,但若是系統編譯環境預設使用 off_t,我們寫的 filesystem 程式便會不正常…

Document Slider 文件滑動閱覽器

不知不覺又過了一年,在這幾天假期花了一番功夫,便從去年與廠商合作的 Project 中,拆出了當時設計的UI並重新撰寫成一個新的文件滑動閱覽程式。在移除了和廠商相關的各個部份後,整體介面功能相當單純易用。該操作介面以滑動(Slider)和時間軸(Timeline)為主要操作概念,方便使用者瀏覽需要照時間排列的各類文件和圖檔資料,並以無限延伸的設計回朔歷史訊息,有點類似圖書館內的報紙查閱機器。