From 39a2aace6601a70eec73af7727d3750c8bebc8f6 Mon Sep 17 00:00:00 2001 From: Phodal HUANG Date: Mon, 19 Nov 2018 23:01:09 +0800 Subject: [PATCH 01/68] fix: fix typo && closed #27 --- Makefile | 1 - chapters/02-github-fundamentals.md | 4 +- chapters/03-build-github-project.md | 6 +- chapters/06-refactor-project.md | 4 +- chapters/07-tdd-with-autotest.md | 4 +- chapters/11-analytics.md | 14 +- chapters/14-streak-your-github.md | 6 +- github-roam.md | 38 +- index.html | 1693 ++++++++++++++------------- 9 files changed, 897 insertions(+), 873 deletions(-) diff --git a/Makefile b/Makefile index 5bc7895..14f21b8 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,6 @@ html: markdown --include-before-body $(include_dir)/share.html \ --include-after-body $(include_dir)/stats.html \ --title-prefix $(title) \ - -smart \ --toc epub: markdown diff --git a/chapters/02-github-fundamentals.md b/chapters/02-github-fundamentals.md index 13f1318..31a2e01 100644 --- a/chapters/02-github-fundamentals.md +++ b/chapters/02-github-fundamentals.md @@ -107,7 +107,7 @@ jQuery[^jQuery]在发布版本``2.1.3``,一共有152个commit。我们可以 > GitHub可以托管各种git库,并提供一个web界面,但与其它像 SourceForge或Google Code这样的服务不同,GitHub的独特卖点在于从另外一个项目进行分支的简易性。为一个项目贡献代码非常简单:首先点击项目站点的“fork”的按钮,然后将代码检出并将修改加入到刚才分出的代码库中,最后通过内建的“pull request”机制向项目负责人申请代码合并。已经有人将GitHub称为代码玩家的MySpace。 -### 在GitHub创建项目 +### 在 GitHub 创建项目 接着,我们试试在上面创建一个项目: @@ -139,7 +139,7 @@ git push -u origin master 如果你完成了上面的步骤之后,那么我想你想知道你需要怎样的项目。 -##GitHub流行项目分析 +## GitHub 流行项目分析 之前曾经分析过一些GitHub的用户行为,现在我们先来说说GitHub上的Star吧。(截止: 2015年3月9日23时。) diff --git a/chapters/03-build-github-project.md b/chapters/03-build-github-project.md index bfbe0bd..062baaa 100644 --- a/chapters/03-build-github-project.md +++ b/chapters/03-build-github-project.md @@ -324,7 +324,7 @@ branches: 这是一种驱动写出更规范js的方法。 -###Mocha +### Mocha > Mocha 是一个优秀的JS测试框架,支持TDD/BDD,结合 should.js/expect/chai/better-assert,能轻松构建各种风格的测试用例。 @@ -405,7 +405,7 @@ it('should return book label & url', function () { 这就是个问题了,于是偶然间看到了一个叫code climate的网站。 -###Code Climate +### Code Climate > Code Climate consolidates the results from a suite of static analysis tools into a single, real-time report, giving your team the information it needs to identify hotspots, evaluate new approaches, and improve code quality. @@ -435,7 +435,7 @@ A | lib/url_handler.js | 9 | 0 | 5 | 2.2 | 94.1% | 0 ![Coverage][1] -###代码的坏味道 +### 代码的坏味道 于是我们就打开``lib/database/sqlite_helper.js``,因为其中有两个坏味道 diff --git a/chapters/06-refactor-project.md b/chapters/06-refactor-project.md index e91b443..dc7ba4f 100644 --- a/chapters/06-refactor-project.md +++ b/chapters/06-refactor-project.md @@ -309,7 +309,7 @@ Windows/Linux: 木有 鼠标: **Refactor** | ``Replace Temp with Query`` -####重构之前 +#### 重构之前 过多的临时变量会让我们写出更长的函数,函数不应该太多,以便使功能单一。这也是重构的另外的目的所在,只有函数专注于其功能,才会更容易读懂。 @@ -366,7 +366,7 @@ public class replaceTemp { 3. 选择``basePrice``再``Inline Method`` -####Intellij IDEA重构 +#### Intellij IDEA重构 在Intellij IDEA的文档中对此是这样的例子 diff --git a/chapters/07-tdd-with-autotest.md b/chapters/07-tdd-with-autotest.md index e47b0c5..d581f7a 100644 --- a/chapters/07-tdd-with-autotest.md +++ b/chapters/07-tdd-with-autotest.md @@ -96,7 +96,7 @@ req.end(); pip install twill -###Twill 登陆测试 +### Twill 登陆测试 1.启动我们的应用。 @@ -143,7 +143,7 @@ req.end(); 发现重定向到首页了。 -###Twill 测试脚本 +### Twill 测试脚本 当然我们也可以用脚本直接来测试``login.twill``: diff --git a/chapters/11-analytics.md b/chapters/11-analytics.md index 51fb798..be19208 100644 --- a/chapters/11-analytics.md +++ b/chapters/11-analytics.md @@ -146,7 +146,7 @@ draw_date("data/2014-01-01-0.json") 不过这个是osrc的分析结果。 -###python github 每周情况分析 +### python github 每周情况分析 看一张分析后的结果 @@ -183,7 +183,7 @@ draw_date("data/2014-01-01-0.json") 8474, 7984, 12933, 13504, 13763, 13544, 12940, 7119, 7346, 13412, 14008, 12555 -###Python 数据分析 +### Python 数据分析 重写了一个新的方法用于计算提交数,直至后面才意识到其实我们可以算行数就够了,但是方法上有点hack @@ -232,7 +232,7 @@ def get_month_total(): 接着我们需要去遍历每个结果,后面的后面会发现这个效率真的是太低了,为什么木有多线程? -###Python Matplotlib图表 +### Python Matplotlib图表 让我们的matplotlib来做这些图表的工作 @@ -335,7 +335,7 @@ sudo zypper install sqlite3 不过,用yast2也很不错,不是么。。 -###数据导入 +### 数据导入 需要注意的是这里是需要python2.7,起源于对gzip的上下文管理器的支持问题 @@ -413,7 +413,7 @@ date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz") 更好的方案? -###Redis +### Redis 查询用户事件总数 @@ -462,7 +462,7 @@ pipe.execute() 到这里我们算是知道了OSRC的数据库部分是如何工作的。 -####Redis 查询 +#### Redis 查询 主要代码如下所示 @@ -505,7 +505,7 @@ def get_vector(user, pipe=None): osrc最有意思的一部分莫过于flann,当然说的也是系统后台的设计的一个很关键及有意思的部分。 -##邻近算法与相似用户 +## 邻近算法与相似用户 邻近算法是在这个分析过程中一个很有意思的东西。 diff --git a/chapters/14-streak-your-github.md b/chapters/14-streak-your-github.md index 430cb98..fa359b0 100644 --- a/chapters/14-streak-your-github.md +++ b/chapters/14-streak-your-github.md @@ -136,7 +136,7 @@ GitHub连击 这个可以从两部分说起: -####重构Skill Tree +#### 重构 Skill Tree 原来的是 @@ -149,7 +149,7 @@ GitHub连击 代码: [https://github.com/phodal/skillock](https://github.com/phodal/skillock) -####技能树Sherlock +#### 技能树Sherlock - D3.js - Dagre-D3.js @@ -311,7 +311,7 @@ GitHub连击 这也是下一个值得提高的地方。 -###其他 +### 其他 是时候写这个小结了。从不会写代码,到写代码是从0到1的过程,但是要从1到60都不是一件容易的事。无论是刷GitHub也好(不要是自动提交),或者是换工作也好,我们都在不断地练习。 diff --git a/github-roam.md b/github-roam.md index a9762be..5057504 100644 --- a/github-roam.md +++ b/github-roam.md @@ -324,7 +324,7 @@ jQuery[^jQuery]在发布版本``2.1.3``,一共有152个commit。我们可以 > GitHub可以托管各种git库,并提供一个web界面,但与其它像 SourceForge或Google Code这样的服务不同,GitHub的独特卖点在于从另外一个项目进行分支的简易性。为一个项目贡献代码非常简单:首先点击项目站点的“fork”的按钮,然后将代码检出并将修改加入到刚才分出的代码库中,最后通过内建的“pull request”机制向项目负责人申请代码合并。已经有人将GitHub称为代码玩家的MySpace。 -### 在GitHub创建项目 +### 在 GitHub 创建项目 接着,我们试试在上面创建一个项目: @@ -356,7 +356,7 @@ git push -u origin master 如果你完成了上面的步骤之后,那么我想你想知道你需要怎样的项目。 -##GitHub流行项目分析 +## GitHub 流行项目分析 之前曾经分析过一些GitHub的用户行为,现在我们先来说说GitHub上的Star吧。(截止: 2015年3月9日23时。) @@ -759,7 +759,7 @@ branches: 这是一种驱动写出更规范js的方法。 -###Mocha +### Mocha > Mocha 是一个优秀的JS测试框架,支持TDD/BDD,结合 should.js/expect/chai/better-assert,能轻松构建各种风格的测试用例。 @@ -840,7 +840,7 @@ it('should return book label & url', function () { 这就是个问题了,于是偶然间看到了一个叫code climate的网站。 -###Code Climate +### Code Climate > Code Climate consolidates the results from a suite of static analysis tools into a single, real-time report, giving your team the information it needs to identify hotspots, evaluate new approaches, and improve code quality. @@ -870,7 +870,7 @@ A | lib/url_handler.js | 9 | 0 | 5 | 2.2 | 94.1% | 0 ![Coverage][1] -###代码的坏味道 +### 代码的坏味道 于是我们就打开``lib/database/sqlite_helper.js``,因为其中有两个坏味道 @@ -1452,7 +1452,7 @@ Windows/Linux: 木有 鼠标: **Refactor** | ``Replace Temp with Query`` -####重构之前 +#### 重构之前 过多的临时变量会让我们写出更长的函数,函数不应该太多,以便使功能单一。这也是重构的另外的目的所在,只有函数专注于其功能,才会更容易读懂。 @@ -1509,7 +1509,7 @@ public class replaceTemp { 3. 选择``basePrice``再``Inline Method`` -####Intellij IDEA重构 +#### Intellij IDEA重构 在Intellij IDEA的文档中对此是这样的例子 @@ -1647,7 +1647,7 @@ req.end(); pip install twill -###Twill 登陆测试 +### Twill 登陆测试 1.启动我们的应用。 @@ -1694,7 +1694,7 @@ req.end(); 发现重定向到首页了。 -###Twill 测试脚本 +### Twill 测试脚本 当然我们也可以用脚本直接来测试``login.twill``: @@ -2280,7 +2280,7 @@ draw_date("data/2014-01-01-0.json") 不过这个是osrc的分析结果。 -###python github 每周情况分析 +### python github 每周情况分析 看一张分析后的结果 @@ -2317,7 +2317,7 @@ draw_date("data/2014-01-01-0.json") 8474, 7984, 12933, 13504, 13763, 13544, 12940, 7119, 7346, 13412, 14008, 12555 -###Python 数据分析 +### Python 数据分析 重写了一个新的方法用于计算提交数,直至后面才意识到其实我们可以算行数就够了,但是方法上有点hack @@ -2366,7 +2366,7 @@ def get_month_total(): 接着我们需要去遍历每个结果,后面的后面会发现这个效率真的是太低了,为什么木有多线程? -###Python Matplotlib图表 +### Python Matplotlib图表 让我们的matplotlib来做这些图表的工作 @@ -2469,7 +2469,7 @@ sudo zypper install sqlite3 不过,用yast2也很不错,不是么。。 -###数据导入 +### 数据导入 需要注意的是这里是需要python2.7,起源于对gzip的上下文管理器的支持问题 @@ -2547,7 +2547,7 @@ date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz") 更好的方案? -###Redis +### Redis 查询用户事件总数 @@ -2596,7 +2596,7 @@ pipe.execute() 到这里我们算是知道了OSRC的数据库部分是如何工作的。 -####Redis 查询 +#### Redis 查询 主要代码如下所示 @@ -2639,7 +2639,7 @@ def get_vector(user, pipe=None): osrc最有意思的一部分莫过于flann,当然说的也是系统后台的设计的一个很关键及有意思的部分。 -##邻近算法与相似用户 +## 邻近算法与相似用户 邻近算法是在这个分析过程中一个很有意思的东西。 @@ -3139,7 +3139,7 @@ GitHub连击 这个可以从两部分说起: -####重构Skill Tree +#### 重构 Skill Tree 原来的是 @@ -3152,7 +3152,7 @@ GitHub连击 代码: [https://github.com/phodal/skillock](https://github.com/phodal/skillock) -####技能树Sherlock +#### 技能树Sherlock - D3.js - Dagre-D3.js @@ -3314,7 +3314,7 @@ GitHub连击 这也是下一个值得提高的地方。 -###其他 +### 其他 是时候写这个小结了。从不会写代码,到写代码是从0到1的过程,但是要从1到60都不是一件容易的事。无论是刷GitHub也好(不要是自动提交),或者是换工作也好,我们都在不断地练习。 diff --git a/index.html b/index.html index 33d5162..2fc2fe2 100644 --- a/index.html +++ b/index.html @@ -8,63 +8,73 @@ - + @@ -133,8 +143,9 @@

