@@ -790,17 +801,17 @@ git push -u origin master
本地测试都通过了,于是我们添加了Travis-CI来跑我们的测试
CI
虽然node.js不算是一门语言,但是因为我们用的node,下面的是一个简单的.travis.yml示例:
-
-代码来源: https://github.com/phodal/lettuce
+
+代码来源: https://github.com/phodal/lettuce
我们把这些集成到README.md之后,就有了之前那张图。
CI对于一个开发者在不同城市开发同一项目上来说是很重要的,这意味着当你添加的部分功能有测试覆盖的时候,项目代码会更加强壮。
代码质量
@@ -812,29 +823,29 @@ git push -u origin master
Code Climate是一个与github集成的工具,我们不仅仅可以看到测试覆盖率,还有代码质量。
先看看上面的ajax类:
-Lettuce .get = function (url, callback) {
- Lettuce .send (url, 'GET' , callback);
-};
-
-Lettuce .send = function (url, method, callback, data) {
- data = data || null ;
- var request = new XMLHttpRequest ();
- if (callback instanceof Function) {
- request .onreadystatechange = function () {
- if (request .readyState === 4 && (request .status === 200 || request .status === 0 )) {
- callback (request .responseText );
- }
- };
- }
- request .open (method, url, true );
- if (data instanceof Object) {
- data = JSON .stringify (data);
- request .setRequestHeader ('Content-Type' , 'application/json' );
- }
- request .setRequestHeader ('X-Requested-With' , 'XMLHttpRequest' );
- request .send (data);
-};
-代码来源: https://github.com/phodal/lettuce
+Lettuce .get = function (url, callback) {
+ Lettuce .send (url, 'GET' , callback);
+};
+
+Lettuce .send = function (url, method, callback, data) {
+ data = data || null ;
+ var request = new XMLHttpRequest ();
+ if (callback instanceof Function) {
+ request .onreadystatechange = function () {
+ if (request .readyState === 4 && (request .status === 200 || request .status === 0 )) {
+ callback (request .responseText );
+ }
+ };
+ }
+ request .open (method, url, true );
+ if (data instanceof Object) {
+ data = JSON .stringify (data);
+ request .setRequestHeader ('Content-Type' , 'application/json' );
+ }
+ request .setRequestHeader ('X-Requested-With' , 'XMLHttpRequest' );
+ request .send (data);
+};
+代码来源: https://github.com/phodal/lettuce
在Code Climate 在出现了一堆问题
Missing “use strict” statement. (Line 2)
@@ -880,24 +891,24 @@ git push -u origin master
Knockout
好在Knockout可以用Require.js进行管理,于是,使用了Require.js进行管理:
-
+
main.js配置如下:
-
+
text、json插件主要是用于处理web.json,即用json来处理技能,于是不同的类到了不同的js文件。
.
|____Book.js
@@ -909,52 +920,52 @@ git push -u origin master
|____TalentTree.js
|____Utils.js
加上了后来的推荐阅读书籍等等。而Book和Link都是继承自Doc。
-
+
而这里便是后面对其进行重构的内容。Doc类则是Skillock中类的一个缩影
-
+
或者说这是一个AMD的Class应该有的样子。考虑到this的隐性绑定,作者用了self=this来避免这个问题。最后Return了这个对象,我们在调用的就需要new一个。大部分在代码中返回的都是对象,除了在Utils类里面返回的是函数:
-
+
当然函数也是一个对象。
自动化测试
一直习惯用Travis CI,于是也继续用Travis Ci,.travis.yml配置如下所示:
-
+
使用gh-pages的原因是,我们一push代码的时候,就可以自动测试、部署等等,好处一堆堆的。
接着我们需要在package.json里面添加脚本
-
+
这样当我们push代码的时候便会自动跑所有的测试。因为mocha的主要配置是用mocha.opts,所以我们还需要配置一下mocha.opts
--reporter spec
--ui bdd
@@ -982,55 +993,55 @@ line 21 col 62 Strings must use singlequote.
✓ should return link label & url
测试示例
简单地看一下Book的测试:
-
+
因为我们用require.js来管理浏览器端,在后台写测试来测试的时候,我们也需要用他来管理我们的依赖,这也就是为什么这个测试这么长的原因,多数情况下一个测试类似于这样子的。(用Jasmine似乎会是一个更好的主意,但是用习惯Jasmine了)
-
+
最后的断言,也算是测试的核心,保证测试是有用的。
代码质量与重构
@@ -1160,85 +1171,85 @@ line 21 col 62 Strings must use singlequote.
于是我们就打开lib/database/sqlite_helper.js,因为其中有两个坏味道
Similar code found in two :expression_statement nodes (mass = 86)
在代码的 lib/database/sqlite_helper.js:58…61 < >
-
+
lib/database/sqlite_helper.js:64…67 < >
与
-
+
只是这是之前修改过的重复。。
原来的代码是这样的
-
+
说的也是大量的重复,重构完的代码
-
+
重构完后的代码比原来还长,这似乎是个问题~~
Git 提交信息及几种不同的规范
@@ -1339,7 +1350,7 @@ line 21 col 62 Strings must use singlequote.
协议
官方首页与在线文档
-很多开源项目都会有自己的网站,并在上面有一个文档,而有的则会放在https://readthedocs.org/ 。
+很多开源项目都会有自己的网站,并在上面有一个文档,而有的则会放在https://readthedocs.org/ 。
Read the Docs 托管文档,让文档可以被全文搜索和更易查找。您可以导入您使用任何常用的版本控制系统管理的文档,包括 Mercurial、Git、Subversion 和 Bazaar。 我们支持 webhooks,因此可以在您提交代码时自动构建文档。并且同样也支持版本功能,因此您可以构建来自您代码仓库中某个标签或分支的文档。查看完整的功能列表 。
@@ -1379,100 +1390,100 @@ React.render(
代码及setup请见github: js-refactor
代码说明
uMarkdown是一个用于将Markdown转化为HTML的库。代码看上去就像一个很典型的过程代码:
-
+
选这个做重构的开始,不仅仅是因为之前在写EchoesWorks 的时候进行了很多的重构。而且它更适合于重构到设计模式的理论。让我们在重构完之后,给作者进行pull request吧。
Markdown的解析过程,有点类似于Pipe and Filters模式(架构模式)。
Filter即我们在代码中看到的正规表达式集:
-
+
他会匹配对应的Markdown类型,随后进行替换和处理。而``str```,就是管理口的输入和输出。
接着,我们就可以对其进行简单的重构。
(ps: 推荐用WebStrom来做重构,自带重构功能)
作为一个示例,我们先提出codeHandler方法,即将上面的
-
+
提取方法成
-
+
while语句就成了
-
+
然后,运行所有的测试。
grunt test
同理我们就可以mail、headline等方法进行重构。接着就会变成类似于下面的代码,
-
+
然后你也看到了,上面有一堆重复的代码,接着让我们用JavaScript的奇技淫巧,即apply方法,把上面的重复代码变成。
-['code' , 'headline' , 'lists' , 'tables' , 'links' , 'mail' , 'url' , 'smlinks' , 'hr' ].forEach (function (type) {
- while ((stra = regexobject[type].exec (str)) !== null ) {
- str = that[(type + 'Handler' )].apply (that, [stra, str, strict]);
- }
-} );
+['code' , 'headline' , 'lists' , 'tables' , 'links' , 'mail' , 'url' , 'smlinks' , 'hr' ].forEach (function (type) {
+ while ((stra = regexobject[type].exec (str)) !== null ) {
+ str = that[(type + 'Handler' )].apply (that, [stra, str, strict]);
+ }
+} );
进行测试,blabla,都是过的。
-
-快来试试吧, https://github.com/artisanstack/js-refactor
+
+快来试试吧, https://github.com/artisanstack/js-refactor
是时候讨论这个Refactor利器了,最初看到这个重构的过程是从ThoughtWorks郑大晔校开始的,只是之前对于Java的另外一个编辑器Eclipse的坏感。。这些在目前已经不是很重要了,试试这个公司里面应用广泛的编辑器。
Intellij Idea重构
开发的流程大致就是这样子的,测试先行算是推荐的。
编写测试->功能代码->修改测试->重构
上次在和buddy聊天的时候,才知道测试在功能简单的时候是后行的,在功能复杂不知道怎么下手的时候是先行的。
开始之前请原谅我对于Java语言的一些无知,然后,看一下我写的Main函数:
-
+
代码写得还好(自我感觉),先不管Cal和Cal2两个类。大部分都能看懂,除了c,d不知道他们表达的是什么意思,于是。
Rename
快捷键:Shift+F6
@@ -1482,18 +1493,18 @@ React.render(
把光标移到int d中的d,按下shift+f6,输入result_sub
于是就有
-
+
快捷键:alt+command+m
作用:扩展方法
@@ -1503,17 +1514,17 @@ React.render(
在弹出的窗口中输入mprint
于是有了
-
+
似乎我们不应该这样对待System.out.println,那么让我们内联回去
Inline Method
快捷键:alt+command+n
@@ -1524,41 +1535,41 @@ React.render(
选中Inline all invocations and remove the method(2 occurrences) 点确定
然后我们等于什么也没有做了~~:
-
+
似乎这个例子不是很好,但是够用来说明了。
Pull Members Up
开始之前让我们先看看Cal2类:
-
+
以及Cal2的父类Cal
-
+
最后的结果,就是将Cal2类中的sub方法,提到父类:
-
+
而我们所要做的就是鼠标右键
重构之以查询取代临时变量
快捷键
@@ -1569,39 +1580,39 @@ React.render(
重构之前
过多的临时变量会让我们写出更长的函数,函数不应该太多,以便使功能单一。这也是重构的另外的目的所在,只有函数专注于其功能,才会更容易读懂。
以书中的代码为例
-
+
重构
选中basePrice很愉快地拿鼠标点上面的重构
Replace Temp With Query
便会返回
-
+
而实际上我们也可以
选中
@@ -1611,15 +1622,15 @@ React.render(
Intellij IDEA重构
在Intellij IDEA的文档中对此是这样的例子
-
+
接着我们选中aString,再打开重构菜单,或者
Command+Alt+Shift+T 再选中Replace Temp with Query
便会有下面的结果:
@@ -1645,28 +1656,28 @@ public class replaceTemp {
之前正在重写一个物联网 的服务端,主要便是结合CoAP、MQTT、HTTP等协议构成一个物联网的云服务。现在,主要的任务是集中于协议与授权。由于,不同协议间的授权是不一样的,最开始的时候我先写了一个http put授权的功能,而在起先的时候是如何测试的呢?
curl --user root:root -X PUT -d '{ "dream": 1 }' -H "Content-Type: application/json" http://localhost:8899/topics/test
我只要顺利在request中看有无req.headers.authorization,我便可以继续往下,接着给个判断。毕竟,我们对HTTP协议还是蛮清楚的。
-
+
可是除了HTTP协议,还有MQTT和CoAP。对于MQTT协议来说,那还算好,毕竟自带授权,如:
-
+
便可以让我们简单地完成这个功能,然而有的协议是没有这样的功能如CoAP协议中是用Option来进行授权的。现在的工具如libcoap只能有如下的简单功能
-
+
于是,先写了个测试脚本来验证功能。
-
+
写完测试脚本后发现不对了,这个不应该是测试的代码吗? 于是将其放到了spec中,接着发现了上面的全部功能的实现过程为什么不用TDD实现呢?
说说TDD
测试驱动开发是一个很“古老”的程序开发方法,然而由于国内的开发流程的问题——即开发人员负责功能的测试,导致这么好的一项技术没有在国内推广。
@@ -2046,7 +2057,7 @@ Set up your git name and email, this is important so that your commits can be id
生成图表
如何分析用户的数据是一个有趣的问题,特别是当我们有大量的数据的时候。除了matlab,我们还可以用numpy+matplotlib
数据可以在这边寻找到
-https://github.com/gmszone/ml
+https://github.com/gmszone/ml
最后效果图
2014 01 01
@@ -2055,37 +2066,37 @@ Set up your git name and email, this is important so that your commits can be id
==, 这个文件代表什么?
2014年1月1日零时到一时,用户在github上的操作,这里的用户指的是很多。。一共有4814条数据,从commit、create到issues都有。
数据解析
-
+
然后再解析json
-
+
这里用到了dateutil,因为新鲜出炉的数据是string需要转换为dateutil,再到数据放到数组里头。最后有就有了parse_data
-
+
下面这句代码就是将上面的解析为
-
+
这样的数组以便于解析
-[(0 , 92 ), (1 , 67 ), (2 , 86 ), (3 , 73 ), (4 , 76 ), (5 , 67 ), (6 , 61 ), (7 , 71 ), (8 , 62 ), (9 , 71 ), (10 , 70 ), (11 , 79 ), (12 , 62 ), (13 , 67 ), (14 , 76 ), (15 , 67 ), (16 , 74 ), (17 , 48 ), (18 , 78 ), (19 , 73 ), (20 , 89 ), (21 , 62 ), (22 , 74 ), (23 , 61 ), (24 , 71 ), (25 , 49 ), (26 , 59 ), (27 , 59 ), (28 , 58 ), (29 , 74 ), (30 , 69 ), (31 , 59 ), (32 , 89 ), (33 , 67 ), (34 , 66 ), (35 , 77 ), (36 , 64 ), (37 , 71 ), (38 , 75 ), (39 , 66 ), (40 , 62 ), (41 , 77 ), (42 , 82 ), (43 , 95 ), (44 , 77 ), (45 , 65 ), (46 , 59 ), (47 , 60 ), (48 , 54 ), (49 , 66 ), (50 , 74 ), (51 , 61 ), (52 , 71 ), (53 , 90 ), (54 , 64 ), (55 , 67 ), (56 , 67 ), (57 , 55 ), (58 , 68 ), (59 , 91 )]
+[(0 , 92 ), (1 , 67 ), (2 , 86 ), (3 , 73 ), (4 , 76 ), (5 , 67 ), (6 , 61 ), (7 , 71 ), (8 , 62 ), (9 , 71 ), (10 , 70 ), (11 , 79 ), (12 , 62 ), (13 , 67 ), (14 , 76 ), (15 , 67 ), (16 , 74 ), (17 , 48 ), (18 , 78 ), (19 , 73 ), (20 , 89 ), (21 , 62 ), (22 , 74 ), (23 , 61 ), (24 , 71 ), (25 , 49 ), (26 , 59 ), (27 , 59 ), (28 , 58 ), (29 , 74 ), (30 , 69 ), (31 , 59 ), (32 , 89 ), (33 , 67 ), (34 , 66 ), (35 , 77 ), (36 , 64 ), (37 , 71 ), (38 , 75 ), (39 , 66 ), (40 , 62 ), (41 , 77 ), (42 , 82 ), (43 , 95 ), (44 , 77 ), (45 , 65 ), (46 , 59 ), (47 , 60 ), (48 , 54 ), (49 , 66 ), (50 , 74 ), (51 , 61 ), (52 , 71 ), (53 , 90 ), (54 , 64 ), (55 , 67 ), (56 , 67 ), (57 , 55 ), (58 , 68 ), (59 , 91 )]
Matplotlib
开始之前需要安装``matplotlib
-
+
然后引入这个库
import matplotlib.pyplot as plt
如上面的那个结果,只需要
@@ -2096,47 +2107,47 @@ Set up your git name and email, this is important so that your commits can be id
plt.show()
最后代码可见
-
+
每周分析
继上篇之后,我们就可以分析用户的每周提交情况,以得出用户的真正的工具效率,每个程序员的工作时间可能是不一样的,如
@@ -2179,157 +2190,157 @@ Set up your git name and email, this is important so that your commits can be id
7119, 7346, 13412, 14008, 12555
Python 数据分析
重写了一个新的方法用于计算提交数,直至后面才意识到其实我们可以算行数就够了,但是方法上有点hack
-
+
接着我们需要去遍历每个结果,后面的后面会发现这个效率真的是太低了,为什么木有多线程?
Python Matplotlib图表
让我们的matplotlib来做这些图表的工作
-
+
蓝色的是第一周,绿色的是第二周,红色的是第三周就有了上面的结果。
我们还需要优化方法,以及多线程的支持。
-让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章http://www.huyng.com/posts/python-performance-analysis/ 讲的就是分析这部分内容的。
+让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章http://www.huyng.com/posts/python-performance-analysis/ 讲的就是分析这部分内容的。
存储到数据库中
SQLite3
我们创建了一个名为userdata.db的数据库文件,然后创建了一个表,里面有owner,language,eventtype,name url
-
+
接着我们就可以查询数据,这里从结果讲起。
-
+
当我查询gmszone的时候,也就是我自己就会有如下的结果
-( u 'gmszone' , u'ForkEvent' , u'RESUME' , u'TeX' , u'https://github.com/gmszone/RESUME' )
-( u 'gmszone' , u'WatchEvent' , u'iot-dashboard' , u'JavaScript' , u'https://github.com/gmszone/iot-dashboard' )
-( u 'gmszone' , u'PushEvent' , u'wechat-wordpress' , u'Ruby' , u'https://github.com/gmszone/wechat-wordpress' )
-( u 'gmszone' , u'WatchEvent' , u'iot' , u'JavaScript' , u'https://github.com/gmszone/iot' )
-( u 'gmszone' , u'CreateEvent' , u'iot-doc' , u'None' , u'https://github.com/gmszone/iot-doc' )
-( u 'gmszone' , u'CreateEvent' , u'iot-doc' , u'None' , u'https://github.com/gmszone/iot-doc' )
-( u 'gmszone' , u'PushEvent' , u'iot-doc' , u'TeX' , u'https://github.com/gmszone/iot-doc' )
-( u 'gmszone' , u'PushEvent' , u'iot-doc' , u'TeX' , u'https://github.com/gmszone/iot-doc' )
-( u 'gmszone' , u'PushEvent' , u'iot-doc' , u'TeX' , u'https://github.com/gmszone/iot-doc' )
-109
+( u 'gmszone' , u'ForkEvent' , u'RESUME' , u'TeX' , u'https://github.com/gmszone/RESUME' )
+( u 'gmszone' , u'WatchEvent' , u'iot-dashboard' , u'JavaScript' , u'https://github.com/gmszone/iot-dashboard' )
+( u 'gmszone' , u'PushEvent' , u'wechat-wordpress' , u'Ruby' , u'https://github.com/gmszone/wechat-wordpress' )
+( u 'gmszone' , u'WatchEvent' , u'iot' , u'JavaScript' , u'https://github.com/gmszone/iot' )
+( u 'gmszone' , u'CreateEvent' , u'iot-doc' , u'None' , u'https://github.com/gmszone/iot-doc' )
+( u 'gmszone' , u'CreateEvent' , u'iot-doc' , u'None' , u'https://github.com/gmszone/iot-doc' )
+( u 'gmszone' , u'PushEvent' , u'iot-doc' , u'TeX' , u'https://github.com/gmszone/iot-doc' )
+( u 'gmszone' , u'PushEvent' , u'iot-doc' , u'TeX' , u'https://github.com/gmszone/iot-doc' )
+( u 'gmszone' , u'PushEvent' , u'iot-doc' , u'TeX' , u'https://github.com/gmszone/iot-doc' )
+109
一共有109个事件,有Watch,Create,Push,Fork还有其他的, 项目主要有iot,RESUME,iot-dashboard,wechat-wordpress, 接着就是语言了,Tex,Javascript,Ruby,接着就是项目的url了。
值得注意的是。
-
+
这个数据库文件有905M ,不过查询结果相当让人满意,至少相对于原来的结果来说。
Python自带了对SQLite3的支持,然而我们还需要安装SQLite3
-
+
或者是
-
+
或者是Ubuntu的
-
+
openSUSE自然就是
-
+
不过,用yast2也很不错,不是么。。
数据导入
需要注意的是这里是需要python2.7,起源于对gzip的上下文管理器的支持问题
-def handle_gzip_file(filename):
- userinfo = []
- with gzip.GzipFile(filename) as f:
- events = [line.decode("utf-8" , errors= "ignore" ) for line in f]
-
- for n, line in enumerate (events):
- try :
- event = json.loads(line)
- except :
-
- continue
-
- actor = event["actor" ]
- attrs = event.get("actor_attributes" , {})
- if actor is None or attrs.get("type" ) != "User" :
- continue
-
- key = actor.lower()
-
- repo = event.get("repository" , {})
- info = str (repo.get("owner" )), str (repo.get("language" )), str (event["type" ]), str (repo.get("name" )), str (
- repo.get("url" ))
- userinfo.append(info)
-
- return userinfo
-
-def build_db_with_gzip():
- init_db()
- conn = sqlite3.connect ('userdata.db' )
- c = conn.cursor()
-
- year = 2014
- month = 3
-
- for day in range (1 ,31 ):
- date_re = re.compile (r"([0-9] {4} )-([0-9] {2} )-([0-9] {2} )-([0-9]+)\.json.gz" )
-
- fn_template = os.path.join("march" ,
- " {year} - {month:02d} - {day:02d} - {n} .json.gz" )
- kwargs = {"year" : year, "month" : month, "day" : day, "n" : "*" }
- filenames = glob.glob(fn_template.format (** kwargs))
-
- for filename in filenames:
- c.executemany('INSERT INTO userinfo VALUES (?,?,?,?,?)' , handle_gzip_file(filename))
-
- conn.commit()
- c.close()
+def handle_gzip_file(filename):
+ userinfo = []
+ with gzip.GzipFile(filename) as f:
+ events = [line.decode("utf-8" , errors= "ignore" ) for line in f]
+
+ for n, line in enumerate (events):
+ try :
+ event = json.loads(line)
+ except :
+
+ continue
+
+ actor = event["actor" ]
+ attrs = event.get("actor_attributes" , {})
+ if actor is None or attrs.get("type" ) != "User" :
+ continue
+
+ key = actor.lower()
+
+ repo = event.get("repository" , {})
+ info = str (repo.get("owner" )), str (repo.get("language" )), str (event["type" ]), str (repo.get("name" )), str (
+ repo.get("url" ))
+ userinfo.append(info)
+
+ return userinfo
+
+def build_db_with_gzip():
+ init_db()
+ conn = sqlite3.connect ('userdata.db' )
+ c = conn.cursor()
+
+ year = 2014
+ month = 3
+
+ for day in range (1 ,31 ):
+ date_re = re.compile (r"([0-9] {4} )-([0-9] {2} )-([0-9] {2} )-([0-9]+)\.json.gz" )
+
+ fn_template = os.path.join("march" ,
+ " {year} - {month:02d} - {day:02d} - {n} .json.gz" )
+ kwargs = {"year" : year, "month" : month, "day" : day, "n" : "*" }
+ filenames = glob.glob(fn_template.format (** kwargs))
+
+ for filename in filenames:
+ c.executemany('INSERT INTO userinfo VALUES (?,?,?,?,?)' , handle_gzip_file(filename))
+
+ conn.commit()
+ c.close()
executemany可以插入多条数据,对于我们的数据来说,一小时的文件大概有五六千个会符合我们上面的安装,也就是有actor又有type才是我们需要记录的数据,我们只需要统计用户的那些事件,而非全部的事件。
我们需要去遍历文件,然后找到合适的部分,这里只是要找2014-03-01到2014-03-31的全部事件,而光这些数据的gz文件就有1.26G,同上面那些解压为json文件显得不合适,只能用遍历来处理。
这里参考了osrc项目中的写法,或者说直接复制过来。
首先是正规匹配
-
+
不过主要的还是在于glob.glob
glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,就类似于Windows下的文件搜索,支持通配符操作。
@@ -2340,22 +2351,22 @@ Set up your git name and email, this is important so that your commits can be id
更好的方案?
Redis
查询用户事件总数
-
+
系统返回了227.0,试试别人。
-
+
看看主要是在哪一天提交的
-
+
结果大致如下图所示:
SMTWTFS
@@ -2373,28 +2384,28 @@ Set up your git name and email, this is important so that your commits can be id
到这里我们算是知道了OSRC的数据库部分是如何工作的。
Redis 查询
主要代码如下所示
-def get_vector(user, pipe= None ):
-
- r = redis.StrictRedis(host= 'localhost' , port= 6379 , db= 0 )
- no_pipe = False
- if pipe is None :
- pipe = pipe = r.pipeline()
- no_pipe = True
-
- user = user.lower()
- pipe.zscore(get_format("user" ), user)
- pipe.hgetall(get_format("user: {0} :day" .format (user)))
- pipe.zrevrange(get_format("user: {0} :event" .format (user)), 0 , -1 ,
- withscores= True )
- pipe.zcard(get_format("user: {0} :contribution" .format (user)))
- pipe.zcard(get_format("user: {0} :connection" .format (user)))
- pipe.zcard(get_format("user: {0} :repo" .format (user)))
- pipe.zcard(get_format("user: {0} :lang" .format (user)))
- pipe.zrevrange(get_format("user: {0} :lang" .format (user)), 0 , -1 ,
- withscores= True )
-
- if no_pipe:
- return pipe.execute()
+def get_vector(user, pipe= None ):
+
+ r = redis.StrictRedis(host= 'localhost' , port= 6379 , db= 0 )
+ no_pipe = False
+ if pipe is None :
+ pipe = pipe = r.pipeline()
+ no_pipe = True
+
+ user = user.lower()
+ pipe.zscore(get_format("user" ), user)
+ pipe.hgetall(get_format("user: {0} :day" .format (user)))
+ pipe.zrevrange(get_format("user: {0} :event" .format (user)), 0 , -1 ,
+ withscores= True )
+ pipe.zcard(get_format("user: {0} :contribution" .format (user)))
+ pipe.zcard(get_format("user: {0} :connection" .format (user)))
+ pipe.zcard(get_format("user: {0} :repo" .format (user)))
+ pipe.zcard(get_format("user: {0} :lang" .format (user)))
+ pipe.zrevrange(get_format("user: {0} :lang" .format (user)), 0 , -1 ,
+ withscores= True )
+
+ if no_pipe:
+ return pipe.execute()
结果在上一篇中显示出来了,也就是
[227.0, {'1': '51', '0': '41', '3': '17', '2': '34', '5': '28', '4': '22', '6': '34'}, [('PushEvent', 154.0), ('CreateEvent', 41.0), ('WatchEvent', 18.0), ('GollumEvent', 8.0), ('MemberEvent', 3.0), ('ForkEvent', 2.0), ('ReleaseEvent', 1.0)], 0, 0, 0, 11, [('CSS', 74.0), ('JavaScript', 60.0), ('Ruby', 12.0), ('TeX', 6.0), ('Python', 6.0), ('Java', 5.0), ('C++', 5.0), ('Assembly', 5.0), ('C', 3.0), ('Emacs Lisp', 2.0), ('Arduino', 2.0)]]
有意思的是在这里生成了和自己相近的人
@@ -2426,47 +2437,47 @@ Set up your git name and email, this is important so that your commits can be id
最多的语言
osrc中用于解析的代码
-
+
这样也就返回我们需要的点数,然后我们可以用get_points来获取这些
-
+
就会得到我们的相应的数据,接着找找和自己邻近的,看看结果。
[ 0.01298701 0.19736842 0. 0.30263158 0.21052632 0.19736842
0. 0.09210526 0. 0.22368421 0.01315789 0. 0.
@@ -2528,104 +2539,104 @@ Set up your git name and email, this is important so that your commits can be id
寻找
在GitHub上搜索了一个看到了下面的几个结果:
-但是显然,他们都太重了。事实上,对于一个库来说,80%的人只需要其中20%的代码。于是,找到了https://github.com/stackp/promisejs ,看了看用法,这就是我们需要的功能:
-
+但是显然,他们都太重了。事实上,对于一个库来说,80%的人只需要其中20%的代码。于是,找到了https://github.com/stackp/promisejs ,看了看用法,这就是我们需要的功能:
+
接着打开看看Promise对象,有我们需要的功能,但是又有一些功能超出我的需求。接着把自己不需要的需求去掉,这里函数最后就变成了
-
+
需要注意的是: License,不同的软件有不同的License,如MIT、GPL等等。最好能在遵循协议的情况下,使用别人的代码。
实现第二个需求
由于已经有了现有的很多库,所以就可以直接参照(抄)别人写的代码。
-Lettuce .get = function (url, callback) {
- Lettuce .send (url, 'GET' , callback);
-};
-
-Lettuce .load = function (url, callback) {
- Lettuce .send (url, 'GET' , callback);
-};
-
-Lettuce .post = function (url, data, callback) {
- Lettuce .send (url, 'POST' , callback, data);
-};
-
-Lettuce .send = function (url, method, callback, data) {
- data = data || null ;
- var request = new XMLHttpRequest ();
- if (callback instanceof Function) {
- request .onreadystatechange = function () {
- if (request .readyState === 4 && (request .status === 200 || request .status === 0 )) {
- callback (request .responseText );
- }
- };
- }
- request .open (method, url, true );
- if (data instanceof Object) {
- data = JSON .stringify (data);
- request .setRequestHeader ('Content-Type' , 'application/json' );
- }
- request .setRequestHeader ('X-Requested-With' , 'XMLHttpRequest' );
- request .send (data);
-};
+Lettuce .get = function (url, callback) {
+ Lettuce .send (url, 'GET' , callback);
+};
+
+Lettuce .load = function (url, callback) {
+ Lettuce .send (url, 'GET' , callback);
+};
+
+Lettuce .post = function (url, data, callback) {
+ Lettuce .send (url, 'POST' , callback, data);
+};
+
+Lettuce .send = function (url, method, callback, data) {
+ data = data || null ;
+ var request = new XMLHttpRequest ();
+ if (callback instanceof Function) {
+ request .onreadystatechange = function () {
+ if (request .readyState === 4 && (request .status === 200 || request .status === 0 )) {
+ callback (request .responseText );
+ }
+ };
+ }
+ request .open (method, url, true );
+ if (data instanceof Object) {
+ data = JSON .stringify (data);
+ request .setRequestHeader ('Content-Type' , 'application/json' );
+ }
+ request .setRequestHeader ('X-Requested-With' , 'XMLHttpRequest' );
+ request .send (data);
+};
如何以“正确的姿势”阅读开源软件代码
所有让你直接看最新源码的文章都是在扯淡,你应该从“某个版本”开始阅读代码。
@@ -2712,7 +2723,7 @@ Set up your git name and email, this is important so that your commits can be id
Longest Streak
在不停地造轮子的过程中,也不停地造车子。
-在那篇连续冲击365天的文章出现之前,我们公司的大大(https://github.com/dreamhead )也曾经在公司内部说过,天天commit什么的。当然这不是我的动力,在连击140天之前
+在那篇连续冲击365天的文章出现之前,我们公司的大大(https://github.com/dreamhead )也曾经在公司内部说过,天天commit什么的。当然这不是我的动力,在连击140天之前
给过google的ngx_speed、node-coap等项目创建过pull request
也有free-programming-books、free-programming-books-zh_CN这样的项目。
@@ -2812,7 +2823,7 @@ Set up your git name and email, this is important so that your commits can be id
google map solr
-代码: https://github.com/phodal/gmap-solr
+代码: https://github.com/phodal/gmap-solr
技能树
这个可以从两部分说起:
重构 Skill Tree
@@ -2826,7 +2837,7 @@ Set up your git name and email, this is important so that your commits can be id
Skill Tree
-代码: https://github.com/phodal/skillock
+代码: https://github.com/phodal/skillock
技能树Sherlock
D3.js
@@ -2840,7 +2851,7 @@ Set up your git name and email, this is important so that your commits can be id
Sherlock skill tree
-代码: https://github.com/phodal/sherlock
+代码: https://github.com/phodal/sherlock
Django Ionic ElasticSearch 地图搜索
Django Elastic Search
@@ -2851,7 +2862,7 @@ Set up your git name and email, this is important so that your commits can be id
Ionic
OpenLayers 3
-代码: https://github.com/phodal/django-elasticsearch
+代码: https://github.com/phodal/django-elasticsearch
简历生成器
Resume
@@ -2863,7 +2874,7 @@ Set up your git name and email, this is important so that your commits can be id
RequireJS
Showdown
-代码: https://github.com/phodal/resume
+代码: https://github.com/phodal/resume
Nginx 大数据学习
Nginx Pig
@@ -2873,7 +2884,7 @@ Set up your git name and email, this is important so that your commits can be id
Hadoop
Pig
-代码: https://github.com/phodal/learning-data/tree/master/nginx
+代码: https://github.com/phodal/learning-data/tree/master/nginx
其他
虽然技术栈上主要集中在Python、JavaScript,当然还有一些Ruby、Pig、Shell、Java的代码,只是我还是习惯用Python和JavaScript。一些用到觉得不错的框架:
@@ -3083,7 +3094,7 @@ Set up your git name and email, this is important so that your commits can be id
ionic-elasticsearch , Django ElasticSearch Ionic 打造 GIS 移动应用
designiot-app ,教你设计物联网APP版
-更多内容可以见我的Idea列表:https://github.com/phodal/ideas ,我实在是不想写了。
+更多内容可以见我的Idea列表:https://github.com/phodal/ideas ,我实在是不想写了。
2016年
2016.png
@@ -3133,7 +3144,51 @@ Set up your git name and email, this is important so that your commits can be id
图形框架 。这是我之前在做一个图形界面的时候,发现没有一个合适的框架可以满足我的要求。然后我就在想,还是自己做一个吧。
不过,最好的开源项目就是自己平时用的。于是,我开始将写各种工具来给自己使用——如现在在用的这篇微信编辑工具:mdpub 。
最后,我做了一个简单的 HTML 5 动画来记录这一时刻,作为这一个里程碑的记念:
-https://phodal.github.io/20k/
+https://phodal.github.io/20k/
+GitHub 寻宝指南
+作为一个资深的咨询师、程序员,GitHub 是我用过的最好工具,因为 Google 并非总是那么用。GitHub 是一个宝藏库,可没有藏宝图,GitHub 一1亿的仓库也和你没有关系。这么一些年下来,也算是掌握了一定的技巧,写篇文章记录一下,也就顺其自然了。
+总结一句话便是:GitHub 来搜索 Google 搜索不到的。它们可以 work 的原因,都是因为我们想做的事情,已经有人已经走过 。如果你走的是一条新的路,那么这篇文章对你来说,意义可能没有那么大。
+寻找 Demo 节省时间
+在工作上使用新的技术,和自己平时的练习,终究差得有些远。工作的时候,我们偏向于目标编程,对于速度和时间的要求,要比自己业余时间要高得多。一旦有了这种压力,便会在 GitHub 上寻找相应的 Demo,了解原理、稍微尝试,再引入到项目中。
+这时,便会按技术栈的关键字搜索,并按更新时间进行排序 ,以查找是否有合适的 Demo。
+生命有限 ,如若是每次我们尝试一个新的技术,总得自己编写一个个 Demo。编写多个 Demo,都得花去个半天八小时的时间。如此一算,能花费在其它事情上的时间便更少了。若只是试用官方的 Demo,往往是比较容易的。可我们编写应用的时候,总得结合到当前的场合来。这时整合并不是一个轻松的工作,依赖冲突、引入第三方依赖等。
+温馨提醒 :对于简单的项目来说,自己直接写 Demo 会更加方便。 尝试项目需要成本,若是需要尝试使用多个项目,那么有可能就浪费时间。
+寻找脚手架:加快前期开发
+无论是后端的微服务架构,还是前端应用,应用的架构正在变得复杂。后端微服务,需要结合一个个的框架,哪怕是 Spring Initializr 这样的工具,也只能帮助我们搭建项目。我们还需要配合其它工具,一起搭建出一个基本的系统。对于前端应用也是类似的,若是 Angular 这样大而全的框架,时间花费倒也是不多。如 React 这种需要组合的、小而美的框架,使用官方的 create-react-app 也很难做出我们想要的东西,寻找一个合适的脚手架是一个更好的选择。
+这时,我们大抵可以,直接使用技术栈 + boilerplate 又或者是 starter 等关键词进行搜索,如 react boilerplate。如果其中找到的组合技术栈,不符合自己的要求,那么再加上相应技术栈的关键字,如 react redux boilerplate 即可。有意思的是,在这时使用 Google 会比 GitHub 方便一些。
+温馨提醒 :我们需要衡量:修改脚手架的成本,是否比自己重头写快 。
+寻找 awesome-xxx:探索可能性
+练习新的框架,我总习惯于,编写一系列相关的 DEMO 项目,然后使用 awesome-xxx 探索可能性。
+Awesome-xxx 系列,是 GitHub 上最容易赚 star 的类型。但凡是有一定知识度的领域、语言、框架等,都有自己的 awesome-xxx 系列的项目,如 awesome-python, awesome-iot, awesome-react 等等。在这样的项目里,都以一定的知识体系整理出来的,从索引和查阅上相应的方便。如果你想进入一个新的领域,会尝试新的东西就搜索 awesome xxx 吧。
+温馨提醒 :awesome-xxx 只意味着它们包含尽可能多的资料,并不代表它们拥有所有相关的库。
+模仿轮子 的轮子
+大学时,我在练习写嵌入式操作系统,uC/OS-II 对于初学者的我来说,太复杂了——有太多无关的代码。便在网上找寻相关的实现,也便是找到了一些,在那的基础上一点点完善操作系统。
+学习一个成熟的框架,直接阅读现有源码的成本太高,毕竟也不经济。最好的方式,就是去造轮子。从模仿轮子之上,再去造轮子,是最省力气的方式。再配合 《造轮子与从Github生成轮子 》 一文,怕是能写一系列的框架。而造一个相似轮子的想法,往往很多人都有。尤其是一个成熟的框架,往往有很多仿制品。
+于是,当你想了解一个框架,造个轮子,不妨试试搜索 xxx-like 或者 xxx-like framework,中文便是 仿 react 框架 或者 类 react。如我们在 Google 上搜索 react-like 就会搜索到 inferno。不过,按 GitHub 的尿性,要搜索到这样的框架,并不是一件容易的事。这时 Google 往往比 GitHub 搜索好用。
+所以建议:平时上班休息时,搜索相关的轮子,回家就可以造轮子了。
+学习资源
+GitHub 上拥有大量的学习资源,从各类的文章到笔记,还有各式各样的电子书。如:
+
+只需要搜索:类型 + 笔记,如 操作系统 笔记 就能找到一些操作系统相关的笔记。
+只需要搜索:书名 就能找到一些和这本书相关的资源,如 重构 改善既有代码的设计。
+
+与此同时,GitHub 上还会搜索到各种 未经授权 英文书籍的翻译,又或者是各种电子书的 PDF 版。作为多本书的作译者,当然不鼓励 GitHub 上找到一些盗版书。
+而在 GitHub 上又有一些库,可以提供相应的学习资源,如 free-programming-books-zh_CN ,即免费的编程中文书籍索引。
+建议:请尊重版权 ,哈哈哈。
+密钥/密码
+GitHub 上有太多这样的东西,尽管我没有能赶上个好时候,找到一个合适的密钥。有相关多的资料泄漏和数据库被扒,和 GitHub 上存在的密钥和密码有关。
+不过,好在 GitHub 已经在着手解决这个问题:自动删除相关的提交、代码警告等等。
+私有、商用的 SDK 或代码
+总有人,会将一些商用的代码,或者公司内部的代码,提交到 GitHub 上。如果你偶尔看到这样的代码,除了每一时间告诉作者,还可以偷偷 Clone 一下代码——虽然这样做不对,但是我还是想看。
+如在 ThoughtWorks 的面试流程里,有一个步骤是代码编程的作业,个人的实现是不能公开出来的。接到一份作业的时候,总会去 GitHub 搜索相应的代码是否被提交了。提交了,倒是也得提醒一下相应的候选人。
+过去,我在使用 Phaser 编写应用的时候,对应的粒子系统是收费的。由于我只是尝试这个粒子系统,便没有购买的想法。我一想 GitHub 上可能有,于是搜索了对应的 particle-storm.js,然后就中奖了。就便愉愉快快地去写我的 Hello, World,最后发现它太耗费资源了,便放弃了。
+建议:一旦你在 GitHub 上拿到别人的商用代码,请仅用于学习,并时刻保持低调 。稍有不慎,有牢狱之灾。
+数据及数据制作工具
+当我们需要数据的时候,就会考虑写爬虫。于是 GitHub 上充满了各各样的式爬虫,除此还有得同学把爬虫数据都放在上面了。某次,当我在玩 ElasticSearch 搜索引擎的时候,突然需要一些真实的数据用来测试。便得找爬虫,就在 GitHub 上,找到了大众点评的一些爬虫。
+这个关键词,就是:scrapy dianping.com,得来不费功夫。
+除此,在 AI 相当流行的今天也是如此,也可以搜索到其它同学训练好的模型。
+结论
+试试你的 GitHub 搜索功能吧。
FAQ
如何看待github 项目刷Star行为?
我觉得:在作者开源了源码的情况下,求 star 并没有任何问题。