20本专业书阅读计划完成进度之 – Clean Code: A Handbook of Agile Software Craftsmanship  (代码整洁之道)

20本专业书计划,之前看过某个视频分享,要想成为这个领域的专家,至少20本这个领域的专业书走起。小时候学习书法的时候,老师教过王羲之的练习方法, 当你写完18缸的水,书法水平才算凑合。每读一本专业书都算是一个大型的project, 因为要耗费至少完整10-20个小时才能完成,且分散到好几天到1-2个月。而且读专业书不像读故事书那样轻松,一般还要边阅读边思考。内化功力是重要的,学习不能只是学不用,我也渐渐意识到,只有在工作中,运用过程中,边做边学习边思考才是有效学习。所以,摒弃学生时代那种学习方式,读完整本课本,再去用,或者读完整本课本,根本没有实战机会去用,这是比较低效的学习,随着时间久了,从书本里学到的东西也就淡忘了。 我读了啥? 最近我完结的一本专业书阅读是:Clean Code: A Handbook of Agile Software Craftsmanship (代码整洁之道),原版链接放在文末参考处。 大师级作者 Uncle Bob 分享: 写代码如写文章 把系统当故事来讲,而不是当作程序来写 计算机业内知名的Uncle Bob (Robert C. Martin)的书,这本书,会给你提供很多思路,整洁你的代码。对我而言,这本书对我最大的帮助是教我如何做好一次Code Review (CR), 以及在自己写代码的时候如何优化自己的代码。 在我进入一家成熟的科技公司 (Tech Company)之前,我根本不太知道CR是什么东西,之前实习的时候的创业公司也不需要做Code Review. 诚如在领英上很多创业公司的人分享的一样,一个创业公司,只要代码能跑,就赶紧先上线再说。然而,这个方式,在成熟的科技公司里,是不允许的,因为你的代码,可能随时破坏Production的稳定性,带来爆炸范围 (Blast Radius)很广的客户影响 (Customer Impact), 进而来带几百万几千万美金的业务损失。隐形的危害是,可能现在看不出来,长久地会越来越难维护,并且变得越来越糟糕且越难越铲除,花费工程师越来越多的时间进行运维 (Ops),而时间就是金钱。 在我工作第一年内,那时候我还是不太懂如何做好一次Code Review, 当有同事叫我帮忙review 一个Code Logic, 那时候的我大概是这样: 看了半天,不知道该从哪里入手?从哪里看起? 对于这个Code Logic 我该问什么问题? 不知道问什么问题,于是就去模仿别人如何回复? 想参考一下别人该从哪开始看。 查遍内外网的WIKI, 关于”How to do a … [Read more…]

分布式系统 – 数据拆分,复制以及在Amazon DynamoDB的应用

1. 概要 本文希望用一杯咖啡的时间,讲明白什么是数据拆分(Partitioning) ,什么是数据复制 (Replica), 一致性哈希算法为何被引入,什么是一致性哈希算法,以及解读amazon 在2007年发表在ACM上,DynamoDB 经典论文 Dynamo: Amazon’s Highly Available Key-value Store 如何应用这些技术。 挑战: 日常生活中,经常会发生,当一台数据库挂了,用户访问不到数据怎么办?以下解决方案可以用来解决这个问题: 1.数据拆分 Sharding or Partitioning 2.数据复制 Replica 2. 数据复制 数据复制 (Replica) 是实时的,每一份数据在写入的同时,会被同时在其他几台机子上面存放几分相同的数据。当某一台机子上的数据丢失的时候,立马能从其他机子获得该数据。数据复制,也能分摊读请求,用户访问一份数据,就不在只能从某一台机子上获取。 数据复制和备份(backup) 有什么区别呢? 数据备份通常是每隔一定时间,进行一次备份。数据丢失的时候,只能恢复到之前某个时间点的数据。数据备份不能分摊读请求。 3. 数据拆分 数据拆分就是把数据分成多块,存在不同的机器上。则挂了一台,不会全挂,也能分摊读写能力。数据复制就是同一份数据存在其他的机器上,多存几份。挂了一台,还可以从其他机器恢复,也能分摊读请求。 数据拆分分为纵向拆分vertical sharding 和纵向拆分 hirizontal sharding。 纵向拆分: 根据工作性质不同,不同类型的表放在不同数据库。例如,订单库,商品库等等。 纵向拆分缺点:如果,表单很大,则访问量就很大。 横向拆分: 将同一个表,分成多部分,存在不同的数据库中。例如将一部分内容存放在机器a, 另一部分内容存放在机器b, 还有一部分内容存放在机器c. 这样用户访问数据时候,可以分散读写,不会仅仅从一台机器里获取数据,导致该机器访问量很大. 那么如何拆分? 方案1:可以把旧的数据存在一起,新的数据用新的机子存,但是这样的缺点是,人们访问最近使用的数据频率比较高,访问就数据频率低,导致各个机子访问量不均匀。 通常将读写访问量不均匀,部分机子访问量异常大的这些机子称之为热点(hot spot)。 方案2:传统的哈希算法,用hash function = key … [Read more…]

