道生一,一生二,二生三,三生万物 —— 《道德经》

赫拉里的“人类简史” 里有一段关于人类从原始人进化到部落的记录很有意思,动物之间也会有传递信息,但是人类发展出来复杂的体系,就是语言的一个新维度:抽象思维。
我理解的抽象是从众多的表象里能抽象出一个能够描述这些表象的框架,理论,名词等。
wikipedia里对抽象的定义:

  • 抽象: 就是抽取事物一些本质的东西,剔除次要的表面东西。
  • 计算机科学里的抽象化: 指高级的模型,和低级的实体相对。

最近又翻开了CSAPP(深入理解计算机系统)…

阅读全文 »

前言

春节带了一本架构即未来回家消遣,听同事说是本书适合xx这样级别的leader看,看了第一部分,感觉言之也确实有理,本书站的角度就与我们这些工程师不同了。开篇第一问题就是哪个因素最产品的久远发展最为关键?工程 or 技术 or 人员。给出的几个选项应该都很明确答案应该是人。但同时我想到的是最近设计和开发产品的时候经常问题不断,项目管理人员想通过规范的方式来避免这些问题的出现。那么就是说想通过规范来避免这些问题。当然初级的技术问题,可以通过这些规范,或者工程来避免。因为当团队新人比例过大的时候,规范起到的作用是很重要的。比如代码规范,上线规范这些都是要通过规范来避免一些低级错误。而当这些错误被尽可能地避免,产品的发展才是刚开始。
前言碎语讲太多,开始对书中的精彩观点做点附议。
人是可扩展性的心和脑
项目要想成功三个因素:

  • 合适的人
    合适的人指的是此人有合适的知识,技术和能力。
  • 合适的行为
    认同公司的文化与价值观,能与同事融洽相处
  • 合适的工作
  • 合适的时间

组织:

要成功的设计出一个组织,首先要搞清楚组织的产出是什么。管理=度量,需要找到合适的度,必须要有指标来衡量。指标很重要

人员数量对项目的影响

贝佐斯的“两张披萨饼”的理论。主要是沟通成本。项目有三十个人力的时候,实际上有效人力只有28个,最佳团队组织人数在十到二十之间。

管理和领导的认知。

管理:推
确保合适的人在合适的时间,以合适的行为做合适的工作。管理就是度量,怎么做到合适。如果没有管理,就没有人对要按时完成的事负责任。
领导:拉
制定使命,描绘愿景,制定路线图,帮助员工理解做什么才能为股东创造价值。领导对可扩展性的重要在于不仅要设定方向和使命,还要激励员工向目标奋进。

本文是重构 读书笔记第三篇

自测试代码的价值

每个类都应该有一个测试函数,并以它来测试自己这个类。

确保所有测试都完全自动化,让他们检查自己的测试结果。

编写测试代码的最有用的时机就是在开始编程之前,当你需要添加特性的时候,先写相应的测试代码。

编写测试代码的时候其实就是在问自己,添加这个功能需要做些什么。编写测试代码还能使你把注意力集中于接口而非实现。

频繁进行测试是极限编程的重要一环。

阅读全文 »

本文是重构 读书笔记第二篇

读完本文你会大概清楚重构开始和停止的时机以及重构机制如何运作。

重构一般是靠经验丰富者的直觉,本章也只是给出一些迹象来表明这里有一个可以用重构解决的问题。

重复代码

IDEA15新增了一个非常好的功能,就是遇到重复代码,IDE会用标记提醒你重复的代码段并可以跳转到重复代码。

常见的重复代码情况:

  • 同一个的类的两个函数含有相同的代码

  • 两个互为兄弟的子类内含相同表达式

  • 两个不相关的类出现重复代码

    对于第一种情况,需要使用Extract Method, 提炼出重复代码,然后让两个函数调用提炼出来的代码。

    对于第二种情况,可以将重复代码提炼出来后放入超类中。

    对于第三种情况,需要使用Extract Class , 将重复代码提炼到一独立类中,然后在另一个类中使用这个新类。

阅读全文 »

前言

