本文章首發於我的博客,鑑於 sf 博客樣式具備賞心悅目的美感,遂發表於此。html
上個週末,也就是10月2四、25號,參加了人生中第一次黑客馬拉松(hackathon),雖然最終沒有獲獎,可是這個比勝過程中仍是 hack 的挺爽,趁如今還有餘熱,紀錄下比賽時的一些心得與收穫。node
當在公司得知有黑客馬拉松以後,我就當即報名了,以爲這件事自己就很酷,雖然身邊一些同事說此類比賽沒意思,大部分人都是奔着投資去的,但我仍是以爲要你怎麼看了,你若是去是爲了那獎品、錢,我以爲那失去了 hackathon 的意義了,hackathon 我理解的就是mysql
作一些很酷的事情,而這些事情在平時的工做中「用不到」,可是完成這些事可以讓咱們有很強的知足感。nginx
也就是玩,雖然當知道本身的做品沒有獲獎時會有些許失落,但那是一時的,最起碼那一天一晚上 coding,讓我確實很 high。git
因爲時間短,我就想着此次比賽用 nodejs 來作,參加比賽前的一週,我中止了 SICP 的閱讀,轉而進攻《Node.js實戰》,這本書以前斷斷續續翻過前二者,此次基本把這本書看完了,主要是學習了下若是系統的開發一個完整的 node 應用,包括經常使用模塊、通用架構等,以前寫的 node 都是玩具,沒有錯誤處理,沒有單元測試(此次比賽雖然也沒用上,可是知道了如何使用相應工具去測了)。程序員
而後書上最後一章介紹了 node 中較爲底層的知識,像net
庫,node 的定位就是提供小而美的核心類庫,經常使用的模塊都是基於這些核心類庫構建。下面紀錄兩個書中比較有趣的例子:github
var net = require("net"); var socket = net.connect({host: "github.com", port: 22}); socket.on("data", function(chunk) { console.log(chunk.toString()); socket.end(); }) // 啓動後,會輸出 SSH-2.0-libssh-0.7.0
下面的代碼片斷實現了相似於 nc 命令:web
var net = require("net"); var socket = net.connect({host: process.argv[2], port: process.argv[3]}); socket.on("connect", function() { process.stdin.pipe(socket); socket.pipe(process.stdout); process.stdin.resume(); }); socket.on("close", function() { console.log("bye..."); });
其次在看 expressjs 時,無心間發現其做者 tj 早在 2014年4月份,就已經拋棄 nodejs,投向 go 的懷抱,心中不免有些憂傷,大牛老是這樣,在咱們還在學習某東西時,人家已經發現其缺點,轉向更高深的地方......算法
此次的比賽是命題制——技術改變生活,這基本上是沒有限制,通過有贊小夥伴的一番討論,最終定了3個題目,而後就開始組隊作了,我和勁風一組,作的是一個超市掃碼購物的微信應用,想要解決的基本問題是——超市排長隊付款。對於我來講,主要是想作一些有難度的技術,挑戰本身,也沒想爲何如今超市爲何不推行掃碼購物,固然這也是後來評委問咱們的問題。
這個題目主要的技術難點有:sql
如何掃碼是咱們遇到的第一個問題,是藉助微信仍是本身作原生應用,因爲我倆都不會 Android 與 IOS 開發,因此微信成了惟一選擇。
微信開發須要有公衆號,若是調用 JS-SDK,須要有備過案的域名,咱們都沒有,這時我想到了大寶兄,他很慷慨的給我提供雲主機、mysql、nginx,加上寶貴的域名,非常感謝。(後面知道了能夠用測試號)。
這裏必須吐槽下微信的開發文檔,真是爛:排版爛、個別語句不通順、常常有死連接,真不知道微信團隊裏都是些什麼人。
好比這裏的簽名算法,微信的人不知道命名錨(named anchors),因此你須要在打開上面的連接後,須要用Ctrl + F
來搜索 「簽名算法」 才能找到我這裏所說的簽名算法,最最坑人的是,因爲簽名是針對網頁 URL 的,因此一個網頁須要簽名一個,而這個 URL 必須是以/
結尾,好比,若是咱們用http://1024.sundabao.com
這個 URL 來簽名是不對的,必須是http://1024.sundabao.com/
,這個真的好坑。
相比之下,Github的開發者文檔,看起來就很讓人舒服,但願微信的好好學學。
掃碼問題解決了,剩下的就是一個集成購物車的訂單系統,以前在公司雖然也是在數據部,可是報表作的很少,真是沒想到這訂單系統是多麼麻煩,我當時遇到問題就是,購物車選好後,點擊提交,這時,按理說應該生成訂單的,可是生成訂單的同時是否須要把購物車的商品刪除呢,第一感受是須要,可是後來發現不是這樣的,若是顧客發現還有商品沒有購買,這時他會返回上一頁繼續購買,因此正確的作法是在確認支付訂單後,再去把購物車的商品刪掉。可是這樣也會有問題,由於顧客確認支付方式後,有可能支付失敗了,這時按理說購物車裏的東西仍是應該有的,可是咱們這裏比較簡單,只要用戶點擊支付,咱們就認爲這成功了。可見,要作一個完整的交易+訂單系統,是多麼不容易的事。
因爲訂單系統的邏輯比較多,涉及不少數據庫的操做,而咱們使用 nodejs 也沒用什麼 ORM 系統,只是用原生的 sql 來作,這時就陷入了 callback hell,以前寫 node 程序通常都不怎麼關注錯誤處理, 因此一直沒怎麼發現這個問題,此次在作這個訂單系統,真是暴露無疑,太難維護了。
下面代碼片斷的功能是:掃描一個商品,向購物車列表中增長一個商品的 callback hell
exports.add = function(userId, goodsId, goodsNum, cb) { var that = this; var dbPool = db.getPool(); var sql = "insert into 1024_cart values (?,?,?) ON DUPLICATE KEY UPDATE goods_num=goods_num+1"; sql = db.formatSQL(sql, [userId, goodsId, goodsNum]); dbPool.query(sql, function(err, result) { if(err) { logger.error("exec:" + sql + " error:" + err); cb({code:-2, msg: "服務器內部錯誤!"}); } else if(result.affectedRows > 0) { goodsDAO.select(goodsId, function(err, result) { if(err) { logger.error("exec:goodsDAO.select. error:" + err); cb({code:-2, msg: "服務器內部錯誤!"}); } else if(result.length == 0) { that.delete(userId, goodsId); cb({code:-1, msg: "數據庫中沒有該商品!"}); } else { var goods = result[0]; getGoodsNum(userId, goodsId, function(err, result) { if(err) { cb({code:-2, msg: "服務器內部錯誤!"}); } else { goods["num"] = result[0]["goods_num"]; cb({code:0, data: goods}); } }) } }); } else { cb({code:-3, msg: "修改失敗!"}); } }); }
在整個比勝過程中(大概20個小時),我睡了不到4個小時,大腦一直處於興奮狀態,一直在解決問題,從動態獲取微信簽名,到解決訂單系統的 bug,到最後的測試,都是極度興奮的,coding 的比較 high。
我以爲我會編碼到老。
記得在學生時代就不斷聽到有人說,程序員是青春飯,作幾年後要轉向管理崗,真不知道說這些話的人是出於什麼心理,固然有部分人是把編碼當成爲一份養家餬口的工做,可是我相信更多人是由於熱愛編碼而編碼的,從編碼中能汲取無限快樂。
若是你身邊在有人 balabala 的說諸如此類的話,我勸你最好離這種人遠些,道不一樣不相爲謀,世界這麼大,爲何不去作本身喜歡的事呢?
注:圖片均來自 sf 官方,如涉及我的隱私請告知。
此次參加比賽,玩的很開心,沒什麼遺憾。至於代碼就不開源了,寫的比較爛,後面等功力提高了在說這事。感興趣能夠看看咱們做品易購 EasyGo的簡介。
這裏我想回答當時評委問咱們組的問題——爲何如今的超市不推廣掃碼支付:
二維碼識別後,通常會包含商品的生產日期這個信息,而對於超市某些產品,像海鮮,是不想讓顧客知道這個的...
同一商品不一樣超市買的價格可能不同,這樣買的貴的超市是不肯意用這套系統的...
對於這些,我只能說,經濟基礎決定上層建築,商家仍是以盈利爲目的的。
比賽是結束了,但生活的挑戰還在繼續,SICP 要繼續搞起了,此次停了有兩個多星期了,真要多下功夫了。
但願你們都可以 happy hacking !