每天学点操作系统-学习笔记

Linux 的进程管理 进程的类型: 前台进程 后台进程 守护进程 前台进程 前台进程就是具有终端,可以和后台进程进行交互的进程 后台进程 与前台进程相对,没有占用终端的就是后台进程 后台程序不和用户进行交互,优先级比前台进程低 需要执行的命令以 & 符号结束 守护进程 守护进程是特殊的后台进程 很多守护进程在系统引导的时候启动,一直运行知道系统关闭 Linux有很多典型的守护进程 以d结尾的一般是守护进程 进程的标记: 进程ID 进程ID是进程的唯一标识符,每个进程拥有不同的id 进程id表现为一个非负整数,最大值由操作系统限定 父进程,子进程 父子进程关系可以通过pstree命令进行查看 Id 为0的进程为idle进程,是系统创建的第一个进程 id为1的进程为init进程,是0号进程的子进程,完成系统初始化 init进程是所有用户进程的祖先进程 进程的状态 进程的5个状态:创建,就绪,阻塞,执行,终止 常用linux命令: ps, top, kill 作业管理之进程调度 进程调度概述 进程调度是指计算机通过决策决定哪个就绪进程可以获得CPU使用权 也是多道程序设计 1.保留旧进程的运行信息,请出旧进程 (收拾包袱) 2.选择新进程,准备运行环境并分配CPU (新进驻) 进程调度包括: 1.就绪队列的排队机制 2. 选择运行进程的委派机制 3. 新老进程的上下文切换机制 就绪队列的排队机制 将就绪进程按照一定的方式排列成队列,以便调度程序可以最快找到就绪进程 选择运行进程的委派机制 调度程序以一定的策略选择就绪进程,将CPU资源分配给它 新老进程的上下文切换机制 保存当前进程的上下文信息,装入被委派执行进程的运行上下文。 … [Read more…]

Go 语言学习

Go 方法中,变量类型是在变量名之后。 短变量声明 在函数中,简洁赋值语句 := 可在类型明确的地方代替 var 声明。 函数外的每个语句都必须以关键字开始(var, func 等等),因此 := 结构不能在函数外使用。 基本类型 Go 的基本类型有 bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // uint8 的别名 rune // int32 的别名 // 表示一个 Unicode 码点 float32 float64 complex64 complex128 零值 没有明确初始值的变量声明会被赋予它们的 零值。 零值是: 数值类型为 0, 布尔类型为 false, 字符串为 “”(空字符串)。 for 是 Go 中的 “while” 此时你可以去掉分号,因为 C 的 while 在 Go 中叫做 for。 defer defer … [Read more…]

Java 异常处理

2019.11 Java的异常 从继承关系可知:Throwable是异常体系的根,它继承自Object。Throwable有两个体系:Error和Exception,Error表示严重的错误,程序对此一般无能为力,例如: OutOfMemoryError:内存耗尽 NoClassDefFoundError:无法加载某个Class StackOverflowError:栈溢出 而Exception则是运行时的错误,它可以被捕获并处理。 某些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如: NumberFormatException:数值类型的格式错误 FileNotFoundException:未找到文件 SocketException:读取网络失败 还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如: NullPointerException:对某个null的对象调用方法或字段 IndexOutOfBoundsException:数组索引越界 Exception又分为两大类: RuntimeException以及它的子类; 非RuntimeException(包括IOException、ReflectiveOperationException等等) Java规定: 必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。 不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。 throw Eg. Throw new IOException(); Throw 抛出的只能够是可抛出类throwable 或者其子类的实例对象 Throw 抛出对象的两种处理方案 1.通过try..catch — 自己抛出自己处理 2.throw 抛出的对象,在方法声明处抛出异常类型—谁用谁处理,调用者可以自己处理,也可以继续上抛 第一点eg. Eg.2 异常分类 异常的五个关键字 Try, catch, finally, throw, throws Try catch finally Try 产生异常,catch 捕获异常,finally 无论怎样都能显示 -> Java 异常链 … [Read more…]

