發表文章

商業操弄,軟體研發人員不喜歡做的事!

在國外,許多大型軟體公司林立,老牌軟體商建立了不少現今軟體業仍在使用的遊戲規則。而比較小的軟體外包商、工作室或是個人,也糊裡糊塗依照這些大公司使用的遊戲規則走,甚至是遵守不合時宜的淺規則。然後,軟體業進入了國內,又被代工思維牽著走,軟體業因此哀嚎聲不斷。軟體研發人才不喜歡去操弄商業,卻被商業操弄著。 身為軟體外包或是軟體客製化的外包商,你是否曾遇過,客戶有很多大大小小的鎖碎要求,不定期會交代過來? 這些修修改改,看似不癢的功能和需求,做起來毫不費功夫,三兩下順手就能完成,卻往往造成雙方驗收標地的分岐,此外,不知不覺中所累積的份量,也讓結案時間遙遙無期,甚至造成軟體產生更多的問題待解決。對於只想當水電工的研發人員,總是在客戶的要求下,修完馬桶順道通水管,又補個土、也打個臘。另外,如果馬桶旁邊剛好有漏水,那你要自認倒楣了,因為客戶也會請你幫忙『順手』解決一下,或認定是你在修馬桶時弄壞的。是吧,令人難過。 難道研發人員就要這麼可憐嗎?我們做錯了什麼,為何就要這樣被對待?明明是為了提供更好服務,卻累死三軍,又讓人有把柄指著鼻子唸。更慘的是,一旦這些看似不起眼的修修改改,累積成有影響力,讓專案與合約內的需求不完全相符。客戶就有機會利用『與合約不符』的矛盾點,再殺下一城。 筆者也同是天涯淪落人,曾經不斷思考這問題也同時咒罵著台灣的業界,咒罵他們總不給軟體商有活命的空間。尤其受了委屈後,更是一股惱自命不凡,認為自己無論做什麼樣的事,都應該比一般人收取更多費用,以平心頭之恨。但過些時日後,經過冷靜思考,發現是一開始雙方的互動模式就錯了,或許更仔細檢視這個行業,才能找到改變現況的辦法。 大多數軟體開發不是演藝事業 一直不認為『軟體程式設計師』是演藝事業,所謂『台上一分鐘,台下十年功』不能完全形容軟體開發的工作。雖然,越厲害的研發人員,越能設計好品質的軟體;越是名不經傳的軟體商,也越難生存於業界。許多面向與藝人生態有些相似,但其實完全不是這個樣子。 因為我們雖練功多年,在專案過程中,卻仍然做很多沒技術性又取代性高的工作,或是『順手工作』這類連項目都寫不出來的事。所以,與演藝事業最大的不同是,我們不是只做一件事:『像巨星一樣站上台吸引全場目光,解決觀眾們長達數十分鐘的無聊時間』,而是因應專案需求,巨星仍然要下海當工讀生或工作人員,甚至是清潔工。所以,大多數軟體研發...

NodeJS + Express + i18next 支援多國語系吧!