本文是重构读书笔记系列第一篇

什么是重构

重构,每个人都对重构有自己的理解和定义。

文中提到的名词和动词的理解

  • 名词,对软件内部结构的一种调整,在不改变软件可观察行为的前提下,提高可理解性。降低修改成本。
  • 动词,使用一系列重构方法调整结构。

重构要扩展的两点

  • 使软件更容易被理解和修改。
  • 不会改变软件可观察的行为。

对用户是透明的。

为什么要重构

重构不是银弹

阅读全文 »

Why Thread

在没有线程的从前日子,当服务器处理成千上万个连接的时候性能问题就非常突兀了,这个时候

  • 重用进程
  • 使用轻量级的线程
    书中提到使用线程代替进程会使服务器性能提升三倍,如果再使用线程池可以提升九倍多。
    使用线程池处理短连接可以在每分钟使用100个不到线程处理数千个短连接。
  • 异步I/O
    在IM的应用场景中经常会出现同时需要数千个很长时间的连接。
    这个会在以后的文章中详细讲解。
    阅读全文 »

在最近的几次面试实习生有时候会问,实现线程的两种方式以及用哪个更好。
同学们一般都会答出extends Threadimplement Runnable ,至于哪种更好,大概会有半数人答不出来,虽然这个问题很简单,但是在实际工作中自己去生成一个线程的情况还是很少遇见的。但这里面的问题稍微抽象下就可以看出是考察extendsimplements之间的区别和优劣。
一般来说我们会选择implement Runnable 方式,因为Java是单继承但可以多个扩展,使用接口更利于扩展,另外扩展Runnable接口更利于资源共享,即多线程处理同一资源.
面试的话到这里可能就结束了,但是深入探究下,为什么两者都可以,两者之间的关系是怎么样的。
先写两个方法的简单示例:
Thread方式

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ThreadTest extends Thread {
private static final int _N = 10;

public void run() {
System.out.println(Thread.currentThread().getName() + " : " + _N);
}

public static void main(String[] args) throws InterruptedException {
ThreadTest t0 = new ThreadTest();
t0.start();
}

}

阅读全文 »

quartz是由Java编写的一款调度程序,github的地址:https://github.com/quartz-scheduler/quartz

Quartz使用

Schedulers是由工厂方法生成的。
Scheduler Job会在调用start()之后才会开始执行。

使用Scheduling API

扩展接口Job,在里面的execute()方法里即可编写被调度程序的逻辑代码.

1
2
3
4
5
6
7
8
9
public class MyJob implements org.quartz.Job {

public MyJob() {
}

public void execute(JobExecutionContext context) throws JobExecutionException {
System.err.println("Hello World! MyJob is executing.");
}
}

阅读全文 »

在查询或者更新数据的时候我们都容易犯忘记关闭JDBC的错误,spring之类的框架又非常笨重,DbUtils 是一个非常轻量的操作JDBC的工具。
除了操作简便之外,dbutils还可以将ResultSet转换成不同的对象。

使用示例

1
2
3
4
5
6
7
8
/*
* @param dataNode 相应的数据节点的信息
* @return 返回QueryRunner实例
* @throws java.lang.NullPointerException 如果连接池并没有初始化,则抛出此异常
* */
public static QueryRunner getQueryRunner(final String dataNode) {
return new QueryRunner(MySQLHelper._DATASOURCEMAP.get(dataNode));
}

其中_DATASOURCEMAP数组存放的是线程池,初始化_DATASOURCEMAP:

1
2
3
4
5
6
7
private static final Map<String, DataSource> _DATASOURCEMAP = new ConcurrentHashMap<>();
...
for (final Map<String, Object> row : (List<Map<String, Object>>) config.get("node")) {
//System.out.println(row.get("aliasName"));
_CONFIG.put(row.get("aliasName").toString(), row); /*把节点缓存*/
_DATASOURCEMAP.put(row.get("aliasName").toString(), DruidDataSourceFactory.createDataSource(row));
}

这部分有个druid的线程池的部分,关于druid的可以参考博客中的druid源码阅读。

阅读全文 »