Database基础概念与常用SQL 语句

I. Database 基础概念 Primary Key 参考廖雪峰的解释 https://www.liaoxuefeng.com/wiki/1177760294764384/1218728391867808 每一条记录都包含若干定义好的字段。同一个表的所有记录都有相同的字段定义。 对于关系表,有个很重要的约束,就是任意两条记录不能重复。不能重复不是指两条记录不完全相同,而是指能够通过某个字段唯一区分出不同的记录,这个字段被称为主键。 例如,假设我们把name字段作为主键,那么通过名字小明或小红就能唯一确定一条记录。但是,这么设定,就没法存储同名的同学了,因为插入相同主键的两条记录是不被允许的。 对主键的要求,最关键的一点是:记录一旦插入到表中,主键最好不要再修改,因为主键是用来唯一定位记录的,修改了主键,会造成一系列的影响。 由于主键的作用十分重要,如何选取主键会对业务开发产生重要影响。如果我们以学生的身份证号作为主键,似乎能唯一定位记录。然而,身份证号也是一种业务场景,如果身份证号升位了,或者需要变更,作为主键,不得不修改的时候,就会对业务产生严重影响。 所以,选取主键的一个基本原则是:不使用任何业务相关的字段作为主键。 因此,身份证号、手机号、邮箱地址这些看上去可以唯一的字段,均不可用作主键。 作为主键最好是完全业务无关的字段,我们一般把这个字段命名为id。常见的可作为id字段的类型有: 自增整数类型:数据库会在插入数据时自动为每一条记录分配一个自增整数,这样我们就完全不用担心主键重复,也不用自己预先生成主键; 全局唯一GUID类型:使用一种全局唯一的字符串作为主键,类似8f55d96b-8acc-4636-8cb8-76bf8abc2f57。GUID算法通过网卡MAC地址、时间戳和随机数保证任意计算机在任意时间生成的字符串都是不同的,大部分编程语言都内置了GUID算法,可以自己预算出主键。 对于大部分应用来说,通常自增类型的主键就能满足需求。我们在students表中定义的主键也是BIGINT NOT NULL AUTO_INCREMENT类型。 FOREIGN KEY 这样,我们就可以根据class_id这个列直接定位出一个students表的记录应该对应到classes的哪条记录。 例如: 小明的class_id是1,因此,对应的classes表的记录是id=1的一班; 小红的class_id是1,因此,对应的classes表的记录是id=1的一班; 小白的class_id是2,因此,对应的classes表的记录是id=2的二班。 在students表中,通过class_id的字段,可以把数据与另一张表关联起来,这种列称为外键。 Eg. Leetcode sql 1327. List the Products Ordered in a Period Product_id 就是用来和Products table连接的外键 II. 常用SQL 语句 LEFT JOIN statement 保留左边Table所有的行,即使右边的Table没有与之匹配的项。其余可以加条件,让左边Table和右边Table关联起来。 SELECT column_name(s) FROM table_name1 LEFT JOIN … [Read more…]

Java 输入输出用例

1. . import java.util.*; public class Main {     public static void main(String[] args) {         Scanner scan = new Scanner(System.in);         while (scan.hasNext()) {             int a = scan.nextInt();             int b = scan.nextInt();             System.out.println (a+b);         }       } } 2. import java.util.*; public class Main {     public static void main(String[] args) {         Scanner sc = new Scanner(System.in);         int pair … [Read more…]

Javascript 学习

标准函数,可以先试用,后定义 自定义函数 isNaN(n)的用法,判断变量是否不是一个数值,如果这个变量不是一个数值,则返回true,如果是一个数值,则返回false。 JS 逻辑符号 运算顺序 JS 数组 不像java, JS数组内可以包含多种数据类型。 DOM 将文档(页面)表现为结构化的表示方法,使每一个页面元素都是可操控,DOM讲网页和脚本以及其他的编程语言联系了起来。 参考: 慕课网,js课程