2015 SegmentFault 杭州黑客马拉松赛后回顾

编者按:西瓜同学是有赞的数据团队的工程师。在10月24日这个特殊的日子,他参加黑客马拉松,和小伙伴们愉快地 hack 了一把,来看看他的回顾吧。

上个周末,也就是10月24、25号,参加了人生中第一次黑客马拉松(hackathon),虽然最终没有获奖,但是这个比赛过程中还是 hack 的挺爽,趁现在还有余热,纪录下比赛时的一些心得与收获。

为什么参加 hackathon

当在公司得知有黑客马拉松之后,我就立即报名了,觉得这件事本身就很酷,虽然身边一些同事说此类比赛没意思,大部分人都是奔着投资去的,但我还是觉得要你怎么看了,你如果去是为了那奖品、钱,我觉得那失去了 hackathon 的意义了,hackathon 我理解的就是

做一些很酷的事情,而这些事情在平时的工作中“用不到”,但是完成这些事能够让我们有很强的满足感。

也就是玩,虽然当知道自己的作品没有获奖时会有些许失落,但那是一时的,最起码那一天一夜 coding,让我确实很 high。

赛前准备

由于时间短,我就想着这次比赛用 nodejs 来做,参加比赛前的一周,我停止了 SICP 的阅读,转而进攻《Node.js实战》,这本书之前断断续续翻过前两章,这次基本把这本书看完了,主要是学习了下如何系统的开发一个完整的 node 应用,包括常用模块、通用架构等,之前写的 node 都是玩具,没有错误处理,没有单元测试(这次比赛虽然也没用上,但是知道了如何使用相应工具去测了)。

书上最后一章介绍了 node 中较为底层的知识,像net库,node 的定位就是提供小而美的核心类库,常用的模块都是基于这些核心类库构建。下面纪录两个书中比较有趣的例子:

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

下面的代码片段实现了类似于 Linux 上 nc 命令的功能:

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个题目,然后就开始组队做了,我和劲风一组,做的是一个超市扫码购物的微信应用,想要解决的基本问题是——超市排长队付款。对于我来说,主要是想做一些有难度的技术,挑战自己,也没想为什么现在超市为什么不推行扫码购物,当然这也是后来评委问我们的问题。 这个题目主要的技术难点有:

微信公众号开发

如何扫码是我们遇到的第一个问题,是借助微信还是自己做原生应用,由于我俩都不会 Android 与 IOS 开发,所以微信成了唯一选择。 微信开发需要有公众号,如果调用 JS-SDK,需要有备过案的域名,我们都没有,这时我想到了大宝兄,他很慷慨的给我提供云主机、mysql、nginx,加上宝贵的域名,很是感谢。(后面知道了可以用测试号)。

当时遇到的主要问题是签名算法,由于开发文档中没有使用命名锚(named anchors),所以打开上面的链接后,需要用Ctrl + F 来搜索 “签名算法” 才能找到我这里所指的签名算法,最最坑人的是,由于签名是针对网页 URL 的,所以一个网页需要签名一个,而这个 URL 必须是以/结尾,比如,如果用http://1024.sundabao.com这个 URL 来签名是不对的,必须是http://1024.sundabao.com/,这个真的好坑。

订单系统

扫码问题解决了,剩下的就是一个集成购物车的订单系统,之前在公司虽然也是在数据部,但是报表做的不多,真是没想到这订单系统是多么麻烦,我当时遇到问题就是,购物车选好后,点击提交,这时,按理说应该生成订单的,但是生成订单的同时是否需要把购物车的商品删除呢,第一感觉是需要,但是后来发现不是这样的,如果顾客发现还有商品没有购买,这时他会返回上一页继续购买,所以正确的做法是在确认支付订单后,再去把购物车的商品删掉。但是这样也会有问题,因为顾客确认支付方式后,有可能支付失败了,这时按理说购物车里的东西还是应该有的,但是我们这里比较简单,只要用户点击支付,就认为成功了。可见,要做一个完整的订单+交易系统,是多么不容易的事。

callback hell

由于订单系统的逻辑比较多,涉及很多数据库的操作,而我们使用 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 的说诸如此类的话,我劝你最好离这种人远些,道不同不相为谋,世界这么大,为什么不去做自己喜欢的事呢?

精彩瞬间

美丽的互联网小镇

午餐时刻

比赛开始了

休息,休息一会♨️ 大家都睡了,但我们还在继续...

凌晨3点的互联网小镇

圆满结束,感谢 sf 组办方

有赞小伙伴

注:图片均来自 sf 官方,如涉及个人隐私请告知。

总结

这次参加比赛,玩的很开心,没什么遗憾。至于代码就不开源了,写的比较烂,后面等功力提升了在说这事。感兴趣可以看看我们作品易购 EasyGo的简介。

这里我想回答当时评委问我们组的问题——为什么现在的超市不推广扫码支付

  1. 二维码识别后,一般会包含商品的生产日期这个信息,而对于超市某些产品,像海鲜,是不想让顾客知道这个的...
  2. 同一商品不同超市卖的价格可能不一样,这样卖的贵的超市是不愿意用这套系统的...

对于这些,我只能说:经济基础决定上层建筑。

比赛是结束了,但生活的挑战还在继续,希望大家都能够 happy hacking !

本文首发于我的 个人博客,观点仅代表个人,与公司无关。

欢迎关注我们的公众号