├── .gitignore ├── Algorithm ├── README.md └── calculate-complexity-of-algorithm.md ├── Live ├── career-route.md ├── how-to-build-personal-influence.md ├── how-to-promote-a-newtech-in-your-team.md ├── how-to-read-source-code.md ├── how-to-write-dissert.md ├── how-to-write-readme.md ├── how-to-write-tech-research.md └── images │ ├── .DS_Store │ ├── career-route │ ├── .DS_Store │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ └── 6.png │ └── how-to-write-readme │ └── licence.png ├── README.md ├── basic-knowledge └── string-code.md ├── computer-system └── linux │ ├── README.md │ └── apache-config.md ├── database ├── README.md ├── advance │ └── optimize-sql.md └── basic │ ├── date.md │ ├── other.md │ ├── select-basic.md │ ├── select-usage.md │ ├── string.md │ └── view.md ├── machine-learing ├── README.md └── introduction.md ├── network-of-computer ├── images │ ├── dns-lb.png │ ├── ip-lb.png │ └── mac-lb.png └── load-balance.md ├── programming-concept ├── design-patterns │ ├── README.md │ ├── behavioral-patterns │ │ └── chain-of-responsibility.md │ └── creational-patterns │ │ ├── README.md │ │ ├── abstract-factory.md │ │ ├── builder.md │ │ ├── factory-method.md │ │ ├── prototype.md │ │ └── singleton.md └── functional-programming │ ├── README.md │ ├── aop.md │ └── images │ ├── aop1.png │ └── aop2.png ├── software-engineering ├── README.md ├── code-style-standard.md ├── git-commit-standard.md ├── how-to-write-a-technoloy-plan.md └── scrum.md └── tools ├── git ├── README.md ├── git-commit.md ├── git-delete-branch.md ├── git-multi-user.md ├── git-problems.md ├── git-reset-commit.md └── images │ └── git-ssh-key.png ├── graph.md ├── ide.md ├── shell-dict.md └── tools.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Algorithm/README.md: -------------------------------------------------------------------------------- 1 | ## 算法 2 | 3 | * [如何计算时间复杂度和空间复杂度?](./calculate-complexity-of-algorithm.md) -------------------------------------------------------------------------------- /Algorithm/calculate-complexity-of-algorithm.md: -------------------------------------------------------------------------------- 1 | ## 如何计算时间复杂度和空间复杂度? 2 | 3 | #### 算法 4 | 5 | 算法对我们来说都很熟悉,简单来说,算法可以理解为解决方案清晰而准确的描述,解决一系列问题的清晰指令。 6 | 7 | #### 算法的效率 8 | 9 | 既然算法是解决问题的描述,那么针对一个问题,可能会有很多种不同的解法,只是不同的算法使用的时间或者消耗的内存不一样,所以我们需要一些标准去衡量算法的优劣。 10 | 11 | 算法的效率主要由以下两个参数来评估: 12 | 13 | * 时间复杂度:评估执行程序所需的时间。估算出程序对处理器的使用程度。 14 | * 空间复杂度:评估执行程序所需的存储空间。估算出程序对内存空间的使用程度。 15 | 16 | #### 时间复杂度 17 | 18 | 一个算法程序执行的时间理论上是无法计算出来的,但是我们有没有必要去执行每个算法进行测试,只需要大概知道哪个算法所花的时间多,哪个算法所花的时间少即可。 19 | 20 | 一个算法所需要的时间与算法中代码语句的数量成正比,算法中语句的数量越多,算法所花费的时间就越多。 21 | 22 | 我们把一个算法中的语句执行次数称为**时间频度**,通常用`T(n)`表示。 23 | 24 | 在时间频度`T(n)`中,当n不断变化,`T(n)`也会随之不断变化。为了描述这个变化的规律,引入了**时间复杂度**这一概念。 25 | 26 | 如果有某一个辅助函数f(n),在n趋于无穷大时,`T(n)/f(n)`的极限值是不为零的某一个常数,那么f(n)是`T(n)`的同数量级函数,记做`T(n)=O(f(n))`,称为算法的渐进时间复杂度,简称为时间复杂度。 27 | 28 | #### 大O表示法 29 | 30 | > 用O(n)来体现算法时间复杂度的记法被称作大O表示法 31 | 32 | 一般我们直接评估一个算法最坏的时间复杂度。 33 | 34 | 大O表示法`O(f(n))`中的`f(n)`的值可以为`1、n、logn、n^2`等,所以我们将`O(1)、O(n)、O(logn)、O(n^2)`分别称为常数阶、线性阶、对数阶和平方阶。 35 | 36 | #### 推导大O阶 37 | 38 | 推导规则: 39 | 40 | * 用常数1替代所有加法常数 41 | * 只保留最高阶项 42 | * 去除最高阶的常数 43 | 44 | ##### 常数阶 45 | 46 | ``` python 47 | a = 1 48 | b = 2 49 | 50 | print a / b 51 | ``` 52 | 53 | 这段代码会执行三条语句,算法时间复杂度为O(1),是常数阶。 54 | 55 | 算法的执行时间不会随着n的增加而增长,即使算法有上千条语句,执行时间也只是一个比较大的常数。此类算法时间复杂度为O(1) 56 | 57 | ##### 线性阶 58 | 59 | ``` python 60 | a = 1 61 | 62 | while a < n: 63 | a += 1 64 | ``` 65 | 66 | 这段代码执行语句数和n的大小有关,时间复杂度为O(n)。 67 | 68 | 算法执行时间随着n的增加成线性增长。 69 | 70 | ##### 对数阶 71 | 72 | ``` python 73 | a = 1 74 | 75 | while a < n: 76 | a *= 2 77 | ``` 78 | 79 | 在上面的算法中,a每次都会放大两倍,假设循环执行m次,由`2^m = n`得出`m = logn`,所以时间复杂度为O(logn)。 80 | 81 | ##### 平方阶 82 | 83 | ``` python 84 | def test(n): 85 | for i in range(n): 86 | for j in range(n): 87 | print i * j 88 | ``` 89 | 90 | 上面的循环中,代码执行2*n^2+n行,时间复杂度为O(n^2)。 91 | 92 | 时间复杂度性能比较: 93 | 94 | `O(1) 影响力,一般指的是用他人乐于接受的方式,改变他人思想和行动的能力。 4 | 5 | 影响力可以分为权力性影响力和非权力性影响力。 6 | 7 | * 权力性影响力:主要源于法律、职位、习惯和武力等,这种影响力具有不可抗拒性。 8 | * 非权力性影响力:主要来源于个人魄力,来源于影响者和被影响者之间的相互感召和相互信赖。 9 | 10 | 影响力就是个人品牌的作用,在提起某样东西的时候,别人能第一时间想起你,你说的话和你做的事情都能影响一定数量的人群。 11 | 12 | 在这个注重个人品牌的时代,每个人都是一个超级IP(intellectual property),任何人都有可能成为明星,我们应该把自己当成一家公司来经营。已经有无数的人通过微信公众号、知乎、直播平台、抖音等内容平台收获大量粉丝,形成自己的个人品牌和影响力。 13 | 14 | 对于程序员来说,自然也要跟上时代的浪潮,积极的去打造个人影响力。影响力对于工作求职来说都是有促进作用的,当你在技术领域有一定影响力,说明大家认可你的能力,也有利于个人成长和事业发展。 15 | 16 | 那么问题来了,作为一个程序员,如何提升自己的个人技术影响力呢? 17 | 18 | 对此,我作了一个简单的总结思考,我们可以从下面几个方面着手去提升自己的影响力。 19 | 20 | * 明确定位 21 | * 提升技术 22 | * 乐于分享 23 | 24 | ### 1.明确定位 25 | 对于一家公司来说,最重要的事就是明确公司的愿景和要务。对于一个人来说,最重要的事是选择深入学习的行业和领域,确定学习的方向。所以对于我们程序员来说,首先要选择自己深入研究的技术领域。 26 | 27 | 现在常见的技术领域有:前端、移动端、后端、测试、运维、数据、算法等。对于学生来说,应该选择一个感兴趣的方向去学习。而对于已经工作的人来说,大的技术领域已经明确了,我们应该选择一个细分的技术领域去深入学习。例如前端还可以划分为几大领域:Node.js、中后台开发、端技术、可视化、开发者服务等方向,我们应该选择一个具体的细分领域去深入学习,努力成为这个领域的专家。 28 | 29 | 选择细分领域的目的是,你能够集中精力去研究这个领域中的所有难题,从而成为领域专家。如果别人遇到这个领域的技术问题或者某个标签时,立马就会想到你,更有利于扩大影响力。 30 | 31 | 明确自身的定位之后,影响的受众也随之确定了,如果你选择学习前端,那么你以后影响到的人群肯定大部分都是前端。实际上我们也可以先考虑自己想要的影响的人群,再确立自身的定位。 32 | 33 | ### 2.提升技术 34 | 明确定位之后,我们就确认了前进的方向了,接下来就是要努力提升自身技术了,努力去在相应的技术领域拿到一定结果。 35 | 36 | 提升技术的途径有很多: 37 | 38 | * 学习框架的官方文档,阅读源码。 39 | * 阅读技术书籍,查看相关的学习视频、技术文章等。 40 | * 参加技术交流会。 41 | 42 | 我们应该尝试去做出一些产品,例如实现一个工具库,能够给其他人带来帮助,解决其他人的问题。最终目的是拿到一个结果,让你的话更有说服力。 43 | 44 | ### 3.乐于分享 45 | 明确好定位之后,在努力提升技术的过程中,我们就可以开始去加强自己的影响力。积极分享自己所学的知识,分享也是一个将输入转化为输出的过程,也会提升写作能力、表达能力、逻辑思维等软能力。通过分享知识,我们也能收到受众的反馈,这是一个正向循环的过程。 46 | 47 | 分享的方式有很多: 48 | 49 | * 音频、视频 50 | * 写文章、写书 51 | * 向开源项目贡献代码 52 | * 在社区中解答别人的问题 53 | 54 | 写技术文章是一个比较常见的方式,我认为写博客有几个关键点需要考虑: 55 | 56 | * 文章要有质量 57 | * 记录解决问题的过程及思考 58 | * 系列化输出 59 | * 考虑受众的层次:初级入门者?进阶?高级? 60 | * 坚持输出 61 | 62 | 很多人会说,写博客不知道写什么内容,其实写博客不一定要写很高深的内容,但是一定要有质量,要有自己的思考,寻找自己与别人的不同之处。例如,你现在搜一下ES6,网上的入门教程已经有很多了,所以你再去写入门教程就没有什么意义了。你可以写一写自己在学习ES6过程中遇到的问题,或者分享自己在学习过程中写的Demo,这样的分享内容就具有一定的价值。 63 | 64 | 我们在学习的过程中肯定会遇到各种各样的问题,我们可以把遇到问题和解决问题的过程和别人分享。分享自己遇到了哪些问题,怎么解决这些问题的,在解决问题的过程中收获了什么。 65 | 66 | 对于一个技术领域,可以尝试进行系列化输出,这样即可以整理自己的知识体系,也能给受众一个系统化的学习资料。例如前端开发的学习,可以分初级、进阶、高级等阶段进行系列化整理输出。 67 | 68 | 写文章的过程中,最重要的就是要坚持。一开始可能粉丝很少,阅读量很少,但你的文章质量都不错,在达到一定的数量后,自然会有一定的影响力。所以最重要的是要坚持去写,不能放弃。**当然也不能自嗨,要注意去营销自己、推广自己。** 69 | 70 | 当然,我们分享的方式也不局限于写文章,还有制作培训视频,在技术交流会上分享等方式。 71 | 72 | 最后可能还有一个问题:我们可以在哪里去分享自己的文章? 73 | 实际上现在有很多的垂直内容平台,我们可以针对与自己的领域,在很多平台上进行分享。 74 | 75 | 下面是我对可以帮助打造影响力的平台的梳理。 76 | 77 | | 文章类型| 文章内容 | 平台 | 78 | | --- | --- | --- | 79 | | 技术文章 | 技术以及技术职场相关 | Github、cnblogs、CSDN、博客园、掘金、简书、知乎专栏、segmentfault | 80 | | 生活感悟 | 生活中的遇到的问题 | 微信公众号、个人博客、知乎、豆瓣、简书 | 81 | | 读书笔记 | 书中内容引发的思考 | 微信公众号、知乎、豆瓣、简书 | 82 | -------------------------------------------------------------------------------- /Live/how-to-promote-a-newtech-in-your-team.md: -------------------------------------------------------------------------------- 1 | ## 如何在团队中推广一门新技术 2 | 3 | ### 一、新技术是什么 4 | 5 | ### 二、 该技术目前的发展水平 6 | 7 | #### 2.1 目前现状 8 | 9 | #### 2.2 社区发展现状 10 | * 工具、工程化支持 11 | * IDE支持 12 | * 社区应用情况 13 | * 公司内应用情况 14 | 15 | ### 三、竞品分析 16 | * 使用量、热度对比 17 | * 开发团队对比、维护程度对比 18 | * 社区发展情况、配套设施对比 19 | 20 | ### 四、在本团队中使用新技术的收益 21 | 22 | ### 五、新技术在团队中使用的可能性及成本 23 | 24 | #### 5.1 学习成本 25 | 26 | #### 5.2 应用成本 27 | * 起步成本 28 | * 工具、工程化 29 | * 迁移成本 30 | 31 | ### 六、落地的步骤及程度 32 | * 在哪些场景下使用 33 | * 怎么用?用到什么程度? 34 | * 推进时间节奏 35 | 36 | -------------------------------------------------------------------------------- /Live/how-to-read-source-code.md: -------------------------------------------------------------------------------- 1 | ## How to read source code? 2 | 3 | ### Steps 4 | 5 | #### 浏览看框架文档 6 | 先看框架的文档,弄清楚这个框架的用处,了解框架的优缺点。 7 | 8 | #### 运行框架源代码 9 | 参照框架的官方文档或者Git仓库中的Readme文档,尝试运行框架代码,观察运行结果,对框架功能有一个清晰的体感。 10 | 11 | #### 仔细查阅框架文档 12 | 仔细阅读框架的文档,查看API及其使用方法。在这个过程中可以做一些实际的项目去熟悉框架的使用,加深理解。 13 | 14 | #### 设想框架实现原理 15 | 针对框架的一些API或者优点,自己先设想一下是怎么实现的,然后带着问题去阅读源码。 16 | 17 | #### 带着问题和目标去看源码 18 | 经过前面的一些过程,我们已经熟悉了框架的使用,在使用过程中肯定会有很多问题,这个时候带着问题去针对性的看源码,效率会很高。比如在使用react的过程中,经常会用到`setState`,但是`setState`的是如何实现的呢?这时候就可以通过看源码去了解其实现过程。 19 | 20 | ### Reference: 21 | 22 | * [Reading Your Framework’s Source Code? Yes, You Can Do It](https://medium.com/@urish/reading-your-frameworks-source-code-yes-you-can-do-it-2bdd8c9e947b) 23 | * [如何阅读大型前端开源项目的源码](https://juejin.im/post/5afe3735518825426539afce) 24 | * [stackoverflow: How/Where to start reading open source code](https://stackoverflow.com/questions/3318684/how-where-to-start-reading-open-source-code) -------------------------------------------------------------------------------- /Live/how-to-write-dissert.md: -------------------------------------------------------------------------------- 1 | ## How to wirte the abstract of a paper? 2 | 3 | ### Abstract 4 | 5 | When you are writing an academic or scientific paper,you must need to an abstract of your essay. It is vital to write a complete but concise description of your work to entice potential readers into obtaining a copy of the full paper. Whether it is a scientific experiment or a literary analysis paper. It should help your reader understand your paper and help people searching for this paper decide whether it suits their purposes prior to reading. 6 | 7 | In order to write a good abstract,writers should follow a checklist consisting of: motivation, problem statement, approach, result, and conclusions.Following the checklist should increase the chance of people taking the time to obtain and read your complete paper.After you get the details down,all left is to format it correctly. Since an abstract is only a summary of your work you have done, it is easy to accomplish! 8 | 9 | -------------------------------------------------------------------------------- /Live/how-to-write-readme.md: -------------------------------------------------------------------------------- 1 | ## 如何写好一个README? 2 | 3 | ### 一、目的 4 | 编写一个项目的README文件就像写一本书的序言一样,一个好的项目不仅本身需要具有一定价值,同时应该有一份高质量的文档。方便用户快速了解项目解决的问题、项目开发环境、项目开发语言等,让用户快速抉择是否需要深入了解这个项目,也减少了用户的使用成本。 5 | 6 | ### 二、组成部分 7 | 看过github上的一些README,总结一下,主要有以下几个核心部分组成: 8 | 9 | * 项目介绍 10 | * 项目使用方法 11 | * API文档 12 | * 作者联系信息 13 | 14 | 更完善的模块如下: 15 | 16 | * 国际化 17 | * 项目介绍 18 | * 项目使用方法 19 | * API文档 20 | * 版本变化 21 | * 待完善功能 22 | * 常见问题汇总 23 | * 作者联系信息 24 | * 贡献者/贡献组织 25 | * 版权信息 26 | 27 | ### 三、模块介绍 28 | #### 3.1 国际化 29 | Github是面向全球的“交友网站”,所以可能会有国外的开发者需要使用你的项目,这时候就需要一份双语的文档了。 30 | 31 | #### 3.2 项目介绍 32 | 这部分是整个README中比较核心的部分,主要从几个方面入手去写这部分内容: 33 | 34 | * 项目名称及logo 35 | * 项目用途 36 | * 项目开发语言 37 | * 项目特点 38 | * 项目架构 39 | * 项目最新版本信息 40 | * 项目目前有哪些用户 41 | * Demo演示地址或者官网 42 | 43 | 当然,上面所列举的因素不一定是都需要去描述的,也可以放在其他部分去描述。 44 | 45 | #### 3.3 项目使用方法 46 | 通过这部分内容,用户能够快速了解如何使用你的项目。 47 | 首先应该告诉用户**如何获取以及初始化你的项目**,然后告诉用户**运行、编译、部署、调试**的操作流程。 48 | 49 | #### 3.4 API文档 50 | 当用户使用你的项目出现问题时,就会需要查阅你的API文档,所以API文档也要尽可能友好。 51 | 应该表达清楚每个API的作用、入参出参、返回值等。 52 | 53 | #### 3.5 版本变化 54 | 可以写一份CHANGELOG文档,记录各个版本的修改内容,方便用户去选择使用哪个版本。 55 | 56 | #### 3.6 待完善功能 57 | 这部分可以让用户了解到你的开发计划,有哪些新功能已经在你的开发计划中,也让用户明确你的项目是在不断维护更新的。 58 | 59 | #### 3.7 常见问题汇总 60 | 记录一些常见的问题。 61 | 62 | #### 3.8 作者联系信息 63 | 方便联系作者 64 | 65 | #### 3.9 贡献者/贡献组织 66 | 将项目贡献者和贡献组织公示出来,可以吸引到更多开发者参与到我们的开源项目中。 67 | 68 | #### 3.10 版权信息 69 | 维护作者利益。 70 | 最流行的有六种:GPL、BSD、MIT、Mozilla、Apache、LGPL。 71 | ![licence](./images/how-to-write-readme/licence.png) 72 | 73 | ### 四、参考 74 | * [README语法](http://younghz.github.io/Markdown/) 75 | * [webpack README](https://github.com/webpack/webpack) 76 | * [ant-design README](https://github.com/ant-design/ant-design) 77 | -------------------------------------------------------------------------------- /Live/how-to-write-tech-research.md: -------------------------------------------------------------------------------- 1 | ## 技术调研方案 2 | 3 | ### 背景及需求 4 | 5 | ### 调研内容 6 | 7 | ### 竞品分析 8 | 9 | ### 使用体验 10 | 11 | ### 调研结论 12 | 13 | * 明确结论 14 | * 可行性建议 -------------------------------------------------------------------------------- /Live/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/.DS_Store -------------------------------------------------------------------------------- /Live/images/career-route/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/.DS_Store -------------------------------------------------------------------------------- /Live/images/career-route/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/1.png -------------------------------------------------------------------------------- /Live/images/career-route/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/2.png -------------------------------------------------------------------------------- /Live/images/career-route/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/3.png -------------------------------------------------------------------------------- /Live/images/career-route/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/4.png -------------------------------------------------------------------------------- /Live/images/career-route/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/5.png -------------------------------------------------------------------------------- /Live/images/career-route/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/career-route/6.png -------------------------------------------------------------------------------- /Live/images/how-to-write-readme/licence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/Live/images/how-to-write-readme/licence.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Github文档库更新慢,最新内容请关注语雀:https://www.yuque.com/qingsong-cqkvm/uumwa8 2 | 3 | ## :bomb: 计算机基础知识 4 | - [字符编码](./basic-knowledge/string-code.md) 5 | 6 | ## :cloud: 计算机网络 7 | - [TCP/IP](#) 8 | - [负载均衡](#) 9 | 10 | ## :bamboo: 操作系统 11 | - [计算机操作系统](#) 12 | 13 | - [Linux](./computer-system/linux/README.md) 14 | 15 | ## :key: 数据结构与算法 16 | - [算法](./Algorithm/) 17 | 18 | - [Leetcode题解](https://github.com/suvllian/problem-oj/tree/master/LeetCode) 19 | 20 | 对题目进行分类,总结解题思路及解法。 21 | 22 | - [机器学习](./machine-learing/) 23 | 24 | ## :game_die: 计算机组成原理 25 | 26 | 27 | ## :tractor: 数据库 28 | - [数据库基础知识](./database) 29 | 30 | 基本SQL使用及常见的查询场景 31 | 32 | - [数据库进阶知识](./database) 33 | 34 | 慢SQL优化 35 | 36 | - 数据库类型: 37 | - 关系型数据库:Mysql 38 | - 非关系型数据库:MongoDb 39 | - 缓存数据库:redis 40 | 41 | ## :horse_racing: 编程思想 42 | - 设计模式 43 | - 设计模式原则 44 | - [创建型设计模式](./programming-concept/design-patterns/creational-patterns) 45 | - 工厂模式 46 | - 抽象工厂模式 47 | - 生成器模式 48 | - 原型模式 49 | - 单例模式 50 | - [结构型设计模式](./programming-concept/design-patterns/structural-patterns) 51 | - [行为设计模式](./programming-concept/design-patterns/behavioral-patterns) 52 | - 职责链模式 53 | 54 | - [函数式编程](./programming-concept/functional-programming/) 55 | - 面向切面编程 56 | 57 | ## :running: 软件工程 58 | - 项目开发 59 | - [敏捷软件开发](./software-engineering/scrum.md) 60 | - [如何写好一份技术评审方案](./software-engineering/how-to-write-a-technoloy-plan.md) 61 | 62 | - 团队合作 63 | - [编码规范](./software-engineering/code-style-standard.md) 64 | - [git commit规范](./software-engineering/git-commit-standard.md) 65 | 66 | 67 | ## :rocket: 开发工具 68 | 69 | - [提效工具、chrome插件等](./tools/tools.md) 70 | - [常用shell命令](./tools/shell-dict.md) 71 | - [IDE](./tools//ide.md) 72 | - [Git](./tools/git/README.md) 73 | - [画图工具](./tools/graph.md) 74 | 75 | ## :grinning: 代码之外的生存之道 76 | 77 | - 职业规划 78 | - [程序员的职业规划](./Live/career-route.md) 79 | 80 | - 自我营销 81 | - [程序员如何打造个人影响力](./Live/how-to-build-personal-influence.md) 82 | 83 | - 学习及方法论 84 | - [如何写好一个README](./Live/how-to-write-readme.md) 85 | - [技术调研方案框架](./Live/how-to-write-tech-research.md) 86 | - [如何阅读源代码](./Live/how-to-read-source-code.md) 87 | - [如何在团队中推广一门新技术](./Live/how-to-promote-a-newtech-in-your-team.md) 88 | -------------------------------------------------------------------------------- /basic-knowledge/string-code.md: -------------------------------------------------------------------------------- 1 | ## 字符编码 2 | 3 | ### 个人总结 4 | * 字符集:一个系统支持的所有抽象字符的集合。ASCII字符集、GB2312字符集、Unicode字符集。 5 | * 字符编码:一套将自然语言与其他东西结合配对的规则。UTF-8编码。 6 | 7 | Unicode字符集将世界上所有符号都纳入其中。 8 | UTF-8是可变长编码,可以节省存储大小,是互联网中使用最多的对Unicode的实现方式。 9 | 10 | **为什么会出现乱码?** 11 | 12 | 使用了不同的编解码方式。例如使用UTF-8编码,却使用GBK解码,就会导致乱码。 13 | 14 | ### 参考文章 15 | * [十分钟搞清字符集和字符编码](http://cenalulu.github.io/linux/character-encoding/) 16 | * [ASCII,Unicode,GBK和UTF-8字符编码的区别和联系](https://www.cnblogs.com/geons/p/9352256.html) -------------------------------------------------------------------------------- /computer-system/linux/README.md: -------------------------------------------------------------------------------- 1 | ## Linux 2 | 3 | * [Linux系统下Apache服务器的配置](./apache-config.md) 4 | -------------------------------------------------------------------------------- /computer-system/linux/apache-config.md: -------------------------------------------------------------------------------- 1 | # Linux系统下Apache服务器的配置 2 | 3 | ## 一、设置404页面 4 | * 修改httpd文件,设置AllowOverride All 5 | * 在服务器配置的网站根目录下添加.htacess文件,添加内容ErrorDocument 404 /404.html(404.html为编辑好的404页面) 6 | * 重启服务器即可 7 | 8 | ## 二、设置403Forbidden禁止访问目录,关闭目录浏览权限 9 | 有些情况下,如果没有对某些目录设置403权限,用户可直接根据路径查看到当前文件夹下所有文件,这对于网站安全来说是不利的,所以需要设置403,让用户不能直接读取文件夹下所有文件。 10 | 11 | * 在文件.htaccess中添加:ErrorDocument 403 /403.html 12 | * 修改httpd文件 13 | 14 | 将httpd文件中的: 15 | ``` 16 | 17 | Options Indexes FollowSymLinks #主要是这句中的Indexs 18 | AllowOverride None 19 | Order deny,allow 20 | Deny from all 21 | 22 | ``` 23 | 修改为: 24 | ``` 25 | 26 | Options FollowSymLinks 27 | AllowOverride All 28 | Order deny,allow 29 | Allow from all 30 | 31 | ``` 32 | 下面还有一处也是Options Indexes FollowSymLinks 33 | 改为 Options FollowSymLinks 34 | 35 | * 重启服务器 36 | 37 | ## 三、配置多站点 38 | 参考文章:http://baijunyao.com/article/9 39 | 操作流程:开启服务器**虚拟主机**配置;修改服务器hosts文件,将域名解析到服务器;修改虚拟主机配置。 40 | 41 | ### 第一步:修改httpd.conf 42 | * 命令行输入:`vim /etc/httpd/conf/httpd.conf`进入apache配置文件 43 | * 删除`NameVirtualHost *:80`前的注释 44 | 45 | ### 第二步:修改hosts文件 46 | * 输入ifconfig查看ip地址,inet addr 47 | * 输入vim /etc/hosts;添加ip地址域名。 48 | ``` 49 | 115.28.17.191 suvllian.com 50 | 115.28.17.191 suvllian.top 51 | ``` 52 | 53 | ### 第三步:修改httpd-vhosts.conf文件 54 | * 输入`vim /etc/httpd/conf.d/virtual.conf`,若没有则添加。 55 | * 编辑文件 56 | ``` 57 | 58 | DocumentRoot /var/www/html/V1 59 | ServerName suvllian.top 60 | 61 | 62 | DocumentRoot /var/www/html/ 63 | ServerName suvllian.com 64 | 65 | ``` 66 | 67 | ### 第四步:重启服务器即可 68 | 69 | ## 四、开启gzip压缩 70 | ### 第一步:修改服务器配置 71 | httpd.conf中打开deflate_Module和headers_Module模块,具体做法为将 如下两句前面的#去掉: 72 | ``` 73 | LoadModule deflate_module modules/mod_deflate.so 74 | LoadModule headers_module modules/mod_headers.so 75 | ``` 76 | 77 | ### 第二步:在httpd.conf文件底部加入如下代码配置需要压缩的文件 78 | ``` 79 | 80 | SetOutputFilter DEFLATE 81 | # Don’t compress images and other 82 | SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary 83 | SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary 84 | SetEnvIfNoCase Request_URI .(?:pdf|doc)$ no-gzip dont-vary 85 | AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css 86 | AddOutputFilterByType DEFLATE application/x-javascript 87 | 88 | ``` 89 | 90 | ## 五、开启缓存 91 | ### 第一步:在配置文件中开启: 92 | ``` 93 | LoadModule headers_module modules/mod_headers.so 94 | ``` 95 | ### 第二步:在.htaccess中添加: 96 | 包含这些后缀的资源都缓存33秒 97 | ``` 98 | 99 | Header set Cache-Control "max-age=33" 100 | 101 | ``` -------------------------------------------------------------------------------- /database/README.md: -------------------------------------------------------------------------------- 1 | ## 数据库知识 2 | 3 | ### 1. 基础SQL语句 4 | 5 | #### 1.1 内建函数 6 | - [日期函数](./basic/date.md) 7 | - [字符串函数](./basic/string.md) 8 | - [其他函数](./basic/other.md) 9 | #### 1.2 查 10 | - [基本查询](./basic/select-basic.md) 11 | - [查询场景](./basic/select-usage.md) 12 | 13 | ### 2. 进阶 14 | - [视图](./basic/view.md) 15 | - 存储过程 16 | - 游标 17 | - 触发器 18 | - 事务处理 19 | - 索引 20 | 21 | ### 3. 高级 22 | - [慢SQL优化](./advance/optimize-sql.md) -------------------------------------------------------------------------------- /database/advance/optimize-sql.md: -------------------------------------------------------------------------------- 1 | ## 慢SQL优化 2 | 3 | ### 1. 理论知识 4 | 通过建立索引优化,建立索引原则: 5 | 6 | * 最左前缀匹配原则 7 | * =和in可以乱序 8 | * 尽量选择区分度高的列作为索引 9 | * 索引列不能参与计算 10 | * 尽量的扩展索引,不要新建索引 11 | 12 | ### 2. 实践 13 | 14 | #### 2.1 反向查询不能使用索引 15 | 16 | not in/not exists都不是好习惯 17 | 18 | **bad case:** 19 | ``` sql 20 | select * from order where status!=0 and stauts!=1 21 | ``` 22 | 23 | **good case:** 24 | ``` sql 25 | select * from order where status in(2,3) 26 | ``` 27 | 28 | #### 2.2 前导模糊查询不能使用索引 29 | 30 | 非前导模糊查询可以使用索引 31 | 32 | **bad case:** 33 | ``` sql 34 | select * from order where desc like '%XX' 35 | ``` 36 | 37 | **good case:** 38 | ``` sql 39 | select * from order where desc like 'XX%' 40 | ``` 41 | 42 | #### 2.3 在属性上进行计算不能命中索引 43 | 44 | **bad case:** 45 | ``` sql 46 | select * from order where YEAR(date) < = '2020' 47 | ``` 48 | 49 | **good case:** 50 | ``` sql 51 | select * from order where date < = CURDATE() 52 | ``` 53 | 54 | #### 2.4 如果明确知道返回结果记录数量,使用limit语句能够提高效率 55 | 56 | **bad case:** 57 | ``` sql 58 | select * from user where login_name=? 59 | ``` 60 | 61 | **good case:** 62 | ``` sql 63 | select * from user where login_name=? limit 1 64 | ``` 65 | 66 | #### 2.5 把计算放到业务层而不是数据库层,除了节省数据的CPU,还有意想不到的查询缓存优化效果 67 | 68 | **bad case:** 69 | ``` sql 70 | select * from order where date < = CURDATE() 71 | ``` 72 | 73 | **good case:** 74 | ``` php 75 | $curDate = date('Y-m-d'); 76 | $res = mysql_query( 77 | 'select * from order where date < = $curDate' 78 | ); 79 | ``` 80 | 81 | #### 2.6 强制类型转换会全表扫描 82 | 83 | 84 | #### 2.7 插入大量数据时,考虑批量插入 85 | 86 | 87 | #### 2.8 不要有超过5个以上的表连接 88 | 89 | ### 3. 参考 90 | * [MySQL索引原理及慢查询优化](https://tech.meituan.com/2014/06/30/mysql-index.html) -------------------------------------------------------------------------------- /database/basic/date.md: -------------------------------------------------------------------------------- 1 | ## 时间函数 2 | 3 | ### 时间格式化 4 | 5 | #### string to_char(datetime date, string format) 6 | 7 | ``` sql 8 | to_char('2010-12-03 00:00:00', '测试yyyy-mm*dd') = '测试010-12*03' 9 | ``` -------------------------------------------------------------------------------- /database/basic/other.md: -------------------------------------------------------------------------------- 1 | ## 其他函数 2 | 3 | ### 1. 数据类型转换 4 | 5 | #### 1.1 cast(value, type) 6 | 7 | The type for the result can be one of the following values: 8 | 9 | * 二进制: BINARY 10 | * 字符型: CHAR 11 | * 日期: DATE 12 | * 时间: TIME 13 | * 日期时间型: DATETIME 14 | * 浮点数: DECIMAL 15 | * 整数: SIGNED 16 | * 无符号整数: UNSIGNED 17 | 18 | **Basic Usage** 19 | 20 | ``` sql 21 | SELECT CAST(prod_code AS INT) FROM product; 22 | ``` 23 | 24 | #### convert -------------------------------------------------------------------------------- /database/basic/select-basic.md: -------------------------------------------------------------------------------- 1 | ## SQL查询 2 | 3 | ### 1. if语句 4 | 5 | if语句用法如下,如果expr1成立返回value1,否则返回value2,可以用`case when`语句实现同样的需求。 6 | ``` sql 7 | if (expr1, value1, value2) 8 | ``` 9 | 10 | ``` sql 11 | select if (sex = 1, '男', '女') as sex from student 12 | ``` 13 | 14 | ### 2. 使用正则表达式 15 | 16 | ``` sql 17 | SELECT vend_name FROM vendors WHERE vend_name REGEXP '.' 18 | ``` 19 | 20 | ### 3. 联结查询 21 | 22 | 联结不是物理实体,它在实际的物理表中并不存在,存在于执行的查询当中。 23 | 24 | #### 3.1 内联结 25 | 内联结是给予两个表的等值联结,只有两个表中的记录满足条件才能返回结果。 26 | 27 | 两个表中都有vend_id字段,且字段值一样的记录才能返回。 28 | 29 | ``` sql 30 | SELECT vend_name, prod_name, prod_price FROM verdors INNER JOIN products ON vendors.vend_id = products.vend_id 31 | ``` 32 | 33 | 等价于 34 | 35 | ``` sql 36 | SELECT vend_name, prod_name, prod_price FROM verdors, products WHERE vendors.vend_id = products.vend_id 37 | ``` 38 | 39 | #### 3.2 自联结 40 | 41 | ``` sql 42 | select p1.prod_id, p1.prod_name from products as p1, products as p2 where p1.vend_id = p2.vend_id and p2.prod_id = 'DTNTR'; 43 | ``` 44 | 45 | 等价于自查询 46 | ```sql 47 | select prod_id, prod_name from products where vend_id = (select vend_id from products where prod_id = 'DTNTR'); 48 | ``` 49 | 50 | #### 3.3 外联结 51 | 许多联结将一个表中的行与另一个表中的行相关联,但有时候会需要包含没有关联行的那些行,这种联结方式叫外联结。 52 | 53 | 在使用`OUTER JOIN`时,必须使用`RIGHT`或`LEFT`关键字指定包括其所有行的表。RIGHT JOIN指的是OUTER JOIN右边的表的内容,LEFT JOIN指的是OUTER JOIN左边的表。 54 | 55 | 56 | ### 4. 组合查询 57 | UNION中的每个查询必须包含相同的列、表达式或聚集函数;UOION必须由两条或者两条以上的SELECT语句组成。 58 | 59 | ``` sql 60 | SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price > 5 61 | UNION 62 | SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001, 1002) 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /database/basic/select-usage.md: -------------------------------------------------------------------------------- 1 | ## SQL查询场景 2 | 3 | ### 1. 将数据库查询结果转换为显示自定义字段 4 | 5 | 在开发时经常会遇到数据中用单字符保存简单信息,如性别、状态等。如果需要在查询时展示对应的字段,比如性别:1表示男,0表示女。 6 | 7 | **Basic Usage** 8 | 9 | 将state字段进行转换:0、1、2分别转换为正常、删除、禁用 10 | 11 | ``` sql 12 | SELECT name 13 | ,age 14 | ,sex 15 | ,CASE WHEN state = 0 THEN '正常' 16 | WHEN state = 1 THEN '删除' 17 | ELSE '禁用' 18 | END AS state 19 | FROM student 20 | 21 | ``` 22 | 23 | 原来的结果: 24 | 25 | | orderId | state | 26 | | ------------- | ------------- | 27 | | 1 | 0 | 28 | | 2 | 1 | 29 | | 3 | 2 | 30 | 31 | 转换后的结果更容易理解 32 | 33 | | orderId | state | 34 | | ------------- | ------------- | 35 | | 1 | 正常 | 36 | | 2 | 删除 | 37 | | 3 | 禁用 | 38 | 39 | ### 2. 根据查询结果进行分组 40 | 41 | 在开发时,可能需要根据某个字段的值进行分组,但不是简单的`group by`,而是需要一些逻辑判断。 42 | 43 | 使用`case when`可以得到我们的结果,同时需要注意的是,如果把一次查询结果作为下一次查询的输入,第一次查询结果需要**重命名**。 44 | 45 | 例如在下面的查询结果中,我们需要统计`userid`为0和不为0的订单量。 46 | 47 | | userid | username | ordertype | 48 | | ------------- | ------------- | ------------- | 49 | | 0 | jack | 1 | 50 | | 0 | jack | 2 | 51 | | 2 | tom | 3 | 52 | 53 | ``` sql 54 | SELECT 55 | COUNT(*) AS 订单数量, 用户名称 56 | FROM (SELECT 57 | CASE WHEN userid = 0 THEN 'jack' ELSE '其他人' END AS 用户名称 58 | FROM cbulst.s_out_bound_order ) AS typeCount 59 | GROUP BY typeCount.用户名称 60 | ``` 61 | 62 | ### 3. 统计数量 63 | #### 3.1 计算总计数量 64 | 65 | 在日常数据分析过程中,我们查处按照某一维度区分的数据,但是还需要一个统计值作为参考。 66 | 67 | 将初步的查询结果作为临时表输出,在将临时表中所有数据进行累加输出一行与临时表中的数据进行联合查询。 68 | `需要注意的是,在进行联合查询时,两个表的字段类型一定要一致` 69 | 70 | 用例如下:需要查询每个班级男生和女生的数量,并且在最后给出男生和女生的总数 71 | 72 | | 班级 | malecount | femalecount | 73 | | ------------- | ------------- | ------------- | 74 | | 101 | 20 | 30 | 75 | | 201 | 30 | 40 | 76 | | 全校 | 50 | 70 | 77 | 78 | ``` sql 79 | DROP TABLE IF EXISTS tmp_student_count_table ; 80 | 81 | CREATE TABLE tmp_student_count_table AS 82 | SELECT classname AS 班级 83 | ,malecount AS 男生数量 84 | ,femalecount AS 女生数量; 85 | 86 | 87 | SELECT 班级 88 | ,男生数量 89 | ,女生数量 90 | FROM ( 91 | SELECT * 92 | FROM tmp_student_count_table 93 | UNION ALL 94 | SELECT '全校' AS 班级 95 | ,SUM(malecount) AS 男生数量 96 | ,SUM(femalecount) AS 女生数量 97 | FROM tmp_student_count_table 98 | ) t1 99 | ; 100 | ``` 101 | #### 3.2 统计一张表多个状态的数量 102 | 103 | ``` sql 104 | SELECT COUNT(*) AS total, 105 | COUNT(if(mdt_apply_type= '1', 1, NULL)) AS single_diseases_num, 106 | COUNT(if(mdt_apply_type= '2', 1, NULL)) AS multidisciplinary_num 107 | FROM t_mdt_apply_list 108 | WHERE audit_opinion= '3' 109 | ``` 110 | ### 4. 处理某一字段重复的记录 111 | 112 | #### 4.1 查询表中某一字段重复的记录 113 | 114 | ``` sql 115 | SELECT * 116 | FROM people 117 | WHERE peopleId IN (SELECT peopleId FROM people GROUP BY peopleId HAVING COUNT(peopleId) > 1) 118 | ``` 119 | 120 | #### 4.2 删除表中某一字段重复的记录,保留最新记录 121 | 122 | ``` sql 123 | DELETE FROM people 124 | WHERE peopleId IN ( 125 | SELECT peopleId 126 | FROM ( 127 | SELECT peopleId 128 | FROM people 129 | GROUP BY peopleId HAVING COUNT(peopleId) >1 130 | ) repeat_people 131 | ) 132 | AND id NOT IN ( 133 | SELECT id 134 | FROM ( 135 | SELECT max(id) 136 | FROM people 137 | GROUP BY peopleId HAVING COUNT(peopleId) >1 138 | ) max_id 139 | ); 140 | ``` 141 | 142 | #### 4.3 更新表中某一字段重复的记录,只保留最新记录 143 | ``` sql 144 | UPDATE people SET value = 1 145 | WHERE peopleId IN ( 146 | SELECT peopleId 147 | FROM ( 148 | SELECT peopleId 149 | FROM people 150 | GROUP BY peopleId HAVING COUNT(peopleId) >1 151 | ) repeat_people 152 | ) 153 | AND id NOT IN ( 154 | SELECT id 155 | FROM ( 156 | SELECT max(id) 157 | FROM people 158 | GROUP BY peopleId HAVING COUNT(peopleId) >1 159 | ) max_id 160 | ); 161 | ``` 162 | 163 | **需要特别注意,在更新表时不能通过自查询再更新,需要通过中间表操作。** 164 | 165 | 参考: 166 | * [You can't specify target table for update in FROM clause解决方法](https://blog.csdn.net/fdipzone/article/details/52695371) 167 | * [MYSQL删除重复数据](https://juejin.im/post/5ab4df3151882555635e4363#heading-0) 168 | 169 | 170 | ### 5. 添加虚拟字段 171 | 172 | ``` sql 173 | SELECT '品牌商' AS user_type 174 | ,name 175 | FROM user_info; 176 | ``` 177 | 178 | ### 6. 将SQL查询结果行记录转换为列属性 179 | 180 | [参考: sql查询结果的行记录转换为列属性](https://blog.csdn.net/Agly_Clarlie/article/details/87978445) 181 | 182 | 需要把查询结果进行转换,按周访问次数进行Group,用户类型作为列名 183 | 184 | | week_visit_time | visit_count | user_type | 185 | | ------------- | ------------- | ------------- | 186 | | 1 | 20 | supplier | 187 | | 1 | 30 | brandOwner 188 | | 2 | 60 | supplier | | 189 | | 2 | 50 | brandOwner | 190 | 191 | 使用`CASE THEN`语句进行转换 192 | 193 | ``` sql 194 | SELECT week_visit_time 195 | ,SUM( 196 | CASE WHEN user_type = 'brandOwner' THEN visit_count 197 | ELSE 0 198 | END 199 | ) AS brandOwner 200 | ,SUM(CASE WHEN user_type = 'supplier' THEN visit_count ELSE 0 END) AS supplier 201 | FROM tmp_merchant_type_visit_table 202 | GROUP BY week_visit_time 203 | ``` 204 | 205 | 转换结果 206 | 207 | | week_visit_time | supplier | brandOwner | 208 | | ------------- | ------------- | ------------- | 209 | | 1 | 20 | 30 | 210 | | 2 | 60 | 50 | 211 | 212 | 213 | ### 7. 分组查询。根据一个或多个字段进行分组,并只取每一组符合特定条件的记录作为结果 214 | 215 | [参考:MySQL组内排序问题:分组查询每组的前n条记录](https://www.jianshu.com/p/717c4bdad462) 216 | 217 | 对于`pv_table`数据,需要查询每个URL访问次数最大的记录 218 | 219 | | id | url | visit_count | date | 220 | | ------------- | ------------- | ------------- | ------------- | 221 | | 3 | suvllian.com | 20 | 20200301 | 222 | | 5 | suvllian.com | 30 | 20200301 | 223 | | 7 | suvllian.com | 40 | 20200301 | 224 | | 9 | suvllian.net | 30 | 20200301 | 225 | | 12 | suvllian.net | 30 | 20200301 | 226 | | 16 | suvllian.net | 40 | 20200301 | 227 | 228 | 使用临时表关联查询,如果直接使用MAX查询,除了MAX函数中的字段,其他字段值是随机的,不是max记录的值,详见参考文章。 229 | 230 | ``` sql 231 | SELECT * 232 | FROM pv_table 233 | WHERE id IN( SELECT pv_table.id FROM pv_table,( SELECT url, MAX(pv) AS maxPv FROM `pv_table` GROUP BY url) max_pv WHERE pv_table.url = max_pv.url AND pv_table.pv = max_pv.maxPv) 234 | ``` 235 | 236 | ### 8. 一次更新多行多字段 237 | 238 | 将满足条件的记录对应字段更新成相同的值 239 | ``` sql 240 | UPDATE mytable SET myfield = 'value' WHERE other_field = 'other_value'; 241 | ``` 242 | 243 | 将满足条件的记录的字段更新成不同的值 244 | ``` sql 245 | UPDATE mytable 246 | SET myfield = CASE other_field 247 | WHEN 1 THEN 'value' 248 | WHEN 2 THEN 'value' 249 | WHEN 3 THEN 'value' 250 | END 251 | WHERE id IN (1,2,3) 252 | ``` 253 | 254 | 参考:[如何在数据库中一次更新多行多字段](http://www.renniaofei.com/code/update-multiple-rows-with-different-values-and-a-single-sql-query.html) 255 | 256 | ### 9. A/B表为1对多关系,联合查询B表只提取第一条与A记录关联的记录 257 | ``` sql 258 | SELECT username 259 | FROM ( 260 | SELECT t1.username 261 | ,row_number() OVER (PARTITION BY t1.user_id) AS group_idx 262 | FROM t1 263 | ,t2 264 | WHERE t2.user_address_id = 1 265 | AND t1.user_id = t2.user_id 266 | ) s 267 | WHERE s.group_idx = 1 268 | ; 269 | ``` 270 | 271 | ### 10. 根据某个字段分组,并将分组中多条记录的某个字段输出 272 | 273 | 通过group_concat()函数可以将group by产生的同一个分组中的值连接起来,返回一个字符串结果。 274 | 275 | 276 | ``` sql 277 | SELECT user_id, GROUP_CONCAT(phone SEPARATOR ',') phone FROM testuser GROUP BY user_id; 278 | ``` 279 | 280 | ### 11. SQL查询结果行转成列展示 281 | 282 | 使用pivot函数转换。 283 | 284 | 原本一个用户会查出七条记录,现将星期几的字段转换成列,可以看每个用户在一周中每天的收入,进行对比。 285 | 286 | ``` sql 287 | select * from DailyIncome 288 | pivot 289 | ( 290 | sum (IncomeAmount) 291 | for IncomeDay in ([MON],[TUE],[WED],[THU],[FRI],[SAT],[SUN]) 292 | ) as AvgIncomePerDay 293 | ``` -------------------------------------------------------------------------------- /database/basic/string.md: -------------------------------------------------------------------------------- 1 | ## 字符串函数 2 | 3 | ### 1. 截断字符串 4 | 5 | #### 1.1 SUBSTRING_INDEX 6 | 7 | #### 1.2 SUBSTR 8 | 9 | ### 2. 获取字符串位置 10 | 11 | #### 2.1 LOCATE(substr,str) 12 | 13 | #### 2.2 POSITION(substr IN str) 14 | 15 | ### 3. 拼接字符串 16 | 17 | #### 3.1 CONCAT() 18 | 19 | ``` sql 20 | SELECT CONCAT(userName, ': ', phoneNumber) AS userInfo FROM users; 21 | ``` -------------------------------------------------------------------------------- /database/basic/view.md: -------------------------------------------------------------------------------- 1 | ## 视图 2 | 视图是虚拟的表,只包含使用时动态检索数据的查询。 3 | 4 | 使用视图的优点: 5 | 6 | * 复用sql。 7 | * 简化复杂的sql操作。 8 | * 使用表的组成部分而不是整个表。 9 | * 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。 10 | * 更改数据格式和表示。 11 | 12 | 视图的规则和限制: 13 | 14 | * 视图命名必须唯一。 15 | * 视图不能索引,不能有关联的触发器或者默认值。 16 | * 视图可以和表一起使用。 17 | 18 | ``` sql 19 | create view productcustomers as 20 | select cust_name, cust_contact, prod_id from customers, orders, orderitems 21 | where customers.cust_id = orders.cust_id and orderitems.order_num = orders.order_name 22 | ``` -------------------------------------------------------------------------------- /machine-learing/README.md: -------------------------------------------------------------------------------- 1 | ## Machine Learning 2 | 3 | - [简介](./introduction.md) -------------------------------------------------------------------------------- /machine-learing/introduction.md: -------------------------------------------------------------------------------- 1 | ### 什么是机器学习? 2 | 3 | 利用计算机从历史数据中找出规律,并把这些规律用到对未来不确定性场景的决策。 4 | 5 | ### 机器学习和数据分析的区别? 6 | 7 | * [Data mining vs Machine learning – 10 Best Thing You Need To Know](https://www.educba.com/data-mining-vs-machine-learning/) -------------------------------------------------------------------------------- /network-of-computer/images/dns-lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/network-of-computer/images/dns-lb.png -------------------------------------------------------------------------------- /network-of-computer/images/ip-lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/network-of-computer/images/ip-lb.png -------------------------------------------------------------------------------- /network-of-computer/images/mac-lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/network-of-computer/images/mac-lb.png -------------------------------------------------------------------------------- /network-of-computer/load-balance.md: -------------------------------------------------------------------------------- 1 | ## 负载均衡 2 | 3 | ### 介绍 4 | #### 场景 5 | * 并发请求转发给多个节点处理 6 | * 单个繁重任务转发给多个节点处理 7 | 8 | #### 目的 9 | 通过调度集群,达到最佳化资源使用,最大化吞吐率,最小化响应时间,避免单点过载 10 | 11 | ### 负载均衡分类 12 | 根绝OSI七层模型分类。 13 | 14 | #### 数据链路层负载均衡 15 | 数据分发时,不修改ip地址,只修改目标mac地址。 16 | 17 | 真实物理服务器集群所有机器VIP和负载均衡服务器VIP地址一致,不修改数据包的源地址和目标地址即可进行数据分发。 18 | 19 | 不需要经过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。 20 | 21 | ![](./images/mac-lb.png) 22 | 23 | **优点** 24 | * 负载均衡服务器只负责转发请求,响应直接返回给客户端 25 | 26 | **缺点** 27 | * 配置负载 28 | 29 | #### 网络层负载均衡 30 | 用户请求数据包,到达负载均衡服务器后,负载均衡服务器根据负载均衡算法得到一台真实服务器地址,然后将请求目的地址修改为真实服务器ip地址,不需要经过用户进程处理。 31 | 32 | 真实服务器处理完成后,响应数据包回到负载均衡服务器,负载均衡服务器,再将数据包源地址修改为自身的ip地址,发送给用户浏览器。 33 | 34 | ![](./images/ip-lb.png) 35 | 36 | **缺点** 37 | * 流量请求进出都要经过负载均衡服务器 38 | 39 | #### 传输层负载均衡 40 | 基于IP和端口号做负载均衡,对流量进行NAT处理 41 | 案例:LVS、F5 42 | 43 | #### 应用层负载均衡 44 | 在传输层负载均衡的基础上,考虑应用层的特征,例如HTTP请求的URL、浏览器类别、语言等特征,进行负载均衡处理。 45 | 46 | 47 | ### 负载均衡方案 48 | #### 基于DNS的负载均衡 49 | 利用域名解析实现负载均衡,在DNS服务器,配置多个A记录,这些A记录对应的服务器构成集群 50 | 51 | ![dns load balance](./images/dns-lb.png) 52 | 53 | **优点** 54 | * 简单易用 55 | * 提高性能:支持基于地址的域名解析,解析到距离用户最近的服务器地址 56 | 57 | **缺点** 58 | * 可用性差:DNS多级缓存 59 | * 扩展性差 60 | * 维护性差:也不能反映服务器的当前运行状态;支持的算法少;不能区分服务器的差异 61 | 62 | #### 基于硬件的负载均衡 63 | 64 | **问题** 65 | * 硬件成本高 66 | 67 | #### 基于软件的负载均衡 68 | 69 | ### 负载均衡算法 70 | #### 轮询(Round Robin) 71 | 轮流转发请求 72 | 具体实现方式 73 | * 顺序轮询 74 | * 随机轮询 75 | * 权重轮询 76 | 77 | #### 负载度策略 78 | 评估后端服务器的负载压力,转发流量 79 | 80 | #### 响应策略 81 | 转发到响应最快的服务器 82 | 83 | #### 哈希策略 84 | 对请求中的某个信息进行哈希计算,相同的请求就被转发到同一个服务器上 85 | 优点 86 | • 有利于处理缓存 87 | 缺点 88 | • 单点故障时,会导致客户端无法正常使用 89 | 90 | ### 参考 91 | * [一篇读懂分布式架构下的负载均衡技术:分类、原理、算法、常见方案等](https://www.cnblogs.com/imstudy/p/10790228.html) 92 | * [大型网站架构系列:负载均衡详解](https://www.jianshu.com/p/215b5575107c) 93 | * [LVS原理篇:LVS简介、结构、四种模式、十种算法](https://blog.csdn.net/lcl_xiaowugui/article/details/81701949) -------------------------------------------------------------------------------- /programming-concept/design-patterns/README.md: -------------------------------------------------------------------------------- 1 | ## 了解设计模式 2 | 3 | ### 什么是设计模式? 4 | 每一个模式描述了一个在我们周围不断重复的问题,以及该问题解决方案的核心。 5 | 6 | ### 如何选择设计模式? 7 | 8 | 9 | ### 如何使用设计模式? -------------------------------------------------------------------------------- /programming-concept/design-patterns/behavioral-patterns/chain-of-responsibility.md: -------------------------------------------------------------------------------- 1 | ## 职责链模式 2 | 3 | ### 使用场景 4 | 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 5 | 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 6 | 3、可动态指定一组对象处理请求。 7 | 8 | ### 优缺点 9 | * 优点 10 | * 降低耦合度。它将请求的发送者和接收者解耦。 11 | * 简化了对象。使得对象不需要知道链的结构。 12 | * 增强给对象指派职责的灵活性 13 | 14 | * 缺点 15 | * 不能保证请求一定被接收。 16 | * 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 17 | 18 | ### 示例 19 | * [职责链模式的PHP实现](https://github.com/suvllian/learning/tree/master/design-patterns/behavioral-patterns/chain-of-responsibility-pattern) 20 | 21 | ### 文档 -------------------------------------------------------------------------------- /programming-concept/design-patterns/creational-patterns/README.md: -------------------------------------------------------------------------------- 1 | ## 创建型设计模式 2 | 创建型模式抽象了实例化过程。 3 | 4 | ### 总结 5 | * [工厂模式](./factory-method.md) 6 | * [抽象工厂模式](./abstract-factory.md) 7 | * [生成器模式](./builder.md) 8 | * [原型模式](./prototype.md) 9 | * [单例模式](./singleton.md) 10 | 11 | ### 文档 12 | * [菜鸟笔记—设计模式](http://www.runoob.com/design-pattern/design-pattern-tutorial.html) 13 | 14 | ### 文章 15 | * [工厂模式——看这一篇就够了](https://juejin.im/entry/58f5e080b123db2fa2b3c4c6) -------------------------------------------------------------------------------- /programming-concept/design-patterns/creational-patterns/abstract-factory.md: -------------------------------------------------------------------------------- 1 | ## 抽象工厂模式 2 | 3 | ### 使用场景 4 | 5 | 1. 客户端不需要知道它所创建的对象的类。 6 | 2. 客户端可以通过子类来指定创建对应的对象,每个工厂都可以产生多种不同类型的对象。 7 | 8 | ### 优缺点 9 | * 优点 10 | * 相比于简单工厂模式,不需要改动原有代码。 11 | 12 | * 缺点 13 | * 扩展复杂,需要增加抽象的Creator代码,也需要增加具体的实现代码。 14 | 15 | ### 示例 16 | * [工厂模式的PHP实现](https://github.com/suvllian/learning/tree/master/design-patterns/creational-patterns/factory-method) 17 | 18 | ### 文档 -------------------------------------------------------------------------------- /programming-concept/design-patterns/creational-patterns/builder.md: -------------------------------------------------------------------------------- 1 | ## 生成器模式 2 | 3 | ### 使用场景 4 | 5 | 1. 一些基本部件不会变,而其组合经常变化的时候。 6 | 7 | ### 优缺点 8 | * 优点 9 | * 建造者独立,易扩展。 10 | 11 | * 缺点 12 | * 产品必须有共同点,范围有限制。 13 | * 如果内部变化复杂,会有很多的建造类。 14 | 15 | ### 示例 16 | 17 | ### 文档 18 | * [菜鸟教程-生成器模式](https://www.runoob.com/design-pattern/builder-pattern.html) -------------------------------------------------------------------------------- /programming-concept/design-patterns/creational-patterns/factory-method.md: -------------------------------------------------------------------------------- 1 | ## 工厂模式 2 | 3 | ### 使用场景 4 | 5 | 1. 需要创建的对象较少。 6 | 2. consumer不关心对象的创建过程。 7 | 8 | ### 优缺点 9 | * 优点 10 | * consumer不需要知道对象的创建过程。 11 | * 扩展性好。 12 | 13 | * 缺点 14 | * 违反**开放-封闭原则**,每次需要添加新功能时,都需要修改代码,增加系统复杂性。 15 | 16 | ### 示例 17 | 18 | ### 文档 -------------------------------------------------------------------------------- /programming-concept/design-patterns/creational-patterns/prototype.md: -------------------------------------------------------------------------------- 1 | ## 原型模式 2 | 3 | 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 4 | 5 | ### 使用场景 6 | 7 | 8 | ### 优缺点 9 | * 优点 10 | * 性能提高 11 | * 逃避构造函数的约束 12 | 13 | * 缺点 14 | * 已有的类不一定支持clone 15 | * 必须实现Cloneable接口 16 | 17 | ### 示例 18 | * [原型模式的PHP实现](https://github.com/suvllian/learning/tree/master/design-patterns/creational-patterns/prototype) 19 | 20 | ### 文档 -------------------------------------------------------------------------------- /programming-concept/design-patterns/creational-patterns/singleton.md: -------------------------------------------------------------------------------- 1 | ## 单例模式 2 | 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 3 | 4 | ### 使用场景 5 | 防止一个全局使用的类频繁地创建与销毁。 6 | 7 | ### 优缺点 8 | * 优点 9 | * 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例 10 | * 避免对资源的多重占用(比如写文件操作) 11 | 12 | * 缺点 13 | * 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。 14 | 15 | ### 示例 16 | * [单例模式的Javascript实现](https://github.com/suvllian/learning/tree/master/design-patterns/creational-patterns/singleton) 17 | 18 | ### 文档 -------------------------------------------------------------------------------- /programming-concept/functional-programming/README.md: -------------------------------------------------------------------------------- 1 | ## 函数式编程 2 | 3 | * [面向切面编程](./aop.md) -------------------------------------------------------------------------------- /programming-concept/functional-programming/aop.md: -------------------------------------------------------------------------------- 1 | ## 面向切面编程 2 | 3 | 用过express、koa或者redux的同学应该都知道它们都有**“中间件”**(前端意义上的中间件,不是指平台与应用之间的通用服务)这样一个概念,在redux中我们可以通过中间件的方式使用`redux-thunk`和`loger`的功能,在koa中我们可以通过中间件对请求上下文`context`进行处理。 4 | 5 | 通过中间件,我们可以在一些方法执行前添加统一的处理(如登录校验,打印操作日志等),中间件的设计思想都是面向切面编程的思想,把一些跟业务无关的逻辑进行抽离,在需要使用的场景中再切入,降低耦合度,提高可重用性,而且使代码更简洁。 6 | 7 | 下面我们通过源码分析redux和koa是如何实现中间件的,最后详细介绍**面向切面编程**解决的一些问题。 8 | 9 | ### 一、redux中间件 10 | 11 | 我们先来看下redux中间件的用法。redux暴露了`applyMiddleware`方法,接受一个函数数组作为参数,函数的返回值作为第二参数传入`createStore`。 12 | 13 | ``` javascript 14 | import { createStore, applyMiddleware } from 'redux' 15 | import thunk from 'redux-thunk' 16 | import { createLogger } from 'redux-logger' 17 | import reducer from './reducers' 18 | 19 | const middleware = [ thunk ] 20 | if (process.env.NODE_ENV !== 'production') { 21 | middleware.push(createLogger()) 22 | } 23 | 24 | const store = createStore( 25 | reducer, 26 | applyMiddleware(...middleware) 27 | ) 28 | ``` 29 | 30 | 接下来看redux中间件是怎么实现的,下面是applyMiddleware的源码,其中对dispatch方法进行了compose处理,处理后的dispatch在每次调用时都会链式调用中间件函数。 31 | 32 | ``` javascript 33 | export default function applyMiddleware(...middlewares) { 34 | return createStore => (...args) => { 35 | const store = createStore(...args) 36 | let dispatch = () => { 37 | throw new Error( 38 | 'Dispatching while constructing your middleware is not allowed. ' + 39 | 'Other middleware would not be applied to this dispatch.' 40 | ) 41 | } 42 | 43 | const middlewareAPI = { 44 | getState: store.getState, 45 | dispatch: (...args) => dispatch(...args) 46 | } 47 | const chain = middlewares.map(middleware => middleware(middlewareAPI)) 48 | dispatch = compose(...chain)(store.dispatch) 49 | 50 | return { 51 | ...store, 52 | dispatch 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | compose的源码如下,其主要作用是依次调用函数数组中的中间件函数,并将前一个函数的返回结果作为后一个函数的入参,从而实现了在调用`dispath`时调用其他方法的需求。 59 | 60 | ``` javascript 61 | export default function compose(...funcs) { 62 | if (funcs.length === 0) { 63 | return arg => arg 64 | } 65 | 66 | if (funcs.length === 1) { 67 | return funcs[0] 68 | } 69 | 70 | return funcs.reduce((a, b) => (...args) => a(b(...args))) 71 | } 72 | ``` 73 | 74 | ### 二、koa中间件 75 | 76 | 同样的,我们来看下koa中间件的用法。首先实例化一个`Koa`对象,然后通过对象中的`use`方法添加中间件函数,最后调用`listen`方法启动node服务器 77 | 78 | ``` javascript 79 | const app = new Koa(); 80 | const logger = async function(ctx, next) { 81 | let res = ctx.res; 82 | 83 | // 拦截操作请求 request 84 | console.log(`<-- ${ctx.method} ${ctx.url}`); 85 | 86 | await next(); 87 | 88 | // 拦截操作响应 request 89 | res.on('finish', () => { 90 | console.log(`--> ${ctx.method} ${ctx.url}`); 91 | }); 92 | }; 93 | 94 | app.use(logger) 95 | 96 | app.use((ctx, next) => { 97 | ctx.cookies.set('name', 'jon'); 98 | ctx.status = 204; 99 | 100 | await next(); 101 | }); 102 | 103 | app.use(async(ctx, next) => { 104 | ctx.body = 'hello world'; 105 | }) 106 | 107 | const server = app.listen(); 108 | ``` 109 | 110 | 我们来看下koa中间件的实现,我们通过实例的`use`方法添加中间件,在调用实例的`listen`方法后,在`callback`中会对中间件进行`compose`处理,最后在`handleRequest`中调用处理过的中间件。 111 | 112 | ``` javascript 113 | listen(...args) { 114 | const server = http.createServer(this.callback()); 115 | return server.listen(...args); 116 | } 117 | 118 | use(fn) { 119 | if (typeof fn !== 'function') throw new TypeError('middleware must be a function!'); 120 | if (isGeneratorFunction(fn)) { 121 | fn = convert(fn); 122 | } 123 | this.middleware.push(fn); 124 | return this; 125 | } 126 | 127 | callback() { 128 | const fn = compose(this.middleware); 129 | 130 | if (!this.listenerCount('error')) this.on('error', this.onerror); 131 | 132 | const handleRequest = (req, res) => { 133 | const ctx = this.createContext(req, res); 134 | return this.handleRequest(ctx, fn); 135 | }; 136 | 137 | return handleRequest; 138 | } 139 | 140 | handleRequest(ctx, fnMiddleware) { 141 | const res = ctx.res; 142 | res.statusCode = 404; 143 | const onerror = err => ctx.onerror(err); 144 | const handleResponse = () => respond(ctx); 145 | onFinished(res, onerror); 146 | return fnMiddleware(ctx).then(handleResponse).catch(onerror); 147 | } 148 | ``` 149 | 150 | koa中的`compose`方法和redux中的`compose`方法原理是一样的,都是用洋葱模型的方式依次调用中间件函数,但是`koa-compose`是通过Promise的方式实现的。我们来看下koa中`compose`方法的实现。 151 | 152 | ``` javascript 153 | function compose (middleware) { 154 | if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!') 155 | for (const fn of middleware) { 156 | if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') 157 | } 158 | 159 | return function (context, next) { 160 | // last called middleware # 161 | let index = -1 162 | return dispatch(0) 163 | function dispatch (i) { 164 | if (i <= index) return Promise.reject(new Error('next() called multiple times')) 165 | index = i 166 | let fn = middleware[i] 167 | if (i === middleware.length) fn = next 168 | if (!fn) return Promise.resolve() 169 | try { 170 | return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); 171 | } catch (err) { 172 | return Promise.reject(err) 173 | } 174 | } 175 | } 176 | } 177 | ``` 178 | 179 | ### 三、面向切面编程 180 | 181 | 通过对redux和koa中间件实现的简单分析,大家应该对面向切面编程有了一个简单的理解,下面一部分内容就是详细介绍面向切面编程,以及如果不用面向切面编程的方式,我们还能用什么方式来满足需求,以及这些方式有什么问题。 182 | 183 | > 面向切面编程(Aspect Oriented Programming,也叫面向方面编程)是一种非侵入式扩充对象、方法和函数行为的技术。 184 | 185 | 其核心思想是通过对方法的拦截,在预编译或运行时进行动态代理,实现在方法被调用时可以以对业务代码无侵入的方式添加功能。 186 | 187 | 比如像日志、事务等这些功能,和核心业务逻辑没有直接关联,通过切面的方式和核心业务逻辑进行剥离,让业务同学只需关心业务逻辑的开发,当需要用到这些功能的时候就把切面插拔到业务流程的某些点上,做到了切面和业务的分离。 188 | 189 | 我们举个例子,来帮助理解面向切面编程的使用场景。 190 | 191 | 农场的水果包装流水线一开始只有**采摘-清洗-贴标签**三步。 192 | 193 | ![](./images/aop1.png) 194 | 195 | 为了提高销量,想加上两道工序**分类**和**包装**但又不能干扰原有的流程,同时如果没增加收益可以随时撤销新增工序。 196 | 197 | ![](./images/aop2.png) 198 | 199 | 最后在流水线的中的空隙插上两个工人去处理,形成**采摘-分类-清洗-包装-贴标签**的新流程,而且工人可以随时撤回。 200 | 201 | 回到AOP的作用这个问题。 202 | 203 | > AOP就是在现有代码程序中,在不影响原有功能的基础上,在程序生命周期或者横向流程中加入/减去一个或多个功能。 204 | 205 | 我们通过一个实际问题来分析AOP的好处。 206 | 207 | 现在有一个类`Foo`,类中包含了方法`doSomething`,我想在每次方法`doSomething`执行前和执行后打印一段日志,想实现的效果如下: 208 | 209 | ``` javascript 210 | class Foo { 211 | doSomething() { 212 | let result; 213 | 214 | // dosomething 215 | 216 | return result 217 | } 218 | } 219 | 220 | const foo = new Foo() 221 | foo.doSomething(1, 2) 222 | 223 | // before doSomething 224 | // after doSomething, result: result 225 | ``` 226 | 227 | #### 3.1 修改源代码 228 | 229 | 最简单粗暴的方法,就是重写`doSomething`方法 230 | 231 | ``` javascript 232 | class Foo { 233 | doSomething() { 234 | console.log(`before doSomething`) 235 | let result; 236 | 237 | // dosomething 238 | 239 | console.log(`after doSomething, result: ${result}`) 240 | return result 241 | } 242 | } 243 | 244 | const foo = new Foo() 245 | foo.doSomething(1, 2) 246 | 247 | // before doSomething 248 | // after doSomething, result: result 249 | ``` 250 | 251 | 这样的坏处很明显,需要改动原有的代码,是侵入性最强的一种做法。如果代码逻辑复杂,修改代码也会变得困难。如果想用类似的方法分析其他方法,同样需要修改其他方法的源代码。 252 | 253 | #### 3.2 继承 254 | ``` javascript 255 | class Bar extends Foo { 256 | doSomething () { 257 | console.log(`before doSomething`) 258 | 259 | const result = super.doSomething.apply(this, arguments) 260 | 261 | console.log(`after doSomething, result: ${result}`) 262 | 263 | return result 264 | } 265 | } 266 | 267 | const bar = new Bar() 268 | bar.doSomething(1, 2) 269 | 270 | // before doSomething 271 | // after doSomething, result: result 272 | ``` 273 | 274 | 用继承的方式避免了修改父类的源代码,但是每个使用`new Foo`的地方都要改成`new Bar`。 275 | 276 | #### 3.3 重写类方法 277 | 278 | ``` javascript 279 | class Foo { 280 | doSomething() { 281 | let result; 282 | 283 | // dosomething 284 | 285 | return result 286 | } 287 | } 288 | 289 | const _doSomething = Foo.prototype.doSomething 290 | Foo.prototype.doSomething = function() { 291 | if (_doSomething) { 292 | console.log(`before doSomething`) 293 | 294 | const result = _doSomething.apply(this, arguments) 295 | 296 | console.log(`after doSomething, result: ${result}`) 297 | 298 | return result 299 | } 300 | } 301 | 302 | const foo = new Foo() 303 | foo.doSomething(1, 2) 304 | 305 | // before doSomething 306 | // after doSomething, result: result 307 | ``` 308 | 309 | 这样就多了中间变量`_doSomething`,管理需要成本。 310 | 311 | #### 3.4 职责链模式 312 | 313 | 我们可以通过在Function的原型上添加before和after函数来满足我们的需求。 314 | 315 | ``` javascript 316 | Function.prototype.before = function (fn) { 317 | var self = this; 318 | return function () { 319 | fn.apply(this, arguments); 320 | self.apply(this, arguments); 321 | } 322 | } 323 | Function.prototype.after = function (fn) { 324 | var self = this; 325 | return function () { 326 | const result = self.apply(this, arguments); 327 | fn.call(this, result); 328 | } 329 | } 330 | 331 | class Foo { 332 | doSomething() { 333 | let result; 334 | 335 | // dosomething 336 | result = 1 337 | 338 | return result 339 | } 340 | } 341 | 342 | const foo = new Foo() 343 | foo.doSomething.after((result) => { 344 | console.log(`after doSomething, result: ${result}`) 345 | }).before(() => { 346 | console.log('before doSomething') 347 | })() 348 | 349 | // before doSomething 350 | // after doSomething, result: 1 351 | ``` 352 | 353 | 从代码上已经实现了完全解耦,也没有中间变量,但是却有一长串的链式调用,如果处理不当,代码可读性及可维护性较差。 354 | 355 | #### 3.5 中间件 356 | 357 | 我们可以借用中间件思想来分解前端业务逻辑,通过next方法层层传递给下一个业务。首先要有个管理中间件的对象,我们先创建一个名为Middleware的对象: 358 | 359 | ``` javascript 360 | function Middleware(){ 361 | this.cache = []; 362 | } 363 | Middleware.prototype.use = function (fn) { 364 | if (typeof fn !== 'function') { 365 | throw 'middleware must be a function'; 366 | } 367 | this.cache.push(fn); 368 | return this; 369 | } 370 | 371 | Middleware.prototype.next = function (fn) { 372 | if (this.middlewares && this.middlewares.length > 0) { 373 | var ware = this.middlewares.shift(); 374 | ware.call(this, this.next.bind(this)); 375 | } 376 | } 377 | Middleware.prototype.handleRequest = function () { 378 | this.middlewares = this.cache.map(function (fn) { 379 | return fn; 380 | }); 381 | this.next(); 382 | } 383 | var middleware = new Middleware(); 384 | middleware.use(function (next) { 385 | console.log(1); next(); console.log('1结束'); 386 | }); 387 | middleware.use(function (next) { 388 | console.log(2); next(); console.log('2结束'); 389 | }); 390 | middleware.use(function (next) { 391 | console.log(3); console.log('3结束'); 392 | }); 393 | middleware.use(function (next) { 394 | console.log(4); next(); console.log('4结束'); 395 | }); 396 | middleware.handleRequest(); 397 | 398 | // 输出结果: 399 | // 1 400 | // 2 401 | // 3 402 | // 3结束 403 | // 2结束 404 | // 1结束 405 | ``` 406 | 407 | ### 四、总结 408 | 409 | 本文一开始简单分析了redux及koa中间件的实现方式,然后介绍了面向切面编程,通过一个例子介绍不同的方式实现对方法的扩充,最后我们能明显的体会到面向切面编程的方式能降低代码耦合度,提高可重用性,而且使代码更简洁。 410 | 411 | ### References 412 | * [koa-compose源代码](https://github.com/koajs/compose/blob/master/index.js) 413 | * [redux中compose的实现](https://github.com/reduxjs/redux/blob/master/src/compose.js) 414 | * [Koa.js的AOP设计](https://chenshenhai.github.io/koajs-design-note/note/chapter02/01.html) 415 | * [编写可维护代码之“中间件模式”](https://zhuanlan.zhihu.com/p/26063036) 416 | * [使用JavaScript拦截和跟踪浏览器中的HTTP请求](https://www.ibm.com/developerworks/cn/web/wa-lo-jshttp/index.html) -------------------------------------------------------------------------------- /programming-concept/functional-programming/images/aop1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/programming-concept/functional-programming/images/aop1.png -------------------------------------------------------------------------------- /programming-concept/functional-programming/images/aop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/programming-concept/functional-programming/images/aop2.png -------------------------------------------------------------------------------- /software-engineering/README.md: -------------------------------------------------------------------------------- 1 | - 项目开发 2 | - [敏捷软件开发](./software-engineering/scrum.md) 3 | - [如何写好一份技术评审方案](./software-engineering/how-to-write-a-technoloy-plan.md) 4 | - 团队合作 5 | - [编码规范](./software-engineering/code-style-standard.md) 6 | - [git commit规范](./software-engineering/git-commit-standard.md) -------------------------------------------------------------------------------- /software-engineering/code-style-standard.md: -------------------------------------------------------------------------------- 1 | ## 编码规范 -------------------------------------------------------------------------------- /software-engineering/git-commit-standard.md: -------------------------------------------------------------------------------- 1 | ## 团队Git Commit规范 2 | 3 | ### 个人总结 4 | #### 目的 5 | 6 | #### 做法 7 | * feat: 新特性 8 | * fix: 修改问题 9 | * refactor: 代码重构 10 | * docs: 文档修改 11 | * style: 代码格式修改, 注意不是 css 修改 12 | * test: 测试用例修改 13 | * chore: 其他修改, 比如构建流程, 依赖管理 14 | 15 | #### 示例 16 | ``` 17 | git commit -m'feat: add new feature' 18 | ``` 19 | 20 | ### 参考 21 | * [优雅的提交你的 Git Commit Message](https://zhuanlan.zhihu.com/p/34223150) 22 | * [知乎讨论:如何写好 Git commit log?](https://www.zhihu.com/question/21209619/answer/257574960) -------------------------------------------------------------------------------- /software-engineering/how-to-write-a-technoloy-plan.md: -------------------------------------------------------------------------------- 1 | # 项目设计文档 2 | 3 | ## 1. 概述 4 | 5 | ### 1.1 项目背景 6 | 7 | ### 1.2 项目目标 8 | 9 | ### 1.3 术语 10 | 11 | ### 1.4 相关文档 12 | 13 | 14 | ## 2. 项目整体分析 15 | 16 | ### 2.1 整体业务流程(泳道图) 17 | 18 | ### 2.2 功能流程/页面流程(流程图) 19 | 20 | ### 2.2 用例图 21 | 22 | ### 2.4 数据流程图 23 | 24 | ### 2.5 系统时序图 25 | 26 | ### 2.6 系统领域模型 27 | 28 | ## 3. 核心模块设计 29 | 30 | ### 3.1 系统架构图 31 | 32 | ### 3.2 核心模块时序图 33 | 34 | ### 3.3 接口设计 35 | 36 | ### 3.4 数据库设计(ER图) 37 | 38 | ## 4. 稳定性 39 | 40 | ## 5. 发布计划 41 | 42 | ### 5.1 发布前准备 43 | 44 | ### 5.2 涉及的发布项目 45 | 46 | ### 5.3 发布顺序 47 | 48 | ### 5.4 回滚计划 49 | 50 | ### 5.5 灰度方案 -------------------------------------------------------------------------------- /software-engineering/scrum.md: -------------------------------------------------------------------------------- 1 | ## 敏捷软件开发 2 | 3 | ### 参考文章 4 | - [what is scrum](https://www.scrum.org/resources/what-is-scrum) 5 | - [scrum guide](https://www.scrumguides.org/) -------------------------------------------------------------------------------- /tools/git/README.md: -------------------------------------------------------------------------------- 1 | ## Git 2 | 3 | ### 个人总结 4 | * [SSH key配置及Git多账号配置](./git-multi-user.md) 5 | * [Git提交内容](./git-commit.md) 6 | * [Git删除分支](./git-delete-branch.md) 7 | * [Git回退操作](./git-reset-commit.md) 8 | * [Git常见问题及解决](./git-problems.md) 9 | 10 | ### 相关文档 -------------------------------------------------------------------------------- /tools/git/git-commit.md: -------------------------------------------------------------------------------- 1 | ## Git 提交操作 2 | 3 | ### 提交所有变化 4 | 5 | ``` 6 | git add . 7 | 8 | git commit -m'commit message' 9 | 10 | git push 11 | ``` 12 | 13 | ### 提交指定文件 14 | 15 | ``` 16 | git status 17 | 18 | // 修改的文件 19 | 20 | git commit filepath1 -m'commit message' 21 | 22 | ``` -------------------------------------------------------------------------------- /tools/git/git-delete-branch.md: -------------------------------------------------------------------------------- 1 | ## Git删除本地分支 2 | 3 | ### 1.删除除了master之外的所有分支 4 | 5 | ``` 6 | git branch | grep -v "master" | xargs git branch -D 7 | ``` 8 | 9 | **注意点** 10 | 11 | * 执行前需要切换到master分支执行 12 | * 当前分支未做修改 13 | 14 | ### 2.删除指定分支 15 | 16 | #### 删除本地分支: 17 | 18 | ``` 19 | git branch -d 分支名(remotes/origin/分支名) 20 | ``` 21 | 22 | #### 强制删除本地分支: 23 | 24 | ``` 25 | git branch -D 分支名 26 | ``` 27 | 28 | #### 删除远程分支: 29 | 30 | ``` 31 | git push origin --delete 分支名(remotes/origin/分支名) 32 | ``` -------------------------------------------------------------------------------- /tools/git/git-multi-user.md: -------------------------------------------------------------------------------- 1 | ## Git多用户配置 2 | 3 | ### 配置密钥 4 | 首先在本地生成一个SSH Key,输入命令: 5 | 6 | ``` 7 | ssh-keygen -t rsa -b 4096 -C "suvlliansong@163.com" 8 | ``` 9 | 10 | 回车之后会出现几条确认信息,其中有: 11 | 12 | ``` 13 | Enter a file in which to save the key (/Users/demon/.ssh/id_rsa): [Press enter] 14 | ``` 15 | 16 | 输入私钥的存储位置,默认是/Users/demon/.ssh/id_sra。如果只使用一个Git账户,使用默认位置即可,如果创建多个账户,第二次及以后的私钥需要重命名。 17 | 18 | /Users/demon是当前用户的根目录,也就是~/.ssh/id_sra和~/.ssh/id_sra.pub是系统默认获取密钥的位置。当你用SSH方式访问Github的时候,默认会用这个路径获取密钥,所以不要轻易修改文件路径。 19 | 20 | 例如我输入的是: 21 | 22 | ``` 23 | /Users/demon/.ssh/id_ras_suvllian 24 | ``` 25 | 26 | 然后,系统会让你设置Key的密码: 27 | 28 | ``` 29 | Enter passphrase (empty for no passphrase): [Type a passphrase] 30 | Enter same passphrase again: [Type passphrase again] 31 | ``` 32 | 33 | 可以输入密码,也可以直接回车。如果输入了密码,那在你使用SSH Key登陆Github的时候,需要输入密码。 34 | 此时,SSH Key已经生成完成,`.ssh`文件夹下会生成两个文件:id_rsa和id_rsa.pub,分别是私钥和公钥。 35 | 36 | 现在需要做的就是把id_rsa.pub的公钥配置到Github服务器中。 37 | ![git-ssh-keys](./images/git-ssh-key.png) 38 | 39 | 添加完SSH Key后就已经完成了所有配置。 40 | 这个时候git clone下载一个私有仓库,再将代码push到远程仓库,就不用再输入任何账户密码了。 41 | 如果你只需要配置一个Git账户,工作到此结束! 42 | 43 | ### 多用户配置 44 | 如果需要配置多账户的话,重复执行上述操作,注意要重新输入SSH key的名称。 45 | 这时候有个问题:当我们使用git命令时,默认使用~/.ssh/id_rsa,新建的key如何使用? 46 | 回想一下,SSH都是根据你输入的git账户去生成的。所以只要在对应的代码仓库中配置`user.email`和`user.name`就可以了。 47 | 48 | 我在电脑上配置了一个全局的config,这个SSH key对应的是公司的gitlab,是我日常都会用到的。然后我自己的github偶尔会写点东西,只需要在对应的代码仓库单独配置`user.email`和`user.name`即可。 49 | 50 | **配置全局config:** 51 | 52 | ``` 53 | git config --global user.name "suvllian" 54 | git config --global user.email "suvlliansong@163.com" 55 | ``` 56 | 57 | **指定代码仓库配置config:** 58 | 59 | ``` 60 | git config user.name "suvllian" 61 | git config user.email "suvlliansong@163.com" 62 | ``` 63 | 64 | 配置完成之后,未经单独配置的代码仓库都是全局账户,经过单独配置的代码仓库使用的都是你所配置的仓库。 65 | 这样就可以使用多账户了。 -------------------------------------------------------------------------------- /tools/git/git-problems.md: -------------------------------------------------------------------------------- 1 | ## Git常见问题及解决 2 | 3 | ### git pull冲突 4 | 5 | 原因:其他人修改了某一文件的内容,而本地文件也被修改了,pull代码的时候就会产生冲突。 6 | 7 | 解决:贮存更改 8 | 9 | 操作步骤: 10 | 11 | * git stash:将工作区恢复到上次提交的内容,同时备份本地修改 12 | * git pull 13 | git stash pop:弹出最近保存的内容,查看对应文件,解决冲突 -------------------------------------------------------------------------------- /tools/git/git-reset-commit.md: -------------------------------------------------------------------------------- 1 | ## Git回退操作 2 | 3 | ### 删除远程仓库分支上的某次提交 4 | 5 | 使用git进行项目管理的过程中,可能会遇到这样的问题。在对本地文件修改后,提交commit并push到了远程仓库,之后发现自己忘记切换分支了。 6 | 7 | 很多人的解决方案是先将本地回滚,然后强制删除远程分支,实际上这是一种高风险的操作,任何用户不应该擅自做远程仓库的回退工作,这样可能对其他用户产生不可预知的影响。 8 | 9 | #### 删除最后一次提交 10 | 11 | ``` shell 12 | git revert HEAD 13 | git push origin master 14 | ``` 15 | 16 | `revert`是放弃指定提交的修改,但是会生成一次新的提交,需要填写相应commit的message,以前的历史记录都在。 17 | 18 | ``` shell 19 | git reset --hard HEAD 20 | git push origin master -f 21 | ``` 22 | 23 | 但是`reset`是将HEAD指针指到指定的提交,历史记录中不会出现放弃的提交记录。 24 | 25 | `-f`是参数强制提交,因为reset之后,本地仓库版本落后于远程仓库,因此需要强制提交。 26 | 27 | **reset参数解释** 28 | 29 | * `git reset –-mixed`:回退到某个版本,只保留源码,回退commit和index file; 30 | * `git reset --soft`:回退到某个版本,只回退commit信息,保留index file,如果还需要提交,可以直接commit; 31 | * `git reset --hard`:彻底回退到某个版本,源码的本地改动也会被删除。 -------------------------------------------------------------------------------- /tools/git/images/git-ssh-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suvllian/computer-science-knowledge/668f0e2e231d464514f8adc0998538c3d1555ac7/tools/git/images/git-ssh-key.png -------------------------------------------------------------------------------- /tools/graph.md: -------------------------------------------------------------------------------- 1 | ## 画图工具 2 | 3 | ### 泳道图 4 | 画图工具: 5 | * 在线工具 6 | * [Visual Paradigm](https://online.visual-paradigm.com/diagrams/features/flowchart-tool/swimlane-diagram-tool/) 7 | 8 | 应用场景 9 | 10 | 示例 -------------------------------------------------------------------------------- /tools/ide.md: -------------------------------------------------------------------------------- 1 | ## 编辑器 2 | 3 | ### 1. 通用编辑器 4 | 5 | #### 1.1 Visual Studio Code 6 | 7 |  **VsCode插件** 8 | * 查看每行代码的Git提交信息:GitLens 9 | * [10款VS Code插件神器,第7款超级实用!](https://zhuanlan.zhihu.com/p/111004160?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io) 10 | 11 | #### 1.2 Sublime Text 12 | 13 | ### 2. 前端开发 14 | 15 | #### 2.1 WebStorm 16 | 17 | #### 2.2 Atom 18 | 19 | ### 3. Python开发 20 | 21 | #### 3.1 PyCharm CE -------------------------------------------------------------------------------- /tools/shell-dict.md: -------------------------------------------------------------------------------- 1 | ## 常用shell命令 2 | 3 | ### 如何查看端口是否被某个进程占用? 4 | 5 | ``` shell 6 | $ lsof -i:3000 7 | ``` 8 | 9 | ### 杀掉制定PID的进程 10 | 11 | ``` shell 12 | $ sudo kill -9 750 13 | ``` 14 | 15 | ### 使用shell SSH连接远程服务器 16 | 17 | * 打开终端,进入根目录 18 | * ssh -p 端口号 用户名@ip,输入后回车 19 | * 输入密码 20 | 21 | ``` shell 22 | $ sudo su 23 | $ ssh -p 22 username@119.22.33.44 24 | ``` -------------------------------------------------------------------------------- /tools/tools.md: -------------------------------------------------------------------------------- 1 | ### 效率工具 2 | * 思维导图:XMind、XMind ZEN 3 | * 项目排期:OmniPlan 4 | 5 | ### 功能工具 6 | * 录屏:LICEcap 7 | * 画图:OmniGraffle 8 | 9 | ### 开发工具 10 | * Host切换工具:iHost 11 | * 网络代理工具: 12 | * Charles 13 | 14 | ### Mac工具 15 | * mac终端工具: iterm2 16 | * 快速进入指定目录:[autojump](https://www.jianshu.com/p/15f0ffaa88d7)。记录原来进入目录的历史记录。 17 | * 终端快捷键:oh-my-zsh 18 | * Mac通用搜索工具:Alfred 19 | * Mac自动切换壁纸: 20 | * Irvue 21 | * Unsplash Wallpapers 22 | 23 | ### Chrome插件 24 | * 通用插件 25 | * 广告过滤:Advertising Terminator 26 | * 前端开发需要使用的插件 27 | * JSON格式化:json-formatter 28 | * 跨域设置:Allow-Control-Allow-Origin 29 | * JS及CSS格式化:JavaScript and CSS Code Beautifier 30 | * React开发者工具:React Developer Tools 31 | * Redux开发者工具:Redux DevTools 32 | * URL生成二维码:草料二维码 33 | --------------------------------------------------------------------------------