除非是區域性的網站服務,不然在這個網路通全世界的時代,開發網站服務就一定有多國語系的需求。一般來說,i18n 的支援都是由 Web Framework 所提供,但 Express 並沒有支援,所以我們要借助 i18next 這個模組。i18next 可以和 Express 以及 template 很完美的結合,最重要的是,有客戶端支援(clientside support),若搭配 jquery,我們也可以使前端的 JavaScript 支援多國語系。 先使用 NPM 安裝 i18next: npm install i18next 在 express 的應用程式(app.js)中引入使用 i18next: var express = require('express'); var i18n = require('i18next'); var app = module.exports = express.createServer(); /* Initializing i18n */ i18n.init(); i18n.registerAppHelper(app); app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(i18n.handle); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(__dirname + '/public')); }); app.get('/', function(req, res) { res.render('index'); }); app.listen(3000); 接著要在應用程式的目錄下,建立預設的翻譯檔和存放路徑(locales/dev/translation.json): { "exam...

【企業顧問咨詢】為您的產品選擇作業系統解決方案

你將為自家的產品,選用什麼樣的作業系統?我想,這年頭,不外乎是 Android。但是,可能不是最佳選擇。 我想大多數人都會同意,由於智慧型行動裝置的掘起,Google Android 在業界大放異彩,使用 Linux 作業系統核心的 Android,實現了許多華麗的UI,也讓眾多廠商取得入門門票,有機會與 Apple iOS 一爭長短。許多人都相信,未來是 Android 的天下,除了手機要用 Android,電視要 Android,救人一命的醫療器材也要用 Android,所謂的 Android anywhere 是終極目標。 不過,經過這幾年下來,許多人發現這不過是我們資訊科技業一廂情願,有太多的領域是難以使用 Android,如工控市場等,無論是以穩定、價格、移植維護成本考量的因素,都可能是無法使用 Android 的重點。因此,如今要選擇作業系統解決方案,又變成一個需要思考的難題。 筆者擔任顧問時,每當面對客戶躊著於這個問題時,我總問他們幾個大問題: 你們的產品用途是否單一且單純?是否要有讓使用者自行上網安裝其他第三方軟體的擴充性? 你們的產品是否為消費行電子產品?是否需要高可用行和高穩定性? 你們的軟體需要有華麗特效的 UI 嗎?你們現在擁有的人員有哪些開發 UI 程式的經驗? 有網路的需求嗎?如果有,需要哪些需求?Ethernet、Wifi、3G? 計劃中的產品硬體規格? 有多少規模的人可以參與開發? 很明顯的,對於手機和行動裝置業者是這樣的答案:(他們都會選用 Android) 用途不單一,需要讓使用者任意自行上網安裝軟體。 是功能複雜的消費性電子產品,所以客戶多多少少能接受偶爾當機 UI 需要有華麗的特效。開發人員都熟悉並使用 Java 的經驗。 有所有網路的需求。 擁有一定等級以上或是當前最頂級的 ARM 處理器。 最少數十個,多半是上百人甚至上千人的研發人員。 如果你是『非手機』和『非行動裝置』業者,你的產品可能不完全具備這些條件。建議您,一旦有任何一點不具備,請慎重考慮是否使用 Android 還是有機會選擇其他的解決方案。 而當前的解決方案主要常見有三種: Android Linux + Qt Framework Linux + Own Application 限於篇幅,太細節的評估無法一...

NodeJS 與 MongoDB 的邂逅

雖然 NodeJS 的模組和開發資源相當多,但相關文件卻非常不足或是不完整,多半文獻都只著重於基礎的使用和片斷的說明,如果不去看原始程式碼,使用 NodeJS 來完成實用的網站,會有很大的困難度。對於已經有過 Web 開發經驗的人,轉換使用 NodeJS 不免也需要花一番功夫,過去經驗中許多的常用的功能,都仍要一一花大量時間嘗試才得以解決。而這樣的情況,對於開發者來說相當的糟,也是很多人重新再評估是否使用 NodeJS 的重點因素之一。有道是『一人得道,雞犬升天』,因此筆者未來將嘗試將自己的實際經驗,寫成一篇篇重點功能實作的文章和隨 Copy 即用的範例,減少其他人浪費同樣的時間再摸索。 開發一個 Web 應用程式,最重要的莫過於資料庫的使用,過去 PHP 有 MySQL 當最佳夥伴,而現在 NodeJS 有 MongoDB 做最佳的組合。MongoDB 是 NoSQL 的代表之一,其採用 JSON/BSON 當做資料儲存和溝通的格式,亦使用 JavaScript 做為 Server-side 的執行程序語言(相當於傳統 RDBMS 的預儲程序),一切設計和習慣與 NodeJS 搭配使用起來,簡直絕配。若你對 MongoDB 的一些基本操作有疑問,可以先參考舊文『 MongoDB 快速筆記 』。 使用 MongoDB MongoDB 擁有 NoSQL 的普遍特色,不用預先定義 Schema,所有的 database 和 collection(相當於傳統 RDBMS 的 Table),都會在新增資料後,自動被建立,我們只要專注於使用 NodeJS 操作資料庫即可。 要在 NodeJS 裡使用 MongoDB,可以安裝 mongodb native driver,若透過 npm 來安裝: npm install mongodb 然後可以使用 NodeJS 建立 MongoDB connection pool ,做一些基礎的操作: var mongodb = require('mongodb'); var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 }); var db = n...

苦其心志,勞其筋骨後,世界末日年快樂!

2012 新年快樂!今年格外不同,也是人稱世界末日將來臨的一年,而在這人生將結束的一年,不免開始思考今年的自我期許。 :-) 回顧去年的風雨,當了一年的『救火隊長』。曾經為了救援朋友的案子,連續三個月,每天平均睡不到一小時,且平均連續工作達72小時以上,如果過程中突然一命嗚乎,一點也不意外。還好,這樣可怕的惡夢,都一一挺了過去,雖然身體似乎出現了點問題,不時陣痛襲來。不過,老天讓我完好的活下來,是祂已經頒發『超級救火員勛章』的最佳證明。 我總相信,只要有信念和方向,任何困境都是老天賜予的挑戰,每當苦盡甘來,就會有許多更好的機運等著。事實上,當了一年職業救火員不是沒有好處,看到了許多人不為人知面貌,許多業界的問題和盲點,更認清了自己該做的事,也得到了更棒更成熟的點子。甚至,某個程度上,已經不害怕死亡突然降臨。 為什麼過的這樣辛苦?為什麼總是孤單的拼命?是否該檢討一下自己? 還清楚記得,這一年有些人這樣問過我,我都沒有正面回答,直到現在才有時間靜下來思考這個問題,也自我檢討了一番。 如果因為負責任而辛苦減壽,為了理想而拼了命和全世界作對,那我真的想不出有任何一點不正確的地方。我只能推論,許多人不願意辛苦,甚至可以『不負責任』去避免辛苦;許多人沒有懷抱理想,所以沒有拼命的目標,只有隨波逐流的生活。 真的要自我檢討,除了憤世忌俗外,就是我死腦筋的總是依據一件事的『順利和成就』,考量應該做什麼,甚至不是自己的義務,也會執行到底,貫徹著父親所囑付:『幫忙之前叫幫忙,幫忙之後叫責任。』然而,許多人理所當然以為處處都是我的義務和責任,一股惱全加諸於我身上。使我,做會自己勞累不堪,不做則內心不舒服,痛苦萬分。 而這樣的個性,讓我和傳統做生意一點都不搭軋,因為我永遠不愛也不喜歡打『把對手權利變成對手義務』的拉拒戰。在這樣的商場戰爭下,人人都不想執行自己的義務,只想行使自己的權利,甚至讓對方的權利變成自己的權利。不過,雖然不喜歡,但不代表我不懂,每次回歸原點和原貌來看,就會發現『人有多不要臉』和『許多醜陋的臉孔』的戲碼都正在天天上演,過程中的種種掩飾都讓人不敢相信,任誰看了都會臉紅找洞鑽。 如果這樣才能不辛苦不孤獨,我寧可苦一輩子。我也永遠不相信,那樣的結黨,能夠有什麼未來。此外,如此彆扭的生意,也不是我所期望的目標。 過去無數個日子,腦袋從未停止轉動過...

【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) 要記憶體空間...

如何在 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 的 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 */ ...

Openmoko 永遠活在我們的心中

圖片
還記得 2006 年 12 月業界出現了一個瘋狂的想法:『Openmoko 的開放手機』,但就在 2011 年 12 月滿五年,這家公司(Openmoko, Inc) 也將劃下了一個圓滿的句點。 回顧過去,Openmoko 不只是單純的軟體層面開放,而是連硬體設計的細節都公開。這對當時的大環境,高端手機技術和 Know-how 都被嚴密掌握在特定公司的時局下,無疑是個瘋狂的舉動。想當然,Openmoko 花了大量錢財與人力物力,還有國內外社群的力量,終於做出了自己的第一代手機原型(參考圖 Neo 1973),爾後又開發出第二代硬體加強版的機種(參考圖 Neo FreeRunner)。 Neo 1973 還記得,當時大多數人都還是使用功能手機(Feature phone),智慧型手機(Smart Phone)也還停留在被難用 Windows CE 稱霸的時代,誰也還沒有想到未來會有 iPhone 和 Android Phone,對絕大多數人而言,手機是個神祕且只有少數人可以參與開發的領域。有趣的是,Openmoko 除了做開放的手機之外,也對應用程式(Apps)安裝於手機上的想法有了初步的構想,而這些想法,都觸動了不少軟體開發者和投資人的目光。 雖然直到最後,Openmoko 的手機還不足以讓一般消費者順暢使用,但許多構想,無論是開放手機,有擴充性的應用程式平台,還是使用 Linux 開發前衛的智慧型手機,都確實已深埋在不少人心中。世界各地的 Hacker 和高手,無一不想擁有這樣一台的開放手機。 Openmoko 也在教育界扎根,除了提供開發的教育訊練外,也去拜訪了許多大專院校,讓許多原本沒有機會碰到手機開發的學生和技術人員,有機會一睹這神秘的領域。然後,也有不少學校買了 Openmoko 的手機,做為開發教學使用,直至今天,這些手機還是相當好的開發教材,甚至,也已經有不少教授在這上面開發了一系列教材。(如:淡江大學資工系已經將 Openmoko 手機當成 C 語言教學和相關基礎技術的實作平台) Neo FreeRunner 隨著 iPhone 的問市,Google Android 的出現,Openmoko 逐漸失去了媒體焦點,也有不少不為人知的事情,讓公司逐漸縮編並轉型(之後轉做過 WikiReader),以致現在的人,多半都只...

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 myA...

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>'...