GitHub 漫游指南

  • GitHub
  • +
  • GitHub 流行项目分析
  • Pull Request
  • -
  • 代码质量与重构
  • +
  • 代码质量与重构
  • Git 提交信息及几种不同的规范
  • 功能测试
  • Fake Server
  • @@ -209,8 +226,8 @@

    GitHub 漫游指南

  • Git 与 GitHub 工具推荐
  • 如何在GitHub“寻找灵感(fork)”

    于是有了

    -
    public static void main(String[] args) {
    -
    int result_add=new Cal().add(1,2);
    -
    int result_sub=new Cal2().sub(2,1);
    -
    System.out.println("Hello,s");
    -
    mprint(result_add);
    -
    mprint(result_sub);
    -
    }
    -
    -
    private static void mprint(int result_sub) {
    -
    System.out.println(result_sub);
    -
    }
    +

    似乎我们不应该这样对待System.out.println,那么让我们内联回去

    Inline Method

    快捷键:alt+command+n

    @@ -1499,41 +1524,41 @@

    Inline Method

  • 选中Inline all invocations and remove the method(2 occurrences) 点确定
  • 然后我们等于什么也没有做了~~:

    -
    public static void main(String[] args) {
    -
    int result_add=new Cal().add(1,2);
    -
    int result_sub=new Cal2().sub(2,1);
    -
    System.out.println("Hello,s");
    -
    System.out.println(result_add);
    -
    System.out.println(result_sub);
    -
    }
    +
    public static void main(String[] args) {
    +    int result_add=new Cal().add(1,2);
    +    int result_sub=new Cal2().sub(2,1);
    +    System.out.println("Hello,s");
    +    System.out.println(result_add);
    +    System.out.println(result_sub);
    +}

    似乎这个例子不是很好,但是够用来说明了。

    Pull Members Up

    开始之前让我们先看看Cal2类:

    -
    public class Cal2 extends Cal {
    -
    -
    public int sub(int a,int b){
    -
    return a-b;
    -
    }
    -
    }
    +
    public class Cal2 extends Cal {
    +
    +    public int sub(int a,int b){
    +        return a-b;
    +    }
    +}

    以及Cal2的父类Cal

    -
    public class Cal {
    -
    -
    public int add(int a,int b){
    -
    return a+b;
    -
    }
    -
    -
    }
    +
    public class Cal {
    +
    +    public int add(int a,int b){
    +        return a+b;
    +    }
    +
    +}

    最后的结果,就是将Cal2类中的sub方法,提到父类:

    -
    public class Cal {
    -
    -
    public int add(int a,int b){
    -
    return a+b;
    -
    }
    -
    -
    public int sub(int a,int b){
    -
    return a-b;
    -
    }
    -
    }
    +
    public class Cal {
    +
    +    public int add(int a,int b){
    +        return a+b;
    +    }
    +
    +    public int sub(int a,int b){
    +        return a-b;
    +    }
    +}

    而我们所要做的就是鼠标右键

    重构之以查询取代临时变量

    快捷键

    @@ -1541,42 +1566,42 @@

    重构之以查询取代临时变

    Windows/Linux: 木有

    或者: Shift+alt+command+T 再选择 Replace Temp with Query

    鼠标: Refactor | Replace Temp with Query

    -

    ####重构之前

    +

    重构之前

    过多的临时变量会让我们写出更长的函数,函数不应该太多,以便使功能单一。这也是重构的另外的目的所在,只有函数专注于其功能,才会更容易读懂。

    以书中的代码为例

    -
    import java.lang.System;
    -
    -
    public class replaceTemp {
    -
    public void count() {
    -
    double basePrice = _quantity * _itemPrice;
    -
    if (basePrice > 1000) {
    -
    return basePrice * 0.95;
    -
    } else {
    -
    return basePrice * 0.98;
    -
    }
    -
    }
    -
    }
    +
    import java.lang.System;
    +
    +public class replaceTemp {
    +    public void count() {
    +        double basePrice = _quantity * _itemPrice;
    +        if (basePrice > 1000) {
    +            return basePrice * 0.95;
    +        } else {
    +            return basePrice * 0.98;
    +        }
    +    }
    +}

    重构

    选中basePrice很愉快地拿鼠标点上面的重构

    Replace Temp With Query
    Replace Temp With Query

    便会返回

    -
    import java.lang.System;
    -
    -
    public class replaceTemp {
    -
    public void count() {
    -
    if (basePrice() > 1000) {
    -
    return basePrice() * 0.95;
    -
    } else {
    -
    return basePrice() * 0.98;
    -
    }
    -
    }
    -
    -
    private double basePrice() {
    -
    return _quantity * _itemPrice;
    -
    }
    -
    }
    +
    import java.lang.System;
    +
    +public class replaceTemp {
    +    public void count() {
    +        if (basePrice() > 1000) {
    +            return basePrice() * 0.95;
    +        } else {
    +            return basePrice() * 0.98;
    +        }
    +    }
    +
    +    private double basePrice() {
    +        return _quantity * _itemPrice;
    +    }
    +}

    而实际上我们也可以

    1. 选中

      @@ -1584,17 +1609,17 @@

      重构

    2. 对其进行Extrace Method

    3. 选择basePriceInline Method

    -

    ####Intellij IDEA重构

    +

    Intellij IDEA重构

    在Intellij IDEA的文档中对此是这样的例子

    -
    public class replaceTemp {
    -
    -
    public void method() {
    -
    String str = "str";
    -
    String aString = returnString().concat(str);
    -
    System.out.println(aString);
    -
    }
    -
    -
    }
    +
    public class replaceTemp {
    +
    +    public void method() {
    +        String str = "str";
    +        String aString = returnString().concat(str);
    +        System.out.println(aString);
    +    }
    +
    +}

    接着我们选中aString,再打开重构菜单,或者

    Command+Alt+Shift+T 再选中Replace Temp with Query

    便会有下面的结果:

    @@ -1620,28 +1645,28 @@

    一次测试驱动开发

    之前正在重写一个物联网的服务端,主要便是结合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协议还是蛮清楚的。

    -
    if (!req.headers.authorization) {
    -
    res.statusCode = 401;
    -
    res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
    -
    return res.end('Unauthorized');
    -
    }
    +
    if (!req.headers.authorization) {
    +  res.statusCode = 401;
    +  res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
    +  return res.end('Unauthorized');
    +}

    可是除了HTTP协议,还有MQTT和CoAP。对于MQTT协议来说,那还算好,毕竟自带授权,如:

    -
    mosquitto_pub -u root -P root -h localhost -d -t lettuce -m "Hello, MQTT. This is my first message."
    +
    mosquitto_pub -u root -P root -h localhost -d -t lettuce -m "Hello, MQTT. This is my first message."

    便可以让我们简单地完成这个功能,然而有的协议是没有这样的功能如CoAP协议中是用Option来进行授权的。现在的工具如libcoap只能有如下的简单功能

    -
    coap-client -m get coap://127.0.0.1:5683/topics/zero -T
    +
    coap-client -m get coap://127.0.0.1:5683/topics/zero -T

    于是,先写了个测试脚本来验证功能。

    -
    var coap = require('coap');
    -
    var request = coap.request;
    -
    var req = request({hostname: 'localhost',port:5683,pathname: '',method: 'POST'});
    -
    -
    ...
    -
    -
    req.setHeader("Accept", "application/json");
    -
    req.setOption('Block2', [new Buffer('phodal'), new Buffer('phodal')]);
    -
    -
    ...
    -
    -
    req.end();
    +
    var coap     = require('coap');
    +var request  = coap.request;
    +var req = request({hostname: 'localhost',port:5683,pathname: '',method: 'POST'});
    +
    +...
    +
    +req.setHeader("Accept", "application/json");
    +req.setOption('Block2',  [new Buffer('phodal'), new Buffer('phodal')]);
    +
    +...
    +
    +req.end();

    写完测试脚本后发现不对了,这个不应该是测试的代码吗? 于是将其放到了spec中,接着发现了上面的全部功能的实现过程为什么不用TDD实现呢?

    说说TDD

    测试驱动开发是一个很“古老”的程序开发方法,然而由于国内的开发流程的问题——即开发人员负责功能的测试,导致这么好的一项技术没有在国内推广。

    @@ -1672,7 +1697,7 @@

    轻量级网站测试TWill

    看了一下源码,大概原理就是用requests下载html,接着用lxml解析html,比较有意思的是内嵌了一个DSL

    这是一个Python的库。

     pip install twill
    -

    ###Twill 登陆测试

    +

    Twill 登陆测试

    1.启动我们的应用。

    2.进入twill shell

    twill-sh
    @@ -1704,7 +1729,7 @@ 

    轻量级网站测试TWill

    Note: submit is using submit button: name="login", value="登入" current page: http://127.0.0.1:5000/

    发现重定向到首页了。

    -

    ###Twill 测试脚本

    +

    Twill 测试脚本

    当然我们也可以用脚本直接来测试login.twill:

    go http://127.0.0.1:5000/login
     
    @@ -2030,37 +2055,37 @@ 

    生成图表

    ==, 这个文件代表什么?

    2014年1月1日零时到一时,用户在github上的操作,这里的用户指的是很多。。一共有4814条数据,从commit、create到issues都有。

    数据解析

    -
    import json
    -
    for line in open(jsonfile):
    -
    line = f.readline()
    +

    然后再解析json

    -
    import dateutil.parser
    -
    -
    lin = json.loads(line)
    -
    date = dateutil.parser.parse(lin["created_at"])
    +

    这里用到了dateutil,因为新鲜出炉的数据是string需要转换为dateutil,再到数据放到数组里头。最后有就有了parse_data

    -
    def parse_data(jsonfile):
    -
    f = open(jsonfile, "r")
    -
    dataarray = []
    -
    datacount = 0
    -
    -
    for line in open(jsonfile):
    -
    line = f.readline()
    -
    lin = json.loads(line)
    -
    date = dateutil.parser.parse(lin["created_at"])
    -
    datacount += 1
    -
    dataarray.append(date.minute)
    -
    -
    minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
    -
    f.close()
    -
    return minuteswithcount
    +

    下面这句代码就是将上面的解析为

    -
    minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
    +

    这样的数组以便于解析

    -
    [(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

    -
    sudo pip install matplotlib
    +

    然后引入这个库

      import matplotlib.pyplot as plt

    如上面的那个结果,只需要

    @@ -2071,47 +2096,47 @@

    Matplotlib

    plt.show()

    最后代码可见

    -
    #!/usr/bin/env python
    -
    # -*- coding: utf-8 -*-
    -
    -
    import json
    -
    import dateutil.parser
    -
    import numpy as np
    -
    import matplotlib.mlab as mlab
    -
    import matplotlib.pyplot as plt
    -
    -
    -
    def parse_data(jsonfile):
    -
    f = open(jsonfile, "r")
    -
    dataarray = []
    -
    datacount = 0
    -
    -
    for line in open(jsonfile):
    -
    line = f.readline()
    -
    lin = json.loads(line)
    -
    date = dateutil.parser.parse(lin["created_at"])
    -
    datacount += 1
    -
    dataarray.append(date.minute)
    -
    -
    minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
    -
    f.close()
    -
    return minuteswithcount
    -
    -
    -
    def draw_date(files):
    -
    x = []
    -
    y = []
    -
    mwcs = parse_data(files)
    -
    for mwc in mwcs:
    -
    x.append(mwc[0])
    -
    y.append(mwc[1])
    -
    -
    plt.figure(figsize=(8,4))
    -
    plt.plot(x, y,label = files)
    -
    plt.legend()
    -
    plt.show()
    -
    -
    draw_date("data/2014-01-01-0.json")
    +
    #!/usr/bin/env python
    +# -*- coding: utf-8 -*-
    +
    +import json
    +import dateutil.parser
    +import numpy as np
    +import matplotlib.mlab as mlab
    +import matplotlib.pyplot as plt
    +
    +
    +def parse_data(jsonfile):
    +    f = open(jsonfile, "r")
    +    dataarray = []
    +    datacount = 0
    +
    +    for line in open(jsonfile):
    +        line = f.readline()
    +        lin = json.loads(line)
    +        date = dateutil.parser.parse(lin["created_at"])
    +        datacount += 1
    +        dataarray.append(date.minute)
    +
    +    minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
    +    f.close()
    +    return minuteswithcount
    +
    +
    +def draw_date(files):
    +    x = []
    +    y = []
    +    mwcs = parse_data(files)
    +    for mwc in mwcs:
    +        x.append(mwc[0])
    +        y.append(mwc[1])
    +
    +    plt.figure(figsize=(8,4))
    +    plt.plot(x, y,label = files)
    +    plt.legend()
    +    plt.show()
    +
    +draw_date("data/2014-01-01-0.json")

    每周分析

    继上篇之后,我们就可以分析用户的每周提交情况,以得出用户的真正的工具效率,每个程序员的工作时间可能是不一样的,如

    @@ -2120,7 +2145,7 @@

    每周分析

    这是我的每周情况,显然如果把星期六移到前面的话,随着工作时间的增长,在github上的使用在下降,作为一个

      a fulltime hacker who works best in the evening (around 8 pm).

    不过这个是osrc的分析结果。

    -

    ###python github 每周情况分析

    +

    python github 每周情况分析

    看一张分析后的结果

    Feb Results
    Feb Results
    @@ -2152,159 +2177,159 @@

    每周分析

      6570, 7420, 11274, 12073, 12160, 12378, 12897,
       8474, 7984, 12933, 13504, 13763, 13544, 12940,
       7119, 7346, 13412, 14008, 12555
    -

    ###Python 数据分析

    +

    Python 数据分析

    重写了一个新的方法用于计算提交数,直至后面才意识到其实我们可以算行数就够了,但是方法上有点hack

    -
    def get_minutes_counts_with_id(jsonfile):
    -
    datacount, dataarray = handle_json(jsonfile)
    -
    minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
    -
    return minuteswithcount
    -
    -
    -
    def handle_json(jsonfile):
    -
    f = open(jsonfile, "r")
    -
    dataarray = []
    -
    datacount = 0
    -
    -
    for line in open(jsonfile):
    -
    line = f.readline()
    -
    lin = json.loads(line)
    -
    date = dateutil.parser.parse(lin["created_at"])
    -
    datacount += 1
    -
    dataarray.append(date.minute)
    -
    -
    f.close()
    -
    return datacount, dataarray
    -
    -
    -
    def get_minutes_count_num(jsonfile):
    -
    datacount, dataarray = handle_json(jsonfile)
    -
    return datacount
    -
    -
    -
    def get_month_total():
    -
    """
    -
    -
    :rtype : object
    -
    """
    -
    monthdaycount = []
    -
    for i in range(1, 20):
    -
    if i < 10:
    -
    filename = 'data/2014-02-0' + i.__str__() + '-0.json'
    -
    else:
    -
    filename = 'data/2014-02-' + i.__str__() + '-0.json'
    -
    monthdaycount.append(get_minutes_count_num(filename))
    -
    return monthdaycount
    +

    接着我们需要去遍历每个结果,后面的后面会发现这个效率真的是太低了,为什么木有多线程?

    -

    ###Python Matplotlib图表

    +

    Python Matplotlib图表

    让我们的matplotlib来做这些图表的工作

    -
    if __name__ == '__main__':
    -
    results = pd.get_month_total()
    -
    print results
    -
    -
    plt.figure(figsize=(8, 4))
    -
    plt.plot(results.__getslice__(0, 7), label="first week")
    -
    plt.plot(results.__getslice__(7, 14), label="second week")
    -
    plt.plot(results.__getslice__(14, 21), label="third week")
    -
    plt.legend()
    -
    plt.show()
    +

    蓝色的是第一周,绿色的是第二周,红色的是第三周就有了上面的结果。

    我们还需要优化方法,以及多线程的支持。

    让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章http://www.huyng.com/posts/python-performance-analysis/讲的就是分析这部分内容的。

    存储到数据库中

    SQLite3

    我们创建了一个名为userdata.db的数据库文件,然后创建了一个表,里面有owner,language,eventtype,name url

    -
    def init_db():
    -
    conn = sqlite3.connect('userdata.db')
    -
    c = conn.cursor()
    -
    c.execute('''CREATE TABLE userinfo (owner text, language text, eventtype text, name text, url text)''')
    +

    接着我们就可以查询数据,这里从结果讲起。

    -
    def get_count(username):
    -
    count = 0
    -
    userinfo = []
    -
    condition = 'select * from userinfo where owener = \'' + str(username) + '\''
    -
    for zero in c.execute(condition):
    -
    count += 1
    -
    userinfo.append(zero)
    -
    -
    return count, userinfo
    +

    当我查询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
    +

    一共有109个事件,有Watch,Create,Push,Fork还有其他的, 项目主要有iot,RESUME,iot-dashboard,wechat-wordpress, 接着就是语言了,Tex,Javascript,Ruby,接着就是项目的url了。

    值得注意的是。

    -
    -rw-r--r-- 1 fdhuang staff 905M Apr 12 14:59 userdata.db
    +

    这个数据库文件有905M,不过查询结果相当让人满意,至少相对于原来的结果来说。

    Python自带了对SQLite3的支持,然而我们还需要安装SQLite3

    -
    brew install sqlite3
    +

    或者是

    -
    sudo port install sqlite3
    +

    或者是Ubuntu的

    -
    sudo apt-get install sqlite3
    +

    openSUSE自然就是

    -
    sudo zypper install sqlite3
    +

    不过,用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()
    +

    executemany可以插入多条数据,对于我们的数据来说,一小时的文件大概有五六千个会符合我们上面的安装,也就是有actor又有type才是我们需要记录的数据,我们只需要统计用户的那些事件,而非全部的事件。

    我们需要去遍历文件,然后找到合适的部分,这里只是要找2014-03-012014-03-31的全部事件,而光这些数据的gz文件就有1.26G,同上面那些解压为json文件显得不合适,只能用遍历来处理。

    这里参考了osrc项目中的写法,或者说直接复制过来。

    首先是正规匹配

    -
    date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz")
    +

    不过主要的还是在于glob.glob

    glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,就类似于Windows下的文件搜索,支持通配符操作。

    @@ -2313,24 +2338,24 @@

    SQLite3

    最后代码可以见

    github.com/gmszone/ml

    更好的方案?

    -

    ###Redis

    +

    Redis

    查询用户事件总数

    -
    import redis
    -
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    -
    pipe = pipe = r.pipeline()
    -
    pipe.zscore('osrc:user',"gmszone")
    -
    pipe.execute()
    +

    系统返回了227.0,试试别人。

    -
    >>> pipe.zscore('osrc:user',"dfm")
    -
    <redis.client.StrictPipeline object at 0x104fa7f50>
    -
    >>> pipe.execute()
    -
    [425.0]
    -
    >>>
    +

    看看主要是在哪一天提交的

    -
    >>> pipe.hgetall('osrc:user:gmszone:day')
    -
    <redis.client.StrictPipeline object at 0x104fa7f50>
    -
    >>> pipe.execute()
    -
    [{'1': '51', '0': '41', '3': '17', '2': '34', '5': '28', '4': '22', '6': '34'}]
    +

    结果大致如下图所示:

    SMTWTFS
    SMTWTFS
    @@ -2346,36 +2371,36 @@

    SQLite3

    蓝色的就是push事件,黄色的是create等等。

    到这里我们算是知道了OSRC的数据库部分是如何工作的。

    -

    ####Redis 查询

    +

    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()
    +

    结果在上一篇中显示出来了,也就是

    [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)]]

    有意思的是在这里生成了和自己相近的人

    ['alesdokshanin', 'hjiawei', 'andrewreedy', 'christj6', '1995eaton']

    osrc最有意思的一部分莫过于flann,当然说的也是系统后台的设计的一个很关键及有意思的部分。

    -

    ##邻近算法与相似用户

    +

    邻近算法与相似用户

    邻近算法是在这个分析过程中一个很有意思的东西。

    邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法可以说是整个数据挖掘分类技术中最简单的方法了。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用她最接近的k个邻居来代表。

    @@ -2401,47 +2426,47 @@

    SQLite3

  • 最多的语言
  • osrc中用于解析的代码

    -
    def parse_vector(results):
    -
    points = np.zeros(nvector)
    -
    total = int(results[0])
    -
    -
    points[0] = 1.0 / (total + 1)
    -
    -
    # Week means.
    -
    for k, v in results[1].iteritems():
    -
    points[1 + int(k)] = float(v) / total
    -
    -
    # Event types.
    -
    n = 8
    -
    for k, v in results[2]:
    -
    points[n + evttypes.index(k)] = float(v) / total
    -
    -
    # Number of contributions, connections and languages.
    -
    n += nevts
    -
    points[n] = 1.0 / (float(results[3]) + 1)
    -
    points[n + 1] = 1.0 / (float(results[4]) + 1)
    -
    points[n + 2] = 1.0 / (float(results[5]) + 1)
    -
    points[n + 3] = 1.0 / (float(results[6]) + 1)
    -
    -
    # Top languages.
    -
    n += 4
    -
    for k, v in results[7]:
    -
    if k in langs:
    -
    points[n + langs.index(k)] = float(v) / total
    -
    else:
    -
    # Unknown language.
    -
    points[-1] = float(v) / total
    -
    -
    return points
    +

    这样也就返回我们需要的点数,然后我们可以用get_points来获取这些

    -
    def get_points(usernames):
    -
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    -
    pipe = r.pipeline()
    -
    -
    results = get_vector(usernames)
    -
    points = np.zeros([len(usernames), nvector])
    -
    points = parse_vector(results)
    -
    return points
    +

    就会得到我们的相应的数据,接着找找和自己邻近的,看看结果。

    [ 0.01298701  0.19736842  0.          0.30263158  0.21052632  0.19736842
         0.          0.09210526  0.          0.22368421  0.01315789  0.          0.
    @@ -2510,97 +2535,97 @@ 

    寻找

  • https://github.com/cujojs/when
  • 但是显然,他们都太重了。事实上,对于一个库来说,80%的人只需要其中20%的代码。于是,找到了https://github.com/stackp/promisejs,看了看用法,这就是我们需要的功能:

    -
    function late(n) {
    -
    var p = new promise.Promise();
    -
    setTimeout(function() {
    -
    p.done(null, n);
    -
    }, n);
    -
    return p;
    -
    }
    -
    -
    late(100).then(
    -
    function(err, n) {
    -
    return late(n + 200);
    -
    }
    -
    ).then(
    -
    function(err, n) {
    -
    return late(n + 300);
    -
    }
    -
    ).then(
    -
    function(err, n) {
    -
    return late(n + 400);
    -
    }
    -
    ).then(
    -
    function(err, n) {
    -
    alert(n);
    -
    }
    -
    );
    +

    接着打开看看Promise对象,有我们需要的功能,但是又有一些功能超出我的需求。接着把自己不需要的需求去掉,这里函数最后就变成了

    -
    function Promise() {
    -
    this._callbacks = [];
    -
    }
    -
    -
    Promise.prototype.then = function(func, context) {
    -
    var p;
    -
    if (this._isdone) {
    -
    p = func.apply(context, this.result);
    -
    } else {
    -
    p = new Promise();
    -
    this._callbacks.push(function () {
    -
    var res = func.apply(context, arguments);
    -
    if (res && typeof res.then === 'function') {
    -
    res.then(p.done, p);
    -
    }
    -
    });
    -
    }
    -
    return p;
    -
    };
    -
    -
    Promise.prototype.done = function() {
    -
    this.result = arguments;
    -
    this._isdone = true;
    -
    for (var i = 0; i < this._callbacks.length; i++) {
    -
    this._callbacks[i].apply(null, arguments);
    -
    }
    -
    this._callbacks = [];
    -
    };
    -
    -
    var promise = {
    -
    Promise: 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);
    -
    };
    +

    如何以“正确的姿势”阅读开源软件代码

    所有让你直接看最新源码的文章都是在扯淡,你应该从“某个版本”开始阅读代码。

    @@ -2790,7 +2815,7 @@

    google map solr polygon 搜索

    代码: https://github.com/phodal/gmap-solr

    技能树

    这个可以从两部分说起:

    -

    ####重构Skill Tree

    +

    重构 Skill Tree

    原来的是

    • Knockout
    • @@ -2802,7 +2827,7 @@

      技能树

      Skill Tree
      Skill Tree

    代码: https://github.com/phodal/skillock

    -

    ####技能树Sherlock

    +

    技能树Sherlock

    • D3.js
    • Dagre-D3.js
    • @@ -2933,7 +2958,7 @@

      领域与练习

      而领域本身也是相似的,这可以解释为什么互联网公司都喜欢互相挖人,而一般都不会去华为、中兴等非互联网领域挖人。出了这个领域,你可能连个毕业生都不如。领域、业务同技术一样是不断强化知识的一个过程。Ritchie先实现了BCPL语言,而后设计了C语言,而BCPL语言一开始是基于CPL语言。

      领域本身也在不断进化。

      这也是下一个值得提高的地方。

      -

      ###其他

      +

      其他

      是时候写这个小结了。从不会写代码,到写代码是从0到1的过程,但是要从1到60都不是一件容易的事。无论是刷GitHub也好(不要是自动提交),或者是换工作也好,我们都在不断地练习。

      而练习是要分成不同的几个步骤,不仅仅局限于技术:

        From a0479896e80dd4e06d24eabf3ca59d18b21ecda6 Mon Sep 17 00:00:00 2001 From: Phodal HUANG Date: Thu, 29 Nov 2018 22:03:00 +0800 Subject: [PATCH 02/68] [ch17] add find projects in github --- chapters/16-find-in-github.md | 82 ++ chapters/{16-faq.md => 17-faq.md} | 0 github-roam.md | 83 ++ index.html | 1651 +++++++++++++++-------------- 4 files changed, 1018 insertions(+), 798 deletions(-) create mode 100644 chapters/16-find-in-github.md rename chapters/{16-faq.md => 17-faq.md} (100%) diff --git a/chapters/16-find-in-github.md b/chapters/16-find-in-github.md new file mode 100644 index 0000000..bf512b6 --- /dev/null +++ b/chapters/16-find-in-github.md @@ -0,0 +1,82 @@ +# 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生成轮子](https://www.phodal.com/blog/create-framework-from-github/)》 一文,怕是能写一系列的框架。而造一个相似轮子的想法,往往很多人都有。尤其是一个成熟的框架,往往有很多仿制品。 + +于是,当你想了解一个框架,造个轮子,不妨试试搜索 ``xxx-like`` 或者 ``xxx-like framework``,中文便是 ``仿 react 框架`` 或者 ``类 react``。如我们在 Google 上搜索 ``react-like`` 就会搜索到 ``inferno``。不过,按 GitHub 的尿性,要搜索到这样的框架,并不是一件容易的事。这时 Google 往往比 GitHub 搜索好用。 + +所以建议:**平时上班休息时,搜索相关的轮子,回家就可以造轮子了。** + +## 学习资源 + +GitHub 上拥有大量的学习资源,从各类的文章到笔记,还有各式各样的电子书。如: + + 1. 只需要搜索:``类型 + 笔记``,如 ``操作系统 笔记`` 就能找到一些操作系统相关的笔记。 + 2. 只需要搜索:``书名`` 就能找到一些和这本书相关的资源,如 ``重构 改善既有代码的设计``。 + +与此同时,GitHub 上还会搜索到各种 **未经授权**英文书籍的翻译,又或者是各种电子书的 PDF 版。作为多本书的作译者,当然不鼓励 GitHub 上找到一些盗版书。 + +而在 GitHub 上又有一些库,可以提供相应的学习资源,如 [free-programming-books-zh_CN](https://github.com/justjavac/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 搜索功能吧。 diff --git a/chapters/16-faq.md b/chapters/17-faq.md similarity index 100% rename from chapters/16-faq.md rename to chapters/17-faq.md diff --git a/github-roam.md b/github-roam.md index 5057504..e55b544 100644 --- a/github-roam.md +++ b/github-roam.md @@ -3559,6 +3559,89 @@ GitHub 里程碑 [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生成轮子](https://www.phodal.com/blog/create-framework-from-github/)》 一文,怕是能写一系列的框架。而造一个相似轮子的想法,往往很多人都有。尤其是一个成熟的框架,往往有很多仿制品。 + +于是,当你想了解一个框架,造个轮子,不妨试试搜索 ``xxx-like`` 或者 ``xxx-like framework``,中文便是 ``仿 react 框架`` 或者 ``类 react``。如我们在 Google 上搜索 ``react-like`` 就会搜索到 ``inferno``。不过,按 GitHub 的尿性,要搜索到这样的框架,并不是一件容易的事。这时 Google 往往比 GitHub 搜索好用。 + +所以建议:**平时上班休息时,搜索相关的轮子,回家就可以造轮子了。** + +## 学习资源 + +GitHub 上拥有大量的学习资源,从各类的文章到笔记,还有各式各样的电子书。如: + + 1. 只需要搜索:``类型 + 笔记``,如 ``操作系统 笔记`` 就能找到一些操作系统相关的笔记。 + 2. 只需要搜索:``书名`` 就能找到一些和这本书相关的资源,如 ``重构 改善既有代码的设计``。 + +与此同时,GitHub 上还会搜索到各种 **未经授权**英文书籍的翻译,又或者是各种电子书的 PDF 版。作为多本书的作译者,当然不鼓励 GitHub 上找到一些盗版书。 + +而在 GitHub 上又有一些库,可以提供相应的学习资源,如 [free-programming-books-zh_CN](https://github.com/justjavac/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 === diff --git a/index.html b/index.html index 2fc2fe2..f6b180f 100644 --- a/index.html +++ b/index.html @@ -29,7 +29,7 @@ pre.numberSource a.sourceLine { position: relative; left: -4em; } pre.numberSource a.sourceLine::before - { content: attr(data-line-number); + { content: attr(title); position: relative; left: -1em; text-align: right; vertical-align: baseline; border: none; pointer-events: all; display: inline-block; -webkit-touch-callout: none; -webkit-user-select: none; @@ -303,6 +303,17 @@

        GitHub 漫游指南

      1. 下一个开源项目
    +
  • GitHub 寻宝指南
  • FAQ
  • @@ -314,13 +325,13 @@

    关于作者

    作为一个开源软件作者,著有 Growth、Stepping、Lan、Echoesworks 等软件。其中开源学习应用 Growth,广受读者和用户好评,可在 APP Store 及各大 Android 应用商店下载。

    作为一个技术作者,著有《自己动手设计物联网》(电子工业出版社)、《全栈应用开发:精益实践》(电子工业出版社,正在出版)。并在 GitHub 上开源有《Growth: 全栈增长工程师指南》、《GitHub 漫游指南》等七本电子书。

    作为技术专家,他为英国 Packt 出版社审阅有物联网书籍《Learning IoT》、《Smart IoT》,前端书籍《Angular 2 Serices》、《Getting started with Angular》等技术书籍。

    -

    他热爱编程、写作、设计、旅行、hacking,你可以从他的个人网站:https://www.phodal.com/ 了解到更多的内容。

    +

    他热爱编程、写作、设计、旅行、hacking,你可以从他的个人网站:https://www.phodal.com/ 了解到更多的内容。

    其它相关信息:

    当前为预览版,在使用的过程中遇到任何问题请及时与我联系。阅读过程中的问题,不妨在GitHub上提出来: Issues

    阅读过程中遇到语法错误、拼写错误、技术错误等等,不妨来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。

    @@ -582,35 +593,35 @@

    GitHub 流行项目分析

    Bootstrap CSS 78490 -https://github.com/twbs/bootstrap +https://github.com/twbs/bootstrap vhf free-programming books - 37240 -https://github.com/vhf/free-programming-books +https://github.com/vhf/free-programming-books angular angular.js JavaScript 36,061 -https://github.com/angular/angular.js +https://github.com/angular/angular.js mbostock d3 JavaScript 35,257 -https://github.com/mbostock/d3 +https://github.com/mbostock/d3 joyent node JavaScript 35,077 -https://github.com/joyent/node +https://github.com/joyent/node @@ -720,24 +731,24 @@

    敏捷软件开发

    当只有一个人的时候,你只需要明确知道自己想要什么就够了。我们还需要的是CI、测试,以来提升代码的质量。

    测试

    通常我们都会找Document,如果没有的话,你会找什么?看源代码,还是看测试?

    - -

    代码来源: https://github.com/phodal/lettuce

    + +

    代码来源: https://github.com/phodal/lettuce

    上面的测试用例,清清楚楚地写明了用法,虽然写得有点扯。

    等等,测试是用来干什么的。那么,先说说我为什么会想去写测试吧: