学习方法论
framework
了解背景
- 框架是什么,用来做什么,解决了什么问题
- 为什么出现这个框架,框架的背景,框架的作者,作者的博客
- 框架的发展历史,版本发布时间,目前的发展情况,从这些信息可以了解到这个框架的目前的活跃程度,这些信息可以从 wiki 上获取 apache wiki
- 有哪些解决了相似问题的框架,这些框架的比较
- 从 cwiki 上可以获取到框架的一些设计理念
分析源码
从框架的使用入手,找到框架的入口类,例如对于调度执行框架来说,kafka, storm 等等,可以从其启动的脚本文件入手。
- 从入口类出发梳理整个框架启动之后,会启动哪些线程
- 这些线程构成了哪些子系统
- 各种子系统的功能是什么,子系统包含哪些线程,各个线程之间如何协作,画出子系统运行图
- 子系统之间如何进行交互,子系统之前通过消息队列,还是其它接口通信。
- 整个框架如何向外发布服务,创建一个 Socket 的某个 port 上监听。
- 提供了哪些服务,可以响应哪些请求
- 外部有哪些 Client,这些 Client是如何使用框架提供的服务的,使用的流程是什么。例如 Consumer 使用 kafka 的流程是什么。
最终源码分析的结果就是可以推导出一幅系统内部运行状态图,同时框架如何与外部依赖交互(例如 kafak 如何使用 zookeeper, storm 如何使用 zookeeper)
如果子系统比较复杂,可以将子系统单独画出内部运行图。然后全局的系统运行图中的子系统不用那么细致的描述。
学习宏观架构
- 架构整体是否使用了什么设计模式,例如 Kafka 使用了 Broker 模式。结合具体的设计模式,可以帮助理解架构,反之,通过学习框架也可以了解到模式在实际场景下是如何被使用的。
- 框架解决的问题域,如何进行模型提取的,是如何抽象到具体的类层次设计的。
- 关注设计模式的使用,框架中为了可扩展性,以及给用户(使用框架的人)留有可以自定义的地方,框架会使用一些设计模式来封装扩展点。例如最为常用的工厂方法。同时也可以反推,如果某个模块使用了工厂方法,说明这个模块是一个整个框架实现 的一个扩展点。例如 Thrift 框架中,
- 总结框架的优缺点,找相关的解决同类的问题的框架作比较,总结框架的适用领域。
框架的应用
框架往往是解决特定的问题域,有一些常用的经验,例如。storm 流式处理框架,时间窗口的问题就是一个框架相关的应用经验,可以说只要是使用到了 storm ,伴随而来的就是时间窗口的问题。所以学习框架到最后就是落实到应用上,掌握框架的
library
学习 library 和 framework 有不同的方法。 类库中往往有一个核心的入口类,其它的功能,都是由这个类生发而来。好的设计往往是简洁,明了和易于学习掌握的。所有通常入口也会统一。例如 HDFS 的 java client 其核心类是 org.apache.hadoop.fs.FileSystem
通过这个类,基本就可以完成对 HDFS 的操作。
所以类库的使用,要根据其所提供的核心功能,找到功能接口类,从这个入口类,就可以使用这个类库的功能了。
对比和选取
在 Java 开发中,往往会大量完成同样功能的框架或者类库,如何选取呢。结合以下指标:
- 框架或者类库能够完成的功能的优点和缺点
- 框架的学习掌握难度
- 目前开发人员对哪个框架比较熟悉
搭建一个通用的 WEB 框架
基于 spring 搭建一个通常的 WEB 框架 和 web server 框架。
web 设计
使用前端 MVC 框架,进行前后端分离。
java 语言
Java 跨平台的意义
Java 语言跨平台,就是因为 JVM 在不同平台上有其不同的实现,JVM的意义在于使用各个操作系统通用的语言(c&c++), 实现 JVM 规范,当然不同系统之间的语言虽然通用,但是其抽象逻辑却不相同,例如在 linux 系统下,操作文件系统,其核心抽象是 文件描述符(FD),而在 windows 平台下却是 句柄(handle), 同样地,系统级接口,例如操作磁盘文件,操作网络的接口,虽然都是使用 C 语言描述,但是API却各不相同。有一些系统级接口,虽然是有规范存在,使用 网络 Socket 接口,使用通用规范提供的 API 确实可以实现代码跨平台使用,但是在有些平台上,这些通用接口可能只是兼容性实现,其效率并没有其平台自带的 API 实现的高,所以虽然 c&c++ 是平台独立的语言,但是涉及到具体平台相关的操作,则使用的库就是不一样的,并且在不同平台上其编译的结果也是不同的。
所以就有必要在不同平台上使用c/c++实现一套相同的规范。在这套规范中定义通用的指令集(JVM指令集)。定义通用的编译后的文件格式(class文件)。定义运行时模式(基于栈的运行模式),等等,这些通用规范的定义,使得所有的机器(不同平台,不同架构)只要实现了相同的规范。则其编译后的代码(class文件)就可以跨平台运行。
JVM的意义在于抽象了不同的运行时环境(不同操作系统平台,不同硬件架构),提供了一个一致对外的运行环境。
只要是符合规范的 Class 文件就可以在 JVM 上运行。从而也就为基于 JVM 上实现的各个编程语言,提供了一个可以跨平台的运行时环境。
更进一步讲,一个通用平台的出现,使得大量的 library 可以被复用,例如我们可以使用各个语言来实现各种非常好用的数据结构例如List,Map等,还有很多算法,例如各种排序。但是由于不同语言实现,可能在不同平台上无法共享使用。而一旦使用基于 JVM 的语言实现,最终编译成的 class 文件,是通用的。这样一个优秀的数据结构,算法的实现,就可以在整个 JVM 的环境中使用。这个一件非常有意义的事。
常用的数据结构,算法,各个队列等等,都通过 相同的 JVM 语言来描述。这样就不会造成浪费不用在各个平台上各自实现,而是有一个通用的良好实现。这样编程的基础构件就会越来越多,越来完善。越来方便。最终构成一个基础构件库。
这时候再考虑,当我们启动了一个 JVM 的时候,我们启动了什么。当我们启动一个 JVM,相当于我们拥有了一台可以执行代码的机器,并且这台机器支持多线程,文件,网络等等。我们可以使用 JDK 及各种 library 来使用这台机器,完成特定的功能。这时候当写代码的时候,就考虑你不仅仅是在写代码,而是使用语言来让这个通用机器完成特定的任务。例如使用 JDK 的文件IO API。可以创建,编辑,读写文件。而这种操作是针对 JVM 的,而不是具体的某个平台。
java 语言和其整个生态系统发展到今天,我觉得 java 语言的跨平台已经不在是 java 语言的一个特点了,跨不跨平台已经不重要,重要的是在这个稳定的,一致的JVM运行时环境下,产生的大量可用的代码,各种库,各种框架。这些库和框架可以被快速应用到各种生产应用环境中,解决实际的问题。并且使用 java 语言进行一致的描述。各种各样的 idea,以代码的形式,保留了下来。便于方便的学习,这个才是最宝贵的。
进阶学习
代码的运行并不是孤立的,它是运行在特定环境中的,对于 java 代码来说,运行在 JVM。所以首先
应该了解 JVM 的基本原理。
其次,JVM 本质也是一个应用的程序。它自身也是运行在特定环境中的。这个环境就是操作系统。
作为一个的程序,有输入,输出,才能够被外界所使用。所以代码中必然会涉及到和外部环境交互的问题。
例如一个 WEB 程序,其作用是用户通过浏览器输入信息,信息通过网络返回到程序内部。程序读取数据库
做相应的计算。然后再返回。整个过程就涉及到多个资源。
- 内存 – 缓存
- 网络 – 网络并发
- 磁盘 – 磁盘并发,性能评价指标
- CPU 多线程 多核CPU – 如何在代码中利用多核心,多处理器的 CPU
- 操作系统 – 线程模型,同步机制等等。文件读写。
在写一个高效的应用的时候,需要考虑的问题就是,这些资源中,哪些可能会造成性能瓶颈。
只有对这些资源都有一定认识,才可能在写代码的时候,注意到如何高效的使用这些资源。
例如,对于数据库。如果有大量并发写入。如果对 mysql(数据库) 的存储引擎,有足够的了解。
如何评价的性能。那么在写代码的时候,自然就知道如何处理,并发写入的问题。
其实,如何用,如何能变通的去应用,其关键点在于,要了解它的特性。
例如:如果对 mysql 有深入的了解,就可以有多种方法处理大表的问题。
总之,就是,程序的性能问题依赖于外部环境。而程序员对外部环境了解多少,那么他对程序的
掌控能力就有多少。
如果没有存储相关的软件,我们需要掌握,如何评价它。例如:性能,并发,适用的存储对象。
书籍:
大话存储
深入理解并行编程
多处理器编程的艺术
MySQL技术内幕:InnoDB存储引擎(第2版)
网络编程的学习路径:基本的 JAVA Socket 接口。基于 Socket 接口的上层 封装 API。例如 netty, mina 等。
在向上走,就是 web 服务器,是如何实现的,如何处理并发请求。并发请求的处理模型。可以学习 tomcat 源码。
可以学习 Tomcat Connector architecture 。
企业级应用的特点
登录验证体系
使用系统的人,不但有客户,还会有系统的运维人员。同时系统的运营人员,可以登录客户的账号进行一些特权操作。
这就要求 account, cusomter 进行分离抽象。
消息系统。
操作日志的记录,帮助企业级客户,进行问题追述。
操作日志又不应该核心业务。所以操作日志的记录应该是异步完成的。
需要有一个消息系统。处理完核心业务之后,发送一条消息。进行日志记录。
外部系统的隔离
对于一些外部服务。例如:公司内部提供了一套消息队列API,我们在系统内部使用的时候,最好先进行一次封装。
例如:如果公司API升级,参数发生变化,甚至服务不可用。此时就需要对我们的当前系统进行改造。
如果没有进行封装处理,可能 API 升级时,需要做大量工作来完成,我们的项目改造。
工作流
企业级应用的审核是非常常见的一种操作。审核就涉及到工作流。