mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-16 22:23:45 +08:00
mod
This commit is contained in:
430
极客时间专栏/设计模式之美/不定期加餐/加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法.md
Normal file
430
极客时间专栏/设计模式之美/不定期加餐/加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法.md
Normal file
@@ -0,0 +1,430 @@
|
||||
<audio id="audio" title="加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/96/26/96777fe4f95a8fb8b88c90d7d8313926.mp3"></audio>
|
||||
|
||||
尽管说设计模式跟编程语言没有直接关系,但是,我们也无法完全脱离代码来讲设计模式。我本人熟悉的是Java语言,所以专栏中的代码示例我都是用Java语言来写的。考虑到有些同学并不熟悉Java语言,我今天用一篇文章介绍一下专栏中用到的Java语法。
|
||||
|
||||
如果你有一定的编程基础,熟悉一门编程语言,结合我今天讲的Java语法知识,那看懂专栏中的代码基本不成问题。
|
||||
|
||||
如果你熟悉的是C/C++、C#、PHP,那几乎不用费多大力气,就能看懂Java代码。我当时从C++转到Java,也只看了一天的书,基本语法就全部掌握了。
|
||||
|
||||
如果你熟悉的是Python、Go、Ruby、JavaScript,这些语言的语法可能跟Java的区别稍微有些大,但是,通过这篇文章,做到能看懂也不是难事儿。
|
||||
|
||||
好了,现在,就让我们一块儿看下,专栏中用到的所有Java语言的语法。
|
||||
|
||||
## Hello World
|
||||
|
||||
我们先来看一下,Java语言的Hello World代码如何编写。
|
||||
|
||||
在Java中,所有的代码都必须写在类里面,所以,我们定义一个HelloWorld类。main()函数是程序执行的入口。main()函数中调用了Java开发包JDK提供的打印函数System.out.println()来打印hello world字符串。除此之外,Java中有两种代码注释方式,第一种是“//注释…”双斜杠,表示后面的字符串都是注释,第二种是“/*注释…*/”,表示中间的内容都是注释。
|
||||
|
||||
```
|
||||
/*hello world程序*/
|
||||
public class HelloWorld {
|
||||
public static void main(String []args) {
|
||||
System.out.println("Hello World"); //打印Hello World
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 基本数据类型
|
||||
|
||||
Java语言中的基本数据类型跟其他语言类似,主要有下面几种:
|
||||
|
||||
- 整型类型:byte(字节)、short(短整型)、int(整型)、long(长整型)
|
||||
- 浮点类型:float(单精度浮点)、double(双精度浮点)
|
||||
- 字符型:char
|
||||
- 布尔型:boolean
|
||||
|
||||
如下,我们来定义一个基本类型变量:
|
||||
|
||||
```
|
||||
int a = 6;
|
||||
|
||||
```
|
||||
|
||||
除此之外,为了方便我们使用,Java还提供了一些封装这些基本数据类型的类,这些类实现了一些常用的功能函数,可以直接拿来使用。常用的有下面几个类:
|
||||
|
||||
- Integer:对应封装了基本类型int;
|
||||
- Long:对应封装了基本类型long;
|
||||
- Float:对应封装了基本类型float;
|
||||
- Double:对应封装了基本类型double;
|
||||
- Boolean:对应封装了基本类型boolean;
|
||||
- String:对应封装了字符串类型char[]。
|
||||
|
||||
如下,我们来定义一个Integer对象:
|
||||
|
||||
```
|
||||
Integer oa = new Integer(6);
|
||||
|
||||
```
|
||||
|
||||
## 数组
|
||||
|
||||
Java中,我们使用[]来定义一个数组,如下所示:
|
||||
|
||||
```
|
||||
int a[] = new int[10]; //定义了一个长度是10的int类型数组
|
||||
|
||||
```
|
||||
|
||||
在Java中,我们通过如下方式访问数组中的元素:
|
||||
|
||||
```
|
||||
a[1] = 3; //将下标是1的数组元素赋值为3
|
||||
System.out.println(a[2]); //打印下标是2的数组元素值
|
||||
|
||||
```
|
||||
|
||||
## 流程控制
|
||||
|
||||
流程控制语句跟其他语言类似,主要有下面几种。
|
||||
|
||||
- if-else语句,代码示例如下所示:
|
||||
|
||||
```
|
||||
// 用法一
|
||||
int a;
|
||||
if (a > 1) {
|
||||
//执行代码块
|
||||
} else {
|
||||
//执行代码块
|
||||
}
|
||||
|
||||
// 用法二
|
||||
int a;
|
||||
if (a > 1) {
|
||||
//执行代码块
|
||||
} else if (a == 1) {
|
||||
//执行代码块
|
||||
} else {
|
||||
//执行代码块
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- switch-case语句,代码示例如下所示:
|
||||
|
||||
```
|
||||
int a;
|
||||
switch (a) {
|
||||
case 1:
|
||||
//执行代码块
|
||||
break;
|
||||
case 2:
|
||||
//执行代码块
|
||||
break;
|
||||
default:
|
||||
//默认执行代码
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- for、while循环,代码示例如下所示:
|
||||
|
||||
```
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
// 循环执行10次此代码块
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < 10) {
|
||||
// 循环执行10次此代码块
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- continue、break、return,代码示例如下所示:
|
||||
|
||||
```
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (i == 4) {
|
||||
continue; //跳过本次循环,不会打印出4这个值
|
||||
}
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (i == 4) {
|
||||
break; //提前终止循环,只会打印0、1、2、3
|
||||
}
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
public void func(int a) {
|
||||
if (a == 1) {
|
||||
return; //结束一个函数,从此处返回
|
||||
}
|
||||
System.out.println(a);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 类、对象
|
||||
|
||||
Java语言使用关键词class来定义一个类,类中包含成员变量(也叫作属性)和方法(也叫作函数),其中有一种特殊的函数叫作构造函数,其命名比较固定,跟类名相同。除此之外,Java语言通过new关键词来创建一个类的对象,并且可以通过构造函数,初始化一些成员变量的值。代码示例如下所示:
|
||||
|
||||
```
|
||||
public class Dog { // 定义了一个Dog类
|
||||
private int age; // 属性或者成员变量
|
||||
private int weight;
|
||||
|
||||
public Dog(int age, int weight) { // 构造函数
|
||||
this.age = age;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public int getAge() { // 函数或者方法
|
||||
return age;
|
||||
}
|
||||
|
||||
public int getWeigt() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
Dog dog1 = new Dog(2, 10);//通过new关键词创建了一个Dog对象dog1
|
||||
int age = dog1.getAge();//调用dog1的getAge()方法
|
||||
dog1.run();//调用dog1的run()方法
|
||||
|
||||
```
|
||||
|
||||
## 权限修饰符
|
||||
|
||||
在前面的代码示例中,我们多次用到private、public,它们跟protected一起,构成了Java语言的三个权限修饰符。权限修饰符可以修饰函数、成员变量。
|
||||
|
||||
- private修饰的函数或者成员变量,只能在类内部使用。
|
||||
- protected修饰的函数或者成员变量,可以在类及其子类内使用。
|
||||
- public修饰的函数或者成员变量,可以被任意访问。
|
||||
|
||||
除此之外,权限修饰符还可以修饰类,不过,专栏中所有的类定义都是public访问权限的,所以,我们可以不用去了解三个修饰符修饰类的区别。
|
||||
|
||||
对于权限修饰符的理解,我们可以参看下面的代码示例:
|
||||
|
||||
```
|
||||
public class Dog {// public修饰类
|
||||
private int age; // private修饰属性,只能在类内部使用
|
||||
private int weight;
|
||||
|
||||
public Dog(int age, int weight) {
|
||||
this.age = age;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public int getAge() { //public修饰的方法,任意代码都是可以调用
|
||||
return age;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 继承
|
||||
|
||||
Java语言使用extends关键字来实现继承。被继承的类叫作父类,继承类叫作子类。子类继承父类的所有非private属性和方法。具体的代码示例如下所示:
|
||||
|
||||
```
|
||||
public class Animal { // 父类
|
||||
protected int age;
|
||||
protected int weight;
|
||||
|
||||
public Animal(int age, int weight) {
|
||||
this.age = age;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public int getAge() { // 函数或者方法
|
||||
return age;
|
||||
}
|
||||
|
||||
public int getWeigt() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
public class Dog extends Animal { // 子类
|
||||
public Dog(int age, int weight) { // 构造函数
|
||||
super(age, weight); //调用父类的构造函数
|
||||
}
|
||||
|
||||
public void wangwang() {
|
||||
//...
|
||||
}
|
||||
}
|
||||
|
||||
public class Cat extends Animal { //子类
|
||||
public Cat(int age, int weight) { // 构造函数
|
||||
super(age, weight); //调用父类的构造函数
|
||||
}
|
||||
|
||||
public void miaomiao() {
|
||||
//...
|
||||
}
|
||||
}
|
||||
|
||||
//使用举例
|
||||
Dog dog = new Dog(2, 8);
|
||||
dog.run();
|
||||
dog.wangwang();
|
||||
Cat cat = new Cat(1, 3);
|
||||
cat.run();
|
||||
cat.miaomiao();
|
||||
|
||||
```
|
||||
|
||||
## 接口
|
||||
|
||||
Java语言通过interface关键字来定义接口。接口中只能声明方法,不能包含实现,也不能定义属性。类通过implements关键字来实现接口中定义的方法。在专栏的第8讲中,我们会详细讲解接口,所以,这里我只简单介绍一下语法。具体的代码示例如下所示:
|
||||
|
||||
```
|
||||
public interface Runnable {
|
||||
void run();
|
||||
}
|
||||
|
||||
public class Dog implements Runnable {
|
||||
private int age; // 属性或者成员变量
|
||||
private int weight;
|
||||
|
||||
public Dog(int age, int weight) { // 构造函数
|
||||
this.age = age;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public int getAge() { // 函数或者方法
|
||||
return age;
|
||||
}
|
||||
|
||||
public int getWeigt() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() { //实现接口中定义的run()方法
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 容器
|
||||
|
||||
Java提供了一些现成的容器。容器可以理解为一些工具类,底层封装了各种数据结构。比如ArrayList底层就是数组,LinkedList底层就是链表,HashMap底层就是散列表等。这些容器我们可以拿来直接使用,不用从零开始开发,大大提高了编码的效率。具体的代码示例如下所示:
|
||||
|
||||
```
|
||||
public class DemoA {
|
||||
private ArrayList<User> users;
|
||||
|
||||
public void addUser(User user) {
|
||||
users.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 异常处理
|
||||
|
||||
Java提供了异常这种出错处理机制。我们可以指直接使用JDK提供的现成的异常类,也可以自定义异常。在Java中,我们通过关键字throw来抛出一个异常,通过throws声明函数抛出异常,通过try-catch-finally语句来捕获异常。代码示例如下所示:
|
||||
|
||||
```
|
||||
public class UserNotFoundException extends Exception { // 自定义一个异常
|
||||
public UserNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UserNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UserNotFoundException(String message, Throwable e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
public class UserService {
|
||||
private UserRepository userRepo;
|
||||
public UserService(UseRepository userRepo) {
|
||||
this.userRepo = userRepo;
|
||||
}
|
||||
|
||||
public User getUserById(long userId) throws UserNotFoundException {
|
||||
User user = userRepo.findUserById(userId);
|
||||
if (user == null) { // throw用来抛出异常
|
||||
throw new UserNotFoundException();//代码从此处返回
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
public class UserController {
|
||||
private UserService userService;
|
||||
public UserController(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
public User getUserById(long userId) {
|
||||
User user = null;
|
||||
try { //捕获异常
|
||||
user = userService.getUserById(userId);
|
||||
} catch (UserNotFoundException e) {
|
||||
System.out.println("User not found: " + userId);
|
||||
} finally { //不管异常会不会发生,finally包裹的语句块总会被执行
|
||||
System.out.println("I am always printed.");
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## package包
|
||||
|
||||
Java通过pacakge关键字来分门别类地组织类,通过import关键字来引入类或者package。具体的代码示例如下所示:
|
||||
|
||||
```
|
||||
/*class DemoA*/
|
||||
package com.xzg.cd; // 包名com.xzg.cd
|
||||
|
||||
public class DemoA {
|
||||
//...
|
||||
}
|
||||
|
||||
/*class DemoB*/
|
||||
package com.xzg.alg;
|
||||
|
||||
import java.util.HashMap; // Java工具包JDK中的类
|
||||
import java.util.Map;
|
||||
import com.xzg.cd.DemoA;
|
||||
|
||||
public class DemoB {
|
||||
//...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我带你一块学习了专栏中用到的所有的Java基本语法。不过,我希望你不要纠结于专栏或者某某书籍到底是用什么编程语言来写的。语言层面的东西完全不会限制我的讲解和你的理解。这就像我们读小说一样,不管它是用英语写的,还是中文写的,故事都可以同样精彩。而且,多了解一些Java语法,对于你今后阅读Java语言编写的书籍或者文档,也很有帮助。
|
||||
|
||||
实际上,我之前在Google工作的时候,大家都不太在意自己熟悉的是哪种编程语言,很多同事都是“现学现卖”,什么项目适合用什么语言就现学什么语言。除此之外,Google在招聘的时候,也不限定候选人一定要熟悉哪种编程语言,也很少问跟语言特性相关的问题。因为他们觉得,编程语言只是一个工具,对于一个有一定学习能力的人,学习一门编程语言并不是件难事。
|
||||
|
||||
除此之外,对于专栏中的代码示例,你也可以用你熟悉语言重新实现一遍,我相信这也是件很有意义的事情,也更能加深你对内容的理解。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
不同的公司开发使用的编程语言可能不一样,比如阿里一般都是用Java,今日头条用Go、C++比较多。在招聘上,这些公司都倾向于招聘熟悉相应编程语言的同学,毕竟熟练掌握一门语言也是要花不少时间的,而且用熟悉的编程语言来开发,肯定会更得心应手,更不容易出错。今天课堂讨论的话题有两个:
|
||||
|
||||
1. 分享一下你学习一门编程语言的经历,从入门到熟练掌握,大约花了多久的时间?有什么好的学习编程语言的方法?
|
||||
1. 在一个程序员的技术能力评价体系中,你觉得“熟练使用某种编程语言”所占的比重有多大?
|
||||
|
||||
欢迎在留言区写下你的想法,和同学一起交流和分享。如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
41
极客时间专栏/设计模式之美/不定期加餐/加餐七 | 基础学科的知识如何转化成实际的技术生产力?.md
Normal file
41
极客时间专栏/设计模式之美/不定期加餐/加餐七 | 基础学科的知识如何转化成实际的技术生产力?.md
Normal file
@@ -0,0 +1,41 @@
|
||||
<audio id="audio" title="加餐七 | 基础学科的知识如何转化成实际的技术生产力?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/1f/8d/1f784dec9713ec7c8c8bc540c5929f8d.mp3"></audio>
|
||||
|
||||
我相信,很多程序员都已经意识到基础知识的重要性,觉得要夯实基础,才能走得更远,但同时对于如何将基础知识转化成开发“生产力”仍然有些疑惑。所以,你可能看了很多基础的书籍,比如操作系统、组成原理、编译原理等,但还是觉得很迷茫,觉得在开发中用不上,起码在平时的CRUD业务开发中用不上。
|
||||
|
||||
实际上,这些基础的知识确实很难直接转化成开发“生产力”,但并不代表就没有用,今天,我们聊一聊为什么要学习基础学科知识,以及基础学科知识是如何转化成“生产力”的?
|
||||
|
||||
话不多说,让我们正式开始今天的内容吧!
|
||||
|
||||
## 没有直接用得上并不代表没有用
|
||||
|
||||
很多人反映,大学里学的很多基础学科都没用,工作之后都用不到。这种感觉是没错的。实际上,不只是基础学科,任何一门技术,能够经常用在工作中的那部分,都只占20%左右。这也符合我们常说的“二八法则”。
|
||||
|
||||
不知道你有没有听过这样一个故事:有一个人想要一个葫芦,于是他就种了一棵葫芦树。葫芦树叶子生了虫子,有人建议他赶紧杀杀虫。这个人却说,我要的是葫芦,管葫芦叶子干嘛。你可能会觉得,故事里的这个人的想法很荒唐,但其实我们也经常犯这种错误。比如说,类比到我们学知识,尽管常用的可能只有20%,但这并不代表我们只需要学习那20%就够了。要想得到那20%最有用的知识,我们需要学习很多周边知识做铺垫才行。
|
||||
|
||||
实际上,我多次强调,构建一个完善的知识体系、知识框架很重要。有些知识能直接转化成生产力,有些知识是为了学习其他知识充当“脚手架”。要想对应用层的知识学得比别人快、学得比别人透彻,铺垫性的基础学科知识就必不可少。
|
||||
|
||||
## 现在用不到并不代表以后用不到
|
||||
|
||||
你可能会说,我科班出身、基础扎实,但跟其他培训出身、只会使用框架干活的同事,在工作中的表现差不多啊,并没有感觉到有太多优势。实际上,如果只是做比较“低级”的CRUD工作,项目本身没有难度、没有挑战,那基础再扎实、技术再好,可能也都发挥不了你的优势,跟其他人拉不开差距。这就相当于跟大妈在菜市场比算账,你高数、微积分学得再好都没用,都比不上大妈算得快。但换个有挑战的工作环境、换个有难度的项目,又或者当你成为更高级别的工程师的时候,这些基础知识可能就会用得上了。
|
||||
|
||||
编程这件事本来就不难,随便培训3、5个月,就能上手干活。基础知识掌握得牢固,在工作初期,可能确实体现不出优势,毕竟大家都是从最基础、最没有技术含量的活干起的。在初期,那些框架、工具用得熟练的人,反倒更有优势,更容易出活、干得更快。但是,只会框架、工具的人,技术天花板是很低的,很多东西都只能学得一知半解、无法深入,很快就会遇到技术成长的瓶颈。相反,基础扎实的人更经得起时间的考验,技术研究的越深入,优势就会越明显。尽管基础知识短期内没法给你带来收益,但长远来看会持续发挥作用。
|
||||
|
||||
很多知识用不到,可能只是暂时用不到。书到用时方恨少。等到用到了,再去学习,就有点来不及了。基础学科知识学起来比较慢,所以,还是要在平时多下功夫,提前学扎实。学习基础学科的知识,不能太急功近利,只看重眼前的利益。
|
||||
|
||||
## 学了记不住并不代表就是白学了
|
||||
|
||||
对于知识的学习,特别是偏理论的基础学科知识的学习,有很多人说,学完之后,关上书啥都回忆不起来,学完不用,过不几天就忘得干干净净。其实,这些现象是很正常的。实际上,如果你一直追求“记住”“不忘”,那就还是应试教育的思维方式。
|
||||
|
||||
知识是用来解决问题的,而不是用来记忆考试的。说句实话,你可能不信,我在写这两个专栏的时候,写完后面的就忘了前面的,全部写完之后,基本就都忘得差不多了。不过,因为我在脑海里构建了整个的知识框架,并且大部分知识难点都已经被我攻克,所以,当工作中需要某块知识的时候,即便细节记不清了,我也只需要稍微查看一下资料,就能全部回忆起来。
|
||||
|
||||
除此之外,学习本身就是一种能力的锻炼。比如,我们在学习算法和设计模式这两个专栏的过程中,从最基础的自学能力、理解能力、逻辑思维能力,到时间空间复杂度分析能力、分析发现解决代码问题能力,都有锻炼到。所以,即便知识的细节忘记了,也并不妨碍我们编写出高性能、高质量的代码。这种对能力的锻炼,比单纯的知识记忆要有意义得多。
|
||||
|
||||
我之前还听过这样一个故事。给一个3岁的小孩每天读一篇希腊文写成的文章,坚持1年的时间。等小孩长大一点之后,拿之前文章里的内容再考他,他完全回忆不起来。但当他开始学习希腊文的时候,他比其他同龄人学得都要快。从这个故事中,我们可以发现,忘记并不等于就白学了,学习对于一个人的影响是潜移默化的。基础学科知识的学习更是如此。你要相信,它总有一天会发挥作用的 ,机会都是给有准备的人,我们要学会“延迟满足”。
|
||||
|
||||
总结一下,比起编程语言、框架、工具,基础学科知识确实很难直接转化成生产力,但它却是你构建整个“技能树”的根本,构建整个“知识大楼”的地基。基础掌握不牢,你对很多应用层技术的理解就会不够有深度,略知皮毛,只能做个技术熟练工。相反,基础扎实能让你学东西更快、更有深度、理解更透彻,也就间接地增强了你的开发能力。可以这么说,在一定程度上,基础知识本身,就是技术生产力。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
你觉得计算机的基础学科知识有哪些?聊一聊你对学习基础科学知识重要性的认识。
|
||||
|
||||
欢迎留言和我分享你的想法,如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
57
极客时间专栏/设计模式之美/不定期加餐/加餐三 | 聊一聊Google是如何做Code Review的.md
Normal file
57
极客时间专栏/设计模式之美/不定期加餐/加餐三 | 聊一聊Google是如何做Code Review的.md
Normal file
@@ -0,0 +1,57 @@
|
||||
<audio id="audio" title="加餐三 | 聊一聊Google是如何做Code Review的" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4a/7d/4ab40aa01b5ca924f48657a90b93267d.mp3"></audio>
|
||||
|
||||
100篇的正文已经全部结束了,估计你学得也有点累了吧?时隔这么久,正文终于结束了,从今天起,我们继续加餐内容。
|
||||
|
||||
跟正文内容相比,加餐内容我希望尽量轻松有趣,帮你拓展知识面,主要是课后的一些小分享,有的会以讲故事为主,但我也希望它能给你带来收获。如果能够引发你的思考和共鸣那就更好了。所以,我也希望你在留言区,多说说自己的感受和看法,多多与我互动。
|
||||
|
||||
话不多说,让我们正式开始今天加餐的内容吧!
|
||||
|
||||
## 为什么国内企业不重视Code Review?
|
||||
|
||||
在专栏[第80讲](https://time.geekbang.org/column/article/232687)中,我列举了Code Review的重要性,在项目中执行Code Review会带来哪些好处,以及如何克服一些常见的难题,在项目中启动Code Review等等。今天,我们想再继续这个话题,和你聊一下Code Review。不过,我刚才也说了,今天的内容会相对轻松一些,我会主要给你讲讲我在Google做Code Review的一些经验和心得。
|
||||
|
||||
我们都知道,Google在Code Review方面做得非常好,可以说是很多公司学习的榜样。从我个人的经历来说,我的技术成长相当大的一部分得益于当年在Google的Code Review。所以,我也希望更多的同行能意识到Code Review的重要性,能够在项目中推行Code Review,受益于Code Review。
|
||||
|
||||
但据我了解,国内的大部分公司都不怎么接受Code Review,在开发中,根本没有Code Review的流程。所以,我一直思考,到底是什么原因,导致这么优秀的一种开发模式,在国内的技术圈内没有被发扬光大。很多人会认为,主要原因是,项目工期紧,没时间做Code Review。我觉得这只是表面的原因,最根本的原因还是缺少技术文化传承。
|
||||
|
||||
我们知道,普遍而言,越是大公司里的工程师,技术能力会越强,技术影响力会越大。这些公司的工程师,即便跳槽去其他公司,一般都会担任核心成员或者Leader的角色。但是,在国内,即便像BAT这些输出有影响力工程师最多的一线公司,也没有很好地实践Code Review,相对应的,这些公司的工程师也就没有一手的Code Review的经验和感受,更无法了解到Code Review的好处,也更不会在团队、公司,甚至技术圈中去推行Code Review了。
|
||||
|
||||
打个不恰当的比方,这些一线互联网公司的工程师一直接受着“996”狼性文化价值观的熏陶,即便跳槽去其他公司,作为资深员工或者技术Leader,他们也会带领新的团队开始996,最终导致整个IT行业的加班氛围都很浓,不加班反倒会显得不正常。
|
||||
|
||||
用996作类比,如果BAT这些比较有技术影响力的公司,内部对Code Review很认可,执行得非常好,从这些公司往外输出的工程师,就会像我一样,大力传播Code Review。星星之火可以燎原,慢慢地,整个技术圈就会接受并且推行Code Review了。
|
||||
|
||||
实际上,据我所知,不只是我,只要是从Google跳槽出来的工程师,到了其他公司之后,都特别热衷于传播Code Review。而且,只要是被Google工程师带领过的团队,在开发流程中严格执行过Code Review的团队,对Code Review都无比认可。所以,我个人觉得,很多人不认可、不推行Code Review,最直接的原因还是没有经历过Code Review,没有有经验的人来带。
|
||||
|
||||
实际上,才开始接触Code Review的时候,我也比较反感。我刚毕业就进入了Google,在此之前,上学的时候,尽管也写了很多代码,也参与过一些垂直课题的研发,但是,那时候的开发只是为了完成功能,从来没有考虑过代码质量问题、代码设计问题,更别提Code Review了。现在想想,自己当时对Code Review的认知水平,跟现在很多国内工程师的认知其实是差不多的。
|
||||
|
||||
所以,在一开始进入Google的时候,对于Code Review我也是不怎么接受的。我第一次提交的代码不足百行,就被Leader Review出了n多问题,而且大部分问题都非常细节,比如变量的命名不够达意、注释不够规范、多了一个空行、少了一个空格之类的。对于这些琐碎的细节,我当时心里挺排斥的,心想:我是来“造火箭”的,为什么成天纠结于这些“拧螺丝”的事情呢?
|
||||
|
||||
现在回去想想,当时的想法真的挺幼稚的。
|
||||
|
||||
如果站在团队协作的角度来看,对于一个长期维护、多人参与、代码比较多的项目来说,代码的可读性、可维护性等与质量相关的问题,是非常重要的。所以,Code Review作为保证代码质量的最有效手段之一,也就非常有必要了。如此吹毛求疵地执行Code Review,看似非常极端,但也表明了公司强硬的态度、坚定的立场,就是要把Code Review执行彻底。这也是Code Review没有在Google流于形式的一个很大的原因。
|
||||
|
||||
在入职一段时间后,来来回回经过多次Code Review之后,我的代码质量整体提高了很多,被Review出的问题也越来越少了,我也切身地体会到Code Review的好处。因此,慢慢地,对这件事,我从排斥变得认可。与此同时,我也慢慢地开始Review别人的代码了。
|
||||
|
||||
## Google是如何进行Code Review的?
|
||||
|
||||
在Google,我们把每次提交的代码片段叫做一个CL,全称是Change List。它就相当于GitHub中的PR(Pull Request)。每个CL都要至少一个Owner和一个具有Readability的同事Approve,才能提交到代码仓库中。其中,Owner一般都是技术Leader或者项目负责人,而Readability是一个证书,表示你具有了写出可读代码、符合编码规范代码的能力。Readability会细化到每种编程语言,比如Java Readability、C++ Readability等。
|
||||
|
||||
如果你想申请某种语言的Readability,你就要提交一段至少包含100行代码、并且稍微有点复杂的CL给Readablity评审委员会。评审委员会会指派一个资深工程师Review你的代码,给你一些修改建议,然后,你需要根据修改建议对代码进行修改,再提交Review。这样来来回回几次之后,他觉得没问题了,就会给你颁发Readability。有了Readability之后,你的Review才真的能起到Approve的作用。当然,即便没有Readability,你对同事代码的Review本身也是有价值的。所以,并非只有Readability的人才能Review别人的代码。
|
||||
|
||||
在Google,每种编程语言都有对应的编码规范。但是,Code Review本身并没有统一的Check list。在Code Review的时候,除了编码规范可以参考之外,大部分都是靠工程师自身的经验来Review。不过,Review考虑的也无外乎这样几个常见的方面:代码结构是否合理、代码是否容易理解、业务是否正确、异常考虑是否全面、是否有隐藏的bug、线程是否安全、性能是否满足业务需求、是否符合编码规范等等。
|
||||
|
||||
Code Review听起来很复杂,要考虑的点很多,但实际上,等到你做熟练了之后,并不会花费太长的时间。一个CL从提交Review到最终合并到代码仓库,一般也就需要一天的时间。当然,对于一些比较大的CL、比较复杂的CL、有比较多争议的CL,以及一些新手的CL,可能会花费比较多的时间。
|
||||
|
||||
但是,大部分情况下,我们都不提倡太大的CL。太大的CL对代码审查者来说是很大的负担,Review过程会很慢,会导致代码迟迟提交不上去。
|
||||
|
||||
对于比较复杂的CL,我们一般建议要写好文档,或者通过类似Jira这样的项目工具,详细描述CL的前因后果、上下文背景。这样,代码审查者就能一眼看懂代码包含的设计意图。对于争议比较多的CL,我们建议直接当面沟通,这样也更加有效率。对于一些新手的CL,因为他们对编码规范等不熟练,可能来来回回要改好几次,才能满足要求,但这个过程是每个新人都要经历的,多改几次就好了。
|
||||
|
||||
实际上,Code Review并不神秘,如果你想了解更多关于Code Review的事情,可以去读一读Google官方公布的[Code Review最佳实践](https://google.github.io/eng-practices/review/reviewer/)。当然,如果有什么疑问,你也可以在留言区问我。
|
||||
|
||||
让国内大部分IT从业人士认识到Code Review的重要性,形成Code Review的技术文化,可能还需要一个漫长的时间。不过,我特别希望,你在学完专栏之后,能够意识到Code Review的重要性。有朝一日,当你成了领导,有了话语权、影响力之后,能够推动在团队、公司内进行Code Review,甚至为Code Review在整个国内技术圈中发扬光大贡献一份力量。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
你觉得为什么国内的大部分公司都不重视Code Review,在开发中都没有Code Review流程呢?你觉得如何把Code Review在国内技术圈中发扬光大呢?有什么好的建议吗?
|
||||
|
||||
欢迎留言和我分享你的想法,如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
49
极客时间专栏/设计模式之美/不定期加餐/加餐九 | 作为面试官或候选人,如何面试或回答设计模式问题?.md
Normal file
49
极客时间专栏/设计模式之美/不定期加餐/加餐九 | 作为面试官或候选人,如何面试或回答设计模式问题?.md
Normal file
@@ -0,0 +1,49 @@
|
||||
<audio id="audio" title="加餐九 | 作为面试官或候选人,如何面试或回答设计模式问题?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/48/04/486500f651600f15159f0362a53ce204.mp3"></audio>
|
||||
|
||||
在[加餐六](https://time.geekbang.org/column/article/255697)中,我们讲到,对于程序员的编程能力,我们一般从数据结构和算法、设计模式这两个方面来考察。加餐六重点讲到了如何考察数据结构和算法,今天,我们重点讲讲,如何考察设计模式。
|
||||
|
||||
除此之外,很多人反映,在面试中被问到设计模式问题的时候,一般都没有什么思路,基本都是想到哪说到哪。今天,我就总结一下回答设计模式相关面试题的一些套路,希望能让你在今后的面试中有章可循。
|
||||
|
||||
话不多说,让我们正式开始今天的内容吧!
|
||||
|
||||
## 作为面试官,如何面试设计模式问题?
|
||||
|
||||
有些面试官喜欢让候选人手写常用的设计模式,比如单例模式、工厂模式,以此来考察候选人对设计模式的掌握程度。实际上,对于比较常用的设计模式,盲写的要求并不过分,毕竟在开发中,徒手写个单例模式、工厂模式,也是常有的事情。
|
||||
|
||||
不过,这种偏向记忆的面试题目,实际上是一种应试考试的面试方式。一方面,它没有区分度,另一方面,候选人容易突击准备。这往往考察不出候选人真正的代码设计和实现能力。我们学习设计模式的初衷是提高代码质量。学习设计模式的重点,是掌握应用场景、能解决哪些问题,而非记忆定义、代码实现。所以,我面试时有个原则,不直接问记忆性问题和过于理论性问题。
|
||||
|
||||
筛选候选人就是筛选将来与你共事的人。我们面试的最终目的,还是希望能在短短的1小时内,粗略地看出候选人在今后工作中的表现。相对应的,在面试中考察候选人设计模式相关的知识,是看他在今后的项目中,能否写出易读、易扩展、易维护的高质量代码。
|
||||
|
||||
为了更准确地反映候选人在以后的工作中的表现,最好的面试方式是拿真实项目来考察,而且最好是候选人入职之后要参加的项目。当然,这个要求稍微有点高了。一般来讲,其实只要比较贴近真实项目就可以了。
|
||||
|
||||
**对设计和代码能力的考察,我一般有两种面试思路。**
|
||||
|
||||
第一种,给候选人一个功能需求,让他去做代码设计和实现,然后,基于他的代码实现,讨论代码的可读性、扩展性等代码质量方面的问题,然后让候选人继续优化,直到满意为止。第二种是,给候选人一段有质量问题的代码,让他去做Code Review,找出代码存在的问题,然后做代码重构。实际上,在我们的专栏中,很多文章中的例子,都符合刚刚两种面试思路。比如第[25](https://time.geekbang.org/column/article/179644)、[26](https://time.geekbang.org/column/article/179673)、[39](https://time.geekbang.org/column/article/193221)、[40](https://time.geekbang.org/column/article/193555)讲,[34](https://time.geekbang.org/column/article/190979)、[35](https://time.geekbang.org/column/article/191621)讲,[36](https://time.geekbang.org/column/article/191642)、[37](https://time.geekbang.org/column/article/191647)讲。你可以回过头去再看下。
|
||||
|
||||
这里我要重点强调一下,这种代码设计实现问题,本身没有标准答案,背景又过于复杂开放,如果只是丢给候选人回答,中间没有任何交流和引导,候选人很难抓住重点,展现出你心里期望的表现。所以,面试的过程切忌像笔试一样,一问一答单向沟通。相反,我们要把面试当做一场与未来同事的技术讨论,在讨论的过程中去感受候选人的技术实力。
|
||||
|
||||
当候选人写完代码之后,如果面试官一个问题都不提,然后就跳到其他面试题目,这种体验,不管是对候选人,还是面试官来说,都不是很好。相反,如果面试官能一语中的地提出设计中的缺陷,深入地跟候选人去讨论,这样一方面能给候选人充分发挥的机会,另一方面,也会赢来候选人对公司技术的认可。
|
||||
|
||||
## 作为候选人,如何回答设计模式问题?
|
||||
|
||||
刚刚我们从面试官的角度,讲解了如何面试设计模式相关的问题。现在,我们再从候选人的角度,讲下如何回答设计模式相关的问题。
|
||||
|
||||
刚刚我讲到,很多面试官喜欢让候选人手写常用设计模式的代码实现,虽然我本身比较讨厌这种面试方式,但保不齐有些面试官喜欢。应对这种面试问题,你只能面试前突击复习一下了。
|
||||
|
||||
刚刚我也讲到,我个人比较喜欢拿真实的功能需求和代码来面试候选人。一种面试题是给功能需求,让候选人写代码,另一种面试题是给代码,让候选人做Code Review和代码重构。针对这两种类型的面试题,我分别讲讲应该如何应对。
|
||||
|
||||
对于第一种面试题目,我们首先要明确需求。大部分情况下,面试官给出的功能需求,都是比较笼统、模糊的,这本身就是为了考察你的沟通能力、分析能力,是否能通过挖掘、假设、取舍,搞清楚具体的需求,梳理出可以执行落地的需求列表。
|
||||
|
||||
跟面试官确定好需求之后,就可以开始设计和实现了。前面也提到,面试的目的是考察候选人在真实项目开发中的表现。在工作中,我们都是从最简单的设计和实现方案做起,所以,回答这种设计面试题,也不要一下子就搞得太复杂,为了设计而设计,非得用些比较复杂的设计模式。
|
||||
|
||||
不过,在用最简单方式实现之后,你可以再讲一下,如何基于某某设计模式,进一步对代码进行解耦,进一步提高代码的扩展性。基于这种最简单的代码,再行讨论优化,这样跟面试官讨论起来,也会更加言之有物。这也能体现你的代码演进思维,以及具体问题具体分析的能力。更加详细的回答套路,你可以参看第[13](https://time.geekbang.org/column/article/171760)、[14](https://time.geekbang.org/column/article/171767)讲。
|
||||
|
||||
比起第一种题目,第二种面试题目会更加明确、具体。你就把它当作一次真实的Code Review来回答就好了。对于如何进行Code Review,你可以回过头去再看下[第34讲](https://time.geekbang.org/column/article/190979),里面有罗列一些Code Review的checklist。
|
||||
|
||||
实际上,回答这种没有固定答案的开放性问题,你要跟面试官多问多沟通,不要觉得问多了就是自己理解能力不够,就会导致面试官反感。相反,面试官不仅不会反感,反倒会觉得你是一个思路开阔、有想法的人。如果你只是自己闷头写代码,面试官有可能会觉得你不善沟通。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
作为面试官,你是如何考察候选人的代码设计和实现能力的呢?作为候选人,你遇到过最想吐槽的设计模式相关的面试题是什么样的?
|
||||
|
||||
欢迎留言和我分享,如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
75
极客时间专栏/设计模式之美/不定期加餐/加餐二 | 设计模式、重构、编程规范等相关书籍推荐.md
Normal file
75
极客时间专栏/设计模式之美/不定期加餐/加餐二 | 设计模式、重构、编程规范等相关书籍推荐.md
Normal file
@@ -0,0 +1,75 @@
|
||||
<audio id="audio" title="加餐二 | 设计模式、重构、编程规范等相关书籍推荐" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e4/17/e48d8826dd25f67143ce4c74d53e4117.mp3"></audio>
|
||||
|
||||
有关设计模式、重构、编程规范等的经典书籍很多,有很多你应该已经听说过、甚至看过。今天,我就结合我的经验,对这些书籍进行一个整理和点评。你可以据此来选择适合你的书籍,结合着专栏一块儿来学习,这样学习效果会更好。
|
||||
|
||||
### 1.《设计模式》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/1d/ab/1deb18c033909ca544195435696e1aab.png" alt="">
|
||||
|
||||
学习设计模式,不知道GoF的《设计模式》估计会被人笑话的。这本书是设计模式的开山之作。经典的23种设计模式最早就诞生于这本书。这本书很薄,只有200多页。但是,我个人觉得,这本书还是比较晦涩难懂的。回想起来,我在读大学的时候,就读过几遍此书,但每次都是一知半解,读一遍忘一遍。如果你是设计模式的初学者,不建议从这本书看起。如果你对设计模式已经有所了解,还是蛮推荐你去看下这本经典书的。
|
||||
|
||||
### 2.《Head First设计模式》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/32/2d/32bf8494047fbdcf4fb1acb0cb1b4f2d.png" alt="">
|
||||
|
||||
如果说刚刚提到的《设计模式》是最经典的设计模式书籍,那《Head First设计模式》就是最通俗易懂的。这本书看起来很厚,但每页里的内容并没有那么密集。这本书最大的特点就是口语化、场景化。整本书围绕几个人的对话来展开。里面的例子比较脱离实践,但比较容易看懂。如果你之前对设计模式没有太多了解,这本书无疑是你的首选。
|
||||
|
||||
### 3.《Java与模式》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/69/0e/6996f3e8c094051d44e94bbbbb94f60e.png" alt="">
|
||||
|
||||
这本书可能并没有那么多人知道,出版的时间也比较久远,而且是跟Java语言比较紧耦合,里面很多例子都是在剖析JDK里的设计模式。不过这可能是最贴近实战的一本设计模式书籍了,里面包含的实战案例,应该是目前我读过的设计模式书籍中最多的。不过,我个人觉得文笔稍微有些晦涩,有些内容可能要反复读一下才能理解。如果你熟悉Java语言,在我推荐的其他书籍都看完的前提下,没事的时候可以看看这本书。
|
||||
|
||||
### 4.《深入浅出面向对象分析与设计》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/25/a4/25ef700c48d79b68b994ebab67fb8fa4.png" alt="">
|
||||
|
||||
这本书跟《Head Frist设计模式》都是出自“Head First”系列,写作风格也相同,不过也略显啰嗦。从书名中我们就可以看出,这本书主要是讲面向对象分析和设计。实际上,很多关于面向对象分析和设计书籍都侧重讲UML,讲得真的好的书籍却并不多。除此之外,我觉得面向对象分析和设计的理论知识并不多,关键还是实践。所以,如果你工作比较忙,看我的专栏就足够了。如果你特别想系统地学一下的话,看看这本书也完全足够了。
|
||||
|
||||
### 5.《代码大全》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/66/a8/6612c56e4d5f1d67ecd678d9810938a8.png" alt="">
|
||||
|
||||
这是一本有近千页大部头。不过,这本书讲的东西很杂,不是很聚焦,涵盖了软件开发方法、编程技巧、编码规范、重构等等诸多方面。书如其名,这本书其实更像是软件开发方面的工具类的百科全书。在读过我推荐的其他书籍之后,这本书快速地翻一遍就可以了。
|
||||
|
||||
### 6.《代码整洁之道》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/09/47/09063c31913414e8c93fb5469fea7f47.png" alt="">
|
||||
|
||||
这本书非常值得推荐。它主要是讲编码规范,除此之外,还讲到了一些有关设计原则、单元测试、并发编程的东西。因为内容比较侧重编码规范,所以每个知识点都非常明确,能够很容易落地指导你的开发,能够立竿见影地改善你的代码质量。
|
||||
|
||||
### 7.《编写可读代码的艺术》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a0/91/a07e5ed7549e272055c0730821431491.png" alt="">
|
||||
|
||||
从书名我们就可以看出,本书主要是教你如何写出可读性好的代码,实际上也是在讲比较偏向细节的编码规范。它的内容跟《代码整洁之道》有部分重复,但是推荐你也看一下。《代码整洁之道》《代码大全》《编写可读代码的艺术》三本书是讲编码规范方面的三大著作。看完这三本书,基本的编码规范你就掌握全了。
|
||||
|
||||
### 8.《重构》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ac/02/ac08ba290bdb1081f5f0efa1deab2502.png" alt="">
|
||||
|
||||
这本书的作者是Martin Fowler,他写了很多跟软件开发相关的经典书籍。这本《重构》无疑是他最经典的作品。书中讲到了诸多代码的坏味道,并且给出了相应的改进方法,是作者一手开发经验的总结输出。我推荐本书的原因倒不是说书里面的内容有多真知灼见、让人耳目一新,而是这本书的内容总结得非常全面,很适合帮你去做一个整体、系统的梳理。
|
||||
|
||||
### 9.《重构与模式》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/01/d1/011c721627e3fa1c7b0ea5230a42f9d1.png" alt="">
|
||||
|
||||
我们之前讲过,设计模式一个重要的应用场景就是代码重构。这本书主要讲如何应用设计模式来重构代码,改善代码设计。如果说《重构》是讲如何做低层次的重构,那这本书就是在讲如何做高层次的重构,也就是我们专栏中要讲到的小重构和大重构。这本书非常推荐你读一下,它能让你知道,为什么要用设计模式,如何有的放矢地应用设计模式,而非只是无痛呻吟。
|
||||
|
||||
### 10.《修改代码的艺术》
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c2/f7/c25b98e63f7fef3f8c12a972b2ac62f7.png" alt="">
|
||||
|
||||
如果说《重构》那本书是从编码规范上来讲如何重构,《重构和模式》是从设计模式上来讲如何重构,那这本书可以粗鲁地归为从面向对象设计思想、设计原则上来讲重构。除此之外,这本书更偏向于教你如何来重构,不像上面两本书那样聚焦,所以是一个很好的补充。这三本书合起来称为重构“三部曲”。这本书的示例代码是用C++写的,不过也很容易看懂,很推荐你读一下。
|
||||
|
||||
## 总结
|
||||
|
||||
今天的加餐内容就这些,我来稍微总结回顾一下推荐的书籍。这些书我基本上都看过,并且很多都看了好几遍,如果你时间宽裕,想要真正掌握写出优秀代码的能力,非常推荐你认真看一下,相信会对你有非常大的帮助。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/5d/41/5dd01ae60a6b904756492f4aecd4d041.png" alt="">
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
我罗列的书籍中,你读过哪几本?哪一本或者几本对你影响最大?除了我罗列的这些,还有哪些书籍你觉得值得推荐?
|
||||
|
||||
欢迎在留言区写下你的答案,和同学一起交流和分享。如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
47
极客时间专栏/设计模式之美/不定期加餐/加餐五 | 听一听小争哥对Google工程师文化的解读.md
Normal file
47
极客时间专栏/设计模式之美/不定期加餐/加餐五 | 听一听小争哥对Google工程师文化的解读.md
Normal file
@@ -0,0 +1,47 @@
|
||||
<audio id="audio" title="加餐五 | 听一听小争哥对Google工程师文化的解读" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/07/a7/07b0c334e37be05d3b72d64330f6a3a7.mp3"></audio>
|
||||
|
||||
在技术圈里,我们经常听到“工程师文化”这个词。很多公司的HR、管理层都热衷于研究Google、Facebook、Netflix等大公司的文化,希望能打造成和它们一样优秀的工程师文化。
|
||||
|
||||
过去几年,好几位朋友也问过我,怎么才能打造跟Google一样的工程师文化?实际上回答这个问题之前,我们先要搞清楚,到底什么是工程师文化,Google的工程师文化是什么。今天,我就针对这三个问题,聊一聊我对Google工程师文化的理解。
|
||||
|
||||
话不多说,让我们正式开始今天的内容吧!
|
||||
|
||||
## 什么是工程师文化?
|
||||
|
||||
我觉得,很多人对“工程师文化”这个词有误解,以为它是一个描述词,甚至是褒义词,表示工程师占主导的公司文化。实际上,我觉得,“工程师文化”是一个名词,你可以类比饮食文化、穿衣文化来理解,它指的是技术团队的价值观(这个团队最看重什么,比如效率、质量等等),更直白点讲就是做事风格。
|
||||
|
||||
每个技术团队都有自己的工程师文化,不管这种文化有没有被书面或者口头上表达出来。不过,工程师文化包含很多方面,就像人的价值观一样,有爱情观、金钱观、人生观等等。所以,它很难用一句话来总结。但因为某些公司的工程师文化中的某些方面比较突出、比较有个性,我们常用这些特殊点来“以偏概全”地代指,比如某些公司的工程师文化是“狼性文化”“奋斗文化”“996文化”“PPT文化”“养老院文化”等等。
|
||||
|
||||
工程师文化会潜移默化地影响团队中的每个人,不认同这种文化的人会选择离开,最终留下的人价值观都会趋同。形成好的工程师文化的主要目的是,公司希望通过文化而非管理和流程,来驱动团队中的每个人,步调一致地工作和交流。
|
||||
|
||||
## Google的工程师文化是什么?
|
||||
|
||||
为什么很多公司都要学习Google的工程师文化呢?我觉得主要原因是,Google凝聚了很多优秀的人才,并且往外输出了很多优秀的技术和产品,侧面上证明了Google工程师文化的优秀,所以,很多公司也希望能借鉴Google的工程师文化,把自己的技术团队也打造成像Google的技术团队那样,执行力强、工作效率高、创新能力强的优秀团队。
|
||||
|
||||
目标很明确,就是要打造优秀的技术团队。但要达成这样的目标,首先要理解Google的工程师文化是什么样的。
|
||||
|
||||
实际上,不同的人对Google工程师文化的理解是不同的。有些人把Google的工程师文化理解为,重视代码质量、重视效率、工匠精神、技术驱动、扁平化管理等等,还有些人甚至理解为,昂贵的电脑和座椅、按摩和报销等各种福利、少开会不加班、免费一日三餐、无限供应的零食等等。
|
||||
|
||||
当然,上面提到的这些在Google都是真实存在的。不过,这都是表象。如果只是学这些表面上的东西,“抄不到”Google工程师文化的本质和精髓,我们也就很难打造成像Google一样的工程师文化了。**那Google工程师文化的本质是什么呢?我觉得,如果用一句话来描述的话,那就应该是“尖子生”文化。**
|
||||
|
||||
这里所说的“尖子生”,跟我们上学时候的“尖子生”是一个意思。不知道你学校里有没有“尖子生班”?或者你有没有在“尖子生班”待过?一般来说,“尖子生班”的同学在各个方面都表现得非常优秀,而且,这种优秀不仅仅体现在学习上面,其他非学习相关的活动也表现得很好。最值得一提的是,这种优秀是自发形成的,不需要老师的督促和刻意的培养。
|
||||
|
||||
类比到Google的工程师文化,Google可以算作工程师中的“尖子生班”。我们知道,Google用人条件很苛刻、招聘要求很高,身边的同事个个都具有光鲜的背景和履历,称为”尖子生“不足为过。这些最顶尖的工程师聚集在一起,不出意外的情况下,稍加引导,就能形成优秀的工程师文化,高产出、高效率、高创新是必然的。至于前面提到的其他方面,比如重视代码质量、工匠精神、重视效率等等,更是不在话下。
|
||||
|
||||
## 如何打造像Google一样的工程师文化?
|
||||
|
||||
表面上的东西很容易“借鉴”,比如为员工购买昂贵的电脑和座椅,但要想打造像Google一样的工程师文化,本质上还是要在”人“上下功夫。招聘最优秀的人才,给足钱、自由和尊重,这些人必然就会发挥最大的价值。
|
||||
|
||||
乔布斯曾经说过,A类工程师招聘A类工程师,B类工程师只能招聘C类工程师。之所以这么说,是因为A类工程师有足够的能力来正确地辨别A、B、C类工程师,有足够的自信去接纳跟自己一样优秀、甚至更加优秀的人才。所以,为了严把人才入口,我们一定要让公司内最优秀的工程师来负责招聘。
|
||||
|
||||
当然,并不是每个公司都可以像Google这样,有足够的背景去吸引最优秀的工程师、有足够的投入去招聘最优秀的工程师。但是,我们仍然可以招聘一小撮足够优秀的工程师,让这小部分工程师影响公司里更多的人,带动起我们想要的工程师文化。这就好比,打造一个全是尖子生的尖子班很难,但我们可以在班级里找几个学习榜样,让这一小撮榜样带动起整个班级的学习氛围。
|
||||
|
||||
除了在招聘上下功夫,在人才培养上,我们要尽可能留住最符合公司工程师文化的员工,让他们在公司内部有好的职场发展,避免劣币驱逐良币。比如,我们的工程师文化是“马屁文化”,如果你是领导,就要让经常拍你马屁的人升职加薪,慢慢地其他人就会效仿,不接受的人就会离职,“马屁文化”就逐渐形成了。
|
||||
|
||||
实际上,我们也不一定非得追求将公司的工程师文化,打造成像Google的一样,毕竟每个公司都有自己的特点,都有自己的发展阶段,完全照抄也不现实。我个人觉得,相对于外企来说,国内企业中跟“人”相关的文化,普遍做得不是太让人满意,比如,以人为本,以结果为导向,讨论就事论事,奖惩公开透明,不搞上下级关系等等,先把这些跟”人“相关的文化搞好,跟”技术“相关的文化,比如重视代码质量、工匠精神、追求效率等等,搞起来就相对容易多了。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
聊一聊你最喜欢的工程师文化是什么样子的?最讨厌的工程师文化是什么样子的?
|
||||
|
||||
欢迎留言和我分享你的想法。如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
57
极客时间专栏/设计模式之美/不定期加餐/加餐八 | 程序员怎么才能让自己走得更高、更远?.md
Normal file
57
极客时间专栏/设计模式之美/不定期加餐/加餐八 | 程序员怎么才能让自己走得更高、更远?.md
Normal file
@@ -0,0 +1,57 @@
|
||||
<audio id="audio" title="加餐八 | 程序员怎么才能让自己走得更高、更远?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d9/7c/d9yyef71ff98d628793c3a1c2103eb7c.mp3"></audio>
|
||||
|
||||
大学就像一个笼子,跑得快的人拖着笼子跑,跑得慢的人被笼子拖着跑,他们之间最大的差距,顶多只有笼子的长度那么大。但等到一毕业,笼门一打开 ,跑得快的人很快就把跑得慢的远远甩在后面。有人不到30岁就升到了阿里P8,有人35岁了还为拿个P7 Offer在拼命。
|
||||
|
||||
为什么几乎同样的起点、差不多的资质,有些人在职场发展得这么好,一路顺风顺水,而有些人却总是觉得怀才不遇,领导不行?今天,我们就来聊一聊,程序员怎么才能让自己走得更高、更远?
|
||||
|
||||
话不多说,让我们正式开始今天的内容吧!
|
||||
|
||||
## 技术、业务、能力是立命之本
|
||||
|
||||
我觉得,不管哪个行业,混得好的人都要有两把刷子。对于程序员来说,我觉得这两把刷子包括技术、业务和能力这三方面。很多人担心出现35岁中年危机,觉得自己能干的事,刚毕业一两年的人也能干得了。我觉得这主要还是因为没有在这三个方面积累出竞争壁垒。
|
||||
|
||||
**我觉得,技术方面的竞争壁垒主要来自,在一个细分技术领域长期****、****深入的积累。**
|
||||
|
||||
如果要想在技术上形成壁垒,我们就要从事一些有技术难度、技术挑战的岗位,比如基础架构、中间件、数据库等偏底层的开发,又或者是人工智能算法等入行门槛比较高的细分领域。在这些领域,你需要较长时间的经验积累,才能成为这一领域的专家,别人无法在短期内超过你,这就是技术竞争壁垒。
|
||||
|
||||
**对于大部分业务开发工程师来说,很多人平时都是使用框架、工具,翻译业务代码,工作没有太多技术含量,技术上可能很难形成竞争壁垒。这个时候,你也不用苦恼,我们在业务上也同样可以形成竞争壁垒。**
|
||||
|
||||
实际上,技术驱动的公司很少,即便像Google这样公认的技术驱动的公司,里面90%的项目都是业务、产品驱动的。真正高精尖的技术也只集中在某一小撮项目中。你可能会说,Google的很多产品的用户、访问量都很高,这些高性能、高并发的要求不是很考验程序员的技术吗?实际上,这些有挑战的技术问题,都是比较有共性的,大部分都通过底层系统解决了,比如MapReduce、BigTable、GFS等。业务研发工程师只需要恰当地使用这些高精尖的系统来实现业务就可以了。
|
||||
|
||||
在业务驱动的项目中,特别是一些业务比较复杂的下项目,比如,金融系统、银行系统、财务系统、清结算系统、物流系统等,我们还可以积累一些业务壁垒。如果你之前的工作都是从事偏向业务系统的开发,靠技术只能面到阿里P7这个层级。如果想面到阿里的P8、P9,靠的就不仅仅只是技术了,还需要对某个业务的深入积累。实际上,很多领导之所以能做领导,不是技术牛逼,而是对业务熟悉。
|
||||
|
||||
**不过,并不是所有的业务系统开发,业务都有足够的复杂度,可以让你积累竞争壁垒。对于技术没有太大挑战,业务也不复杂的项目开发,我们可以多积累自己的能力。**
|
||||
|
||||
这里所说的能力,指的是成事能力、解决问题的能力。实际上,很多问题的解决,即便是技术问题的解决,靠的都不是技术,而是一个人最基本的解决问题的能力。这其中就包括分析总结能力、逻辑思维能力、沟通协调能力、自我驱动能力等等。
|
||||
|
||||
比起固定的技术和业务知识,这种成事能力、解决问题的能力,我觉得对于混职场来说可能更加重要。在职场中,职位越高,这种成事能力就越重要,毕竟企业最终还是看结果的,而不是看你技术有多好。
|
||||
|
||||
## 学历、项目、履历是入场门票
|
||||
|
||||
经常听人吐槽,面试造火箭,入职拧螺丝。也经常听人抱怨,有些公司太看重学历,因为学历拒掉了我,却招了一个技术比我差的前同事,仅仅因为他是985名校毕业。
|
||||
|
||||
现在,学IT的人越来越多,招聘市场也逐渐从卖家市场变成了买家市场。很多公司开始提高招人要求,不仅加大面试难度,为了提高招聘效率,还会在学历、过往是否有大公司经历等方面,先过滤掉一批候选人。
|
||||
|
||||
你可能会说,学历高的不一定技术好,学历低的也有技术很好的。你说得没错。但一般来讲,虽然都说做技术学历不重要,但好学校的学生对计算机基础知识掌握得更好,学习能力、逻辑思维更强,相对要聪明一些,而且在工作中,我们也发现,成绩好的同学往往在工作中表现出很强的执行力和快速交付能力,在工作中的表现普遍也更优秀。站在公司整体招聘的角度来说,通过学历来过滤候选人是一个比较高效的手段,毕竟公司也不在乎因此漏掉一两个优秀的候选人,或者错招一两个不优秀的候选人。
|
||||
|
||||
实际上,比起短短的1个小时的面试,我个人也更倾向于通过学历、项目(项目经历是否有技术难度)、履历(是否有知名公司的工作经历、以及职位高低),这些过去的能够证明能力的经历来判断一个候选人。特别是对于一些中高端的岗位,好的学历、项目、履历基本上有碾压性的优势。我自己做面试官多年,基本上在看完候选人的简历之后,对符不符合我们招聘要求,心里就有个八九不离十的判断了。在面试开始的前10分钟,我基本上已经决定要不要录用他了。后面的面试只是为了进一步证实自己刚刚的决定而已。
|
||||
|
||||
如果说技术、业务、能力是程序员的立命之本,它们决定了你能不能在职场这场比赛中胜出,那学历、项目、履历就是入场门票,决定了你可以选择哪个比赛赛道,是Google、Facebook,还是BAT,又或者是完全不知名的小公司。
|
||||
|
||||
所以,在夯实技术、业务、能力的同时,你也要学会“面向简历打工”“面向跳槽打工”,提前做一些职业规划,把自己的履历弄好看点,比如,学历太低的就去考个好点的学历,在公司内部努力去选择做一些有技术含量的项目,跳槽去一些知名点的互联网公司等等。
|
||||
|
||||
## 不要让职场软技能成为短板
|
||||
|
||||
在职场中,我常常听到有人抱怨说,旁边的同事明明技术一般,却升到很高的职位,而自己技术很好,却发展一般。实际上,怀才不遇大多数都是因为忽视了职场软技能。这些人的特点大多是性格耿直、脾气暴躁、眼里容不了沙子、斗天斗地斗空气。而且,大部分情况下,他们都会觉得自己做得很好,领导不识货,同事都没他强。
|
||||
|
||||
职场不是学校,影响你向上发展的因素很多,肯定不是单靠技术,所以,学生思维要不得。在上学的时候,学得好坏,一份试卷见分晓。要想成绩好,闷头学就行了,你也不需要什么团队合作。但是,毕业之后,技术的好坏、代码写得好坏、活干得好坏,就没有那么容易客观评价、量化评价了。所以,这就会出现你自己觉得工作做得很好,而领导却不这么认为的情况。
|
||||
|
||||
而且,技术好其实并不代表贡献多。我也见过很多技术好的人,比较爱自嗨,成天鼓捣些高精尖的技术。实际上,不管是从短期还是长期看,这些技术都没有给团队、公司带来收益。当然,我也并不是完全摒弃个人成长,让你完全奉献给公司。我只是觉得,作为员工,要学会跟公司共同成长。只有你的成长为公司的成长贡献了力量,为公司、为领导解决了问题,公司才愿意为你的付出买单,你才有升职加薪的机会。
|
||||
|
||||
总的来讲,要想职场混得好,一些必须的沟通、协作、总结汇报等软技能还是不能忽视的,当然,我也不是推崇,纯靠“耍手段”上位。我只是觉得,这方面起码不能成为你的短板,不要让这些非技术、非能力的因素,阻碍了你职场的发展。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
作为“前浪”的你,还有哪些经验、教训,可以分享给“后浪”,让“后浪”在职场发展上少走些弯路呢?又或者作为“后浪”的你,有哪些职场的疑惑、迷茫,想向“前浪”请教呢?
|
||||
|
||||
可以在留言区说一说。如果有收获,也欢迎你把今天的内容分享给你的朋友。
|
||||
45
极客时间专栏/设计模式之美/不定期加餐/加餐六 | 什么才是所谓的编程能力?如何考察一个人的编程能力?.md
Normal file
45
极客时间专栏/设计模式之美/不定期加餐/加餐六 | 什么才是所谓的编程能力?如何考察一个人的编程能力?.md
Normal file
@@ -0,0 +1,45 @@
|
||||
<audio id="audio" title="加餐六 | 什么才是所谓的编程能力?如何考察一个人的编程能力?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/1f/1d/1fbdd7f0b0a0f92ce374fe5bf145361d.mp3"></audio>
|
||||
|
||||
在招聘要求里,我们经常看到“要求候选人有扎实的编程能力”。在面试反馈中,我们也经常看到面试官用“编程能力很强”来评价候选人。那到底什么是编程能力呢?如何考察一个人的编程能力呢?又如何提高编程能力呢?今天,我们就编程能力这个话题展开聊一聊。
|
||||
|
||||
话不多说,让我们正式开始今天的内容吧!
|
||||
|
||||
## 什么是编程能力?
|
||||
|
||||
所谓编程能力,指的是把“逻辑”(或者说“功能”“业务”)翻译成代码的能力。所谓编程能力强,指的是,不仅能编写正确的代码,而且编写代码的速度很快,写出来的代码bug很少、性能很好、质量很高。
|
||||
|
||||
更加具体点讲,一个编程能力强的人,能熟练使用编程语言、开发类库等工具,思路清晰,面对复杂的逻辑,能够编写出bug free的代码,能够合理地利用数据结构和算法编写高效的代码,能够灵活地使用设计思想、原则和模式,编写易读、易扩展、易维护、可复用的高质量代码。
|
||||
|
||||
相反,一个编程能力差的人,往往逻辑思维能力比较差,面对复杂的逻辑,编写代码的速度很慢,而且容易考虑不周,写出来的代码bug很多,更没有性能意识,不懂得如何分析代码的时间复杂度、空间复杂度,更不懂得如何借助现成的数据结构和算法来优化代码性能。除此之外,写代码的时候,几乎不考虑代码的可读性、可扩展性等质量问题,只追求能运行就可以。
|
||||
|
||||
## 如何考察编程能力?
|
||||
|
||||
前面我给出了编程能力的简单的定义,从定义中,我们能很清楚地了解,考察一个人的编程能力的几个要素。总结一下,我觉得主要包含这样三个方面:编程语言,数据结构和算法,设计思想、原则和模式。
|
||||
|
||||
考察编程能力,那就离不开写代码。所以,在面试中,我一般都会出道编程题,让候选人写段代码看看,也就是所谓的“白板编程”。白板编程在外企面试中比较流行,国内有些候选人不怎么能接受,特别是工作年限比较长的候选人,一听说要写个代码,就觉得这是在“羞辱”他,觉得不应该从这么基础的东西考起。
|
||||
|
||||
不过从我多年的面试经验来看,这种拒绝写代码的“大龄码农”,满嘴“架构、高可用、高并发、分布式”,往往代码写得惨不忍睹。所以,只要是应聘一线技术研发岗的候选人,不管是资深工程师、架构师,还是技术Leader,我都会要求他现场写一段代码。因为这是最直接、最有效检验这个人基本技术素养的途径。
|
||||
|
||||
一般来讲,编程语言都可以快速掌握,所以,我一般都不会把它拎出来单独考察,只是顺带着考察一下就可以了。我会重点考察后两个方面:数据结构和算法,设计思想、原则和模式。但是,要想设计一个题目,既能考察到这两方面的知识,又能在不到1个小时的面试时间内完成,还是挺难的。所以,对于这两个方面,我一般都分开来考察。我今天重点讲对数据结构和算法的考察,对于设计思想原则和模式的考察,我后面有文章专门来讲。
|
||||
|
||||
对于数据结构和算法的考察,我个人不建议面试题目涉及需要记忆的算法,比如被很多人诟病的面试题:写个快排。没有人会天天背诵快排算法,候选人写不出来也理所应当。如果我们换个问法,比如给候选人讲一下快排的思想,然后让候选人用代码实现,测试候选人的代码翻译能力,我觉得这反倒是一个比较好的面试题。除此之外,我也不建议面试题目涉及特殊解题方法或技巧,比如需要用到线段树、并查集等高级数据结构。毕竟大家在工作中不常用到这些知识,不知道或者忘记了我觉得也很正常。
|
||||
|
||||
所以,那种不依赖很强的算法背景和特殊的解题技巧的题目,比较适合用来面试。比如像下面这样的面试题就比较好:“写一个函数将IPv4地址字符串(仅包含数字、点、空格)转化成32位整数。另外,数字和点之间的空格是合法的,其他情况均为非法地址,要求输出合法地址的32位整型结果。”
|
||||
|
||||
我觉得这种题目是比较公平的,对于没有刷过题的人来说也很友好,因为它纯粹是在考察候选人的基本编程素质:逻辑思维是否清晰,细节是否考虑全面,是否能写出bug free的代码,是否有计算机思维,会关注时间空间复杂度等。
|
||||
|
||||
## 如何提高编程能力?
|
||||
|
||||
刚刚我们讲了什么是编程能力,如何考察编程能力,现在,我们讲下如何提高编程能力。实际上,我的两个专栏《数据结构与算法之美》《设计模式之美》,就是为了提高你的编程能力而设计的。《数据结构与算法之美》专栏教你如何写出高性能代码,《设计模式之美》专栏教你如何编写易读、易扩展、易维护的高质量代码。
|
||||
|
||||
方向很明确,但是要真的提高编程能力,光学不练肯定是不行的。
|
||||
|
||||
对于数据结构和算法的练习,我们推荐你多刷LeetCode上的题目。刷题不仅仅能加强你对数据结构和算法的掌握,还能锻炼你的逻辑思维能力、写出bug free代码的能力、快速实现复杂逻辑的能力,也能锻炼你的性能意识。所以,刷题不只是为了面试,刷题对这些能力的锻炼,都有助于你在平时的业务开发中写出好的代码。
|
||||
|
||||
对于设计思想原则和模式的练习,它就不像算法练习那样有现成的题库了。所以,要在平时的开发中进行练习。比如,拿到一个功能需求的时候,我们先去思考一下如何设计,而不是上来就写代码。写代码时,我们时刻思考代码是否遵循了经典的设计思想、设计原则,比如是否足够可扩展、是否满足SOLID原则、可读性如何等等。写完代码之后,我们再思考一下,代码是否有进一步优化的空间。做Code Review的时候,看到别人的优秀的代码,我们就去思考一下,有哪些值得借鉴的地方。总之,在平时的开发中,我们要刻意地去做这种跟代码质量、代码设计相关的思考训练。时间长了,这种思考就能成为习惯、本能反应,慢慢地,你的代码能力也就不自觉地提高了。这一部分内容你可以回过头去再看下第100篇,我们前面有非常详细的讲解。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
实际上,不管从事什么行业,要积累的东西都可以分为“变”与“不变”两类。“不变”的是内功,“变”的是招式。我们要善于发现、持续积累那种“不变”的能力,而不是要去盲目追逐一直都在“变”的招式。除了编程能力之外,在IT技术领域,你觉得还有哪些不变的内功?
|
||||
|
||||
欢迎留言和我分享你的想法。如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
43
极客时间专栏/设计模式之美/不定期加餐/加餐十 | 如何接手一坨烂业务代码?如何在烂业务代码中成长?.md
Normal file
43
极客时间专栏/设计模式之美/不定期加餐/加餐十 | 如何接手一坨烂业务代码?如何在烂业务代码中成长?.md
Normal file
@@ -0,0 +1,43 @@
|
||||
<audio id="audio" title="加餐十 | 如何接手一坨烂业务代码?如何在烂业务代码中成长?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/00/19/00390a19dfddc2015ed3a96063928a19.mp3"></audio>
|
||||
|
||||
在我们的职业生涯中,很少有机会可以从零开发一个项目,大部分都是接手别人的代码继续开发,或者做些维护性开发。而且,对于大部分业务系统来说,因为业务导向,需求倒逼,开发工期紧,团队往往都不是很重视代码质量,快速上线是第一要务。所以,很多团队的代码质量一般都不怎么高。埋坑无数、没有文档、也没有注释,代码读不懂、也不敢改,这对于新人来说,会非常苦恼。今天,我们就聊一聊,如何接手一坨烂业务代码,以及如在烂业务代码中的成长?
|
||||
|
||||
话不多说,让我们正式开始今天的内容吧!
|
||||
|
||||
## 如何接手一坨烂业务代码?
|
||||
|
||||
在我过去10年的工作经历中,我接手过很多个代码质量比较烂的项目。这些项目都有很多共性的特点,大部分都已经维护了两三年,甚至五六年之久,代码量很大,有十几万行以上,并且大部分代码都没有任何注释,业务功能非常庞杂,也没有对应的业务文档。
|
||||
|
||||
除此之外,代码中还充斥着各种临时解决方案(Workaround)、硬编码(Hard Code)、遗留代码(Legacy Code),还有很多匪夷所思的设计。对于有些设计来说,我们称之为“反人类”设计或者“故意挖坑”,一点都不为过。如果没有老员工给你解释上下文,你万万都想不到它为什么这么设计和实现。
|
||||
|
||||
实际上,**要想接手一个业务系统,前提是要读懂代码,而读懂代码的关键,是要熟悉业务。**只要业务搞清楚了,代码只不过是对业务的翻译,对照着业务看代码实现,看懂并不是件难事。不过,我所接手的这几个项目,基本上都是零文档,所有的业务知识都是靠口口相传。所以,搞清楚业务,就成了接手项目最难的事情了。
|
||||
|
||||
面对如此庞大的项目代码,没有文档,几乎就是两眼一抹黑。原来参与这个项目开发的老同事,有的离职,有的去做其他新项目,一直问他们也不好意思,所以,大部分情况下,我都只能硬着头皮,通过阅读代码反推业务功能。
|
||||
|
||||
如果代码质量比较高,模块划分清晰,命名规范,那通过读代码反推业务,也并非不可能的事情。但真实的情况往往事与愿违,就像我们前面提到的,代码中充斥着临时解决方案、硬编码、遗留代码等各种坑,这就使反推业务变得非常困难。对于代码中的这些坑,尽管我不想一直麻烦同事,但也只有多问才能最快速地解决。
|
||||
|
||||
在读代码的过程中,我非常重视知识的文档化,我会把读懂的每个业务都写到文档中。当然,这其中也包括前面提到的各种坑。对于复杂的业务流程,我还会画一些流程图。读代码的过程非常痛苦,花了好几个月,我才有信心说,自己几乎把所有代码都搞清楚了。同时,我也做了一件过去几年都没有人做的事情,那就是补充完整了技术文档和业务文档,之后再有新同事加入,看了我的文档,就可以很快了解代码、了解业务,很快就能上手开发代码。
|
||||
|
||||
总结一下,即便代码再烂,只要有完善的业务文档,先理解业务,再去看代码,几乎就没啥难度了。对于零文档的项目,大部分情况下,我们只能通过代码来反推业务。当然,对于有些坑来说,必要的情况下,我们也要询问前辈来搞定。在读代码的过程中,我们要将得到的知识文档化,这也是对公司和团队来说最有价值的部分。
|
||||
|
||||
## 如何在烂业务代码中成长?
|
||||
|
||||
有人一遇到这种烂业务代码,就觉得很心烦,我反倒不一样。恰恰相反,相比接手好代码,我觉得接手烂代码,虽然过程更加痛苦,但同时也会给我更多施展才华的空间、锻炼技术的机会,我的成长也会更多。
|
||||
|
||||
除此之外,很多人觉得做偏底层的开发(基础架构、框架、中间件等开发)才锻炼技术,做业务系统没有挑战,技术上没有成长,对此非常苦恼。实际上,我觉得这种看法是比较片面的。做业务开发的难度不亚于底层开发,做好也不是件容易的事情,同样可以积累技术、锻炼能力。
|
||||
|
||||
偏底层的开发更加考验程序员在某一细分领域的技术深度,偏业务的开发更加考验程序员的能力,比如沟通能力、分析问题解决问题能力、权衡取舍能力、架构能力等,毕竟业务多种多样,问题千奇百怪,单一细分领域的经验很难应对所有问题。
|
||||
|
||||
**实际上,业务系统的开发难度一般来自两个方面:高性能要求和业务复杂。**
|
||||
|
||||
解决性能问题,你需要具备一定的架构能力,有一定的技术广度,需要对各种基础架构、框架、中间件都有所了解。光了解还不够,还要有一定的技术深度,最好能对原理甚至是源码有所研究。除此之外,还要有一定的使用经验。广度、深度、经验三者配合,这样才能做到恰到好处组合这些技术搭建架构,解决性能问题,并且在出现问题之后才能快速地解决。
|
||||
|
||||
应对大型项目的业务复杂性,要想让项目代码一直在你的掌控范围内,你需要有很强的业务建模能力、复杂逻辑的抽象能力、代码翻译能力等。对于一个人的基本素质、基础能力的要求要更高。实际上,对于复杂业务系统来说,对业务的熟悉也能成为你的竞争壁垒,成为升职加薪的砝码。我前面也讲到,低级别的晋升靠技术,比如升阿里的P7,高级别的晋升靠业务,比如升阿里的P8、P9,或者换个说法,高级别的晋升,靠业务比单纯靠技术,更容易一些。
|
||||
|
||||
如果你参与的项目,性能要求高、业务也复杂,那恭喜你,好好干就成了。如果你参与的项目,在性能和复杂度上,只兼具其中一点,那也不错,值得一做。如果你参与的项目,既没有性能压力、业务也不复杂,那也别太着急,走着瞧,实在不行再跳槽。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
在过往的项目经历中,你有没有像我一样,接手过代码质量比较差的代码?你又是如何顺利接手的呢?
|
||||
|
||||
欢迎留言和我分享你的想法。如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
45
极客时间专栏/设计模式之美/不定期加餐/加餐四 | 聊一聊Google那些让我快速成长的地方.md
Normal file
45
极客时间专栏/设计模式之美/不定期加餐/加餐四 | 聊一聊Google那些让我快速成长的地方.md
Normal file
@@ -0,0 +1,45 @@
|
||||
<audio id="audio" title="加餐四 | 聊一聊Google那些让我快速成长的地方" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a3/56/a3e7cb1cab02710e29d5229bd0816956.mp3"></audio>
|
||||
|
||||
我一直强调,在项目中实践、由点及面的学习,是提高技术最有效的途径。但是,好的技术氛围、培养机制,也能打破通过项目单一成长的限制,获得更多项目之外的收获。很多公司,特别是一些大公司,在关注员工工作效率、工作产出的同时,也十分关注员工的个人成长、职场发展。今天,我就和你聊一聊Google有哪些让我快速成长的地方。
|
||||
|
||||
## 完善的培训课程
|
||||
|
||||
Google内部的课程是非常多的。有些是线下分享,有些是线上录播课程。在内容方面,课程也多种多样,有新技术的DogFood(比如我当年就参加过Go语言的),有入门级的101教程(比如针对后端工程师的前端入门课),还有比较有深度的系列教程(比如AI相关的课程)。所有的课程,只要你感兴趣,都可以自由选择来学习。
|
||||
|
||||
而且,最近我还听说,Google有个“G2G”学习计划,全称是Googler to Googler,意思就是Googlers之间互相学习。只要你有值得分享的东西,都可以录制成视频分享给其他同事。同理,你也可以从其他同事那里学习他们分享的技术。
|
||||
|
||||
总之,Google内部有大把的优质课程供你学习,这点对于好学的人来说,是非常幸福的一件事情。而且,得益于以结果为导向的企业文化,Google非常鼓励员工自我充电学习,不像有些公司反对员工占用上班时间来学习。
|
||||
|
||||
## 公开的文档和代码
|
||||
|
||||
除了各种线下和线上的课程之外,Google还有另外一块非常宝贵的学习资料,那就是文档和代码。在Google,除了特别核心的一些代码,比如跟搜索质量相关的代码,几乎所有的文档和代码都是公开的,你可以随意查看某个感兴趣的项目的设计文档和代码,比如Google Adwords的文档和代码等等。
|
||||
|
||||
你可能会说,Google就不怕员工泄露代码吗?在这一点上,Google相对是比较信任员工的。毕竟在招聘入口上做了过滤,员工本身的素质都不差,这点我们在下一篇加餐中还会讲到。
|
||||
|
||||
我们知道,Google有非常多优秀的开发框架,有些是开源的,有些是还没有公布、只限内部使用的。不管你对哪个开发框架感兴趣,你都可以在公司内部获取到一手的文档资料。通过阅读别人的文档,除了学习这些框架如何使用之外,我们还能学到很多关于设计、架构、解决方案等方面的经验和知识。
|
||||
|
||||
实际上,我觉得,代码公开最大好处并非是,你没事的时候就可以阅读别人的代码,毕竟泛泛地去读,效率也不会很高,收获也并不会很大,读完就忘了。相反,我一直强调,带着问题去学习是更有效的一种学习方法。所以,我觉得代码公开最大的好处是,当你想要实现某个功能的时候,或者为实现某个功能绞尽脑汁的时候,你只需要搜索一下代码仓库,就可以找到很多类似的优质代码做参考。对于很多新人或者初级工程师来说,参考别人的设计和实现,这样一方面可以提高开发速度、保证代码质量,另一方面也可以从高手那里学习好的设计思路和实现技巧,提高自己的设计和实现能力。
|
||||
|
||||
相反,据我所知,很多公司的代码都是限制访问的,员工只能查看一小部分相关项目的代码,极端情况下,只能阅读自己参与的项目的代码。相对而言,Google就“大方”很多。除了Code Review之外,我觉得,从n多Google高手的代码中学习设计和实现,是提高代码水平的另一个非常重要的渠道,也是让我代码能力成长最快的地方之一。
|
||||
|
||||
## 清晰的成长路径
|
||||
|
||||
除了有那么多课程、文档、代码来供我们自我学习之外,Google也非常关注员工的个人成长,希望能跟员工共同进步,而不只是将员工当成达成目标的工具。所以,在不同的阶段,公司会帮组员工制定不同的成长计划。
|
||||
|
||||
我们知道,像国内的一些大公司,比如BAT,在新员工入职的时候,一般都会有集中几天的入职培训。我当年加入Google的时候并没有这样的培训。我只参加过一次TGIF(Thanks God It’s Friday)上NewGoogler的欢迎仪式。
|
||||
|
||||
Google虽然没有集中的培训,但对于新入职的员工,公司会有一个新人的学习计划,主要涉及编码规范、单元测试、Code Review、开发工具、行为准则等方面的内容。我觉得,这一点对新人来说还是挺友好的。新人可以根据指引,一步一步完成学习计划里的内容,不会因为刚入职还未参加项目,而觉得无事可做。除此之外,在新员工入职时,公司还会分配一个同事作为mentor(导师)。任何工作、生活中的问题,你都可以向他请教,帮助你快速地融入公司。
|
||||
|
||||
除此之外,在工作中,每隔半年,你的Leader还会跟你一块制定OKR,也就是接下来半年你要做的事情,除了工作内容,这里面还会包含你的个人成长部分,比如你可以学习数据挖掘相关的知识,把这部分内容直接写到OKR中,这部分甚至可以跟你的工作没有任何关系,只是你对自己的自我提升。
|
||||
|
||||
不仅如此,你的Leader还会帮你制定升职计划。如果你有意申请下一轮晋升,领导一般会提前跟你一块规划,如何来做才能达成这个目标,比如做什么项目、做哪些有影响力的事情、管理多大的团队等等,也会有意安排一些帮你晋升的事情给你做。
|
||||
|
||||
为了不让工程师一直呆在舒适区,Google还非常鼓励内部转岗,希望员工不要一直做一个项目,鼓励员工跳出舒适区,换岗到其他团队,用不熟悉的语言、不熟悉的技术,去做一些不熟悉的项目。虽然我们知道,内部转岗机制也并非Google所特有的,很多公司都有,但是,真的执行得很顺畅的却不多。大部分公司都是跟风喊喊口号,员工真的要转岗的时候,条条关卡、困难重重。
|
||||
|
||||
上面的这些机制,貌似也没有什么特别的,很多公司都有。我要特别说的是,在Google,一对一的沟通非常多,特别是跟自己的Leader或者Manager,一般一两周就有一次,聊一聊自己这周的工作、想法、迷惑。这种沟通也能让你把工作、个人成长中的困难、疑问,及时反馈给领导,领导也可以及时地了解你的想法,对你进行指导,这也能避免很多工程师闷头干活,感觉不爽就立刻离职的情况。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
在你的职业生涯中,你觉得哪段工作经历对你的个人成长最有帮助?为什么呢?
|
||||
|
||||
欢迎留言和我分享你的想法。如果有收获,也欢迎你把这篇文章分享给你的朋友。
|
||||
75
极客时间专栏/设计模式之美/不定期加餐/春节特别加餐 | 王争:如何学习《设计模式之美》专栏?.md
Normal file
75
极客时间专栏/设计模式之美/不定期加餐/春节特别加餐 | 王争:如何学习《设计模式之美》专栏?.md
Normal file
@@ -0,0 +1,75 @@
|
||||
<audio id="audio" title="春节特别加餐 | 王争:如何学习《设计模式之美》专栏?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f9/b3/f9bd9f1a6c1425c60aa72a9b92ddf9b3.mp3"></audio>
|
||||
|
||||
你好,我是王争。今天是春节,首先祝你在新的一年,学业进步,工作顺利。放假期间,也不要忘记学习啊!
|
||||
|
||||
到此为止,咱们的《设计模式之美》快要更新过半了。很多小伙伴反馈的问题我都看到了。这里我也来讲一下,到底该如何学习《设计模式之美》专栏,才能做到事半功倍、有的放矢?
|
||||
|
||||
**《设计模式之美》专栏相对于我的另一个专栏《数据结构与算法之美》来说,内容看似更容易,实际上却更难。**为什么这么说呢?
|
||||
|
||||
从我写作的角度来说,《设计模式之美》要更加有难度。因为《数据结构与算法之美》的知识点都比较明确,一篇讲一个数据结构或算法。我只需要把原理、实现讲清楚,再举个实战的例子就基本大功告成了。
|
||||
|
||||
但是,《设计模式之美》中的知识点就没那么明确了。每个知识点到底该如何讲,并没有太多的参考。特别是专栏的前一部分,设计原则和思想,我在写专栏的时候参考了大量的书籍和资料。不瞒你说,大部分现有资料都讲得很浅,而且“互相借鉴”的痕迹也很明显。如果你之前对设计原则、思想、模式有所了解,或者看过挺多相关的书籍,应该能发现,我的专栏跟其他书籍的讲解还是有比较大的区别,这其中融入了我很多自己的思考和见解,这也是我的专栏与其他书籍区别最大的地方。
|
||||
|
||||
相对应的,从你学习的角度来说,《设计模式之美》也更有难度。它的难跟算法的难还不大一样。算法是原理难、实现难,最后才是应用难。而设计模式正好相反,原理、实现都挺简单的,基本上你一看就会觉得懂了,但是真正的能把它用到项目中,还是比较难的。对于很多人来说,你问他个具体的设计原则、思想、模式的原理和实现,他都能回答得头头是道,但是,在实际的项目开发中,写出来的代码质量还是很差。这种情况出现的原因还是相关的知识点都过于抽象,通俗点讲就是有点“假大空”,不够具体、不太能落地,导致理论和实践容易脱节。
|
||||
|
||||
所以,有些小伙伴总感觉《设计模式之美》学起来比《数据结构与算法之美》要简单,容易看懂,实际上这是种错觉。如果你也有这种感觉,那你要警醒了,因为你可能并没有真正读懂专栏的精髓。说了这么多,接下来我就讲讲,我为什么说你可能没有体会到文章的精髓,以及到底该如何来学习这个专栏。
|
||||
|
||||
## 1.建立完善的知识体系
|
||||
|
||||
你可能已经注意到,虽然这个专栏的名字叫《设计模式之美》,但专栏内容并不局限于此。实际上,整个专栏是围绕着教你如何编写高质量代码来设计的。
|
||||
|
||||
在整个专栏中,我试图给你建立完善的知识体系,所以,从内容上来讲,涵盖了编写高质量代码的方方面面,比如面向对象、设计原则、设计思想、编码规范、重构技巧、设计模式。虽然在有限的100篇文章、50万字内,我可能没法儿把每一个知识点都讲解得无比详细、全面,但我整理的这份知识框架,相当于给你指出了一个深入研究的方向,你可以按图索骥,积累起来会更快。先建立整体的知识框架,再慢慢深入、各个攻破,这也是学习任何一门新技术、新知识最有效的方法。
|
||||
|
||||
所以,这里给你布置一个小任务,闭上眼睛,想一想整个专栏都会讲哪些内容?已经讲过的设计原则和思想,都讲了哪些内容?你能想起来多少?
|
||||
|
||||
## 2.建立代码质量意识
|
||||
|
||||
实际上,建立正确的技术认知和技术观,比单纯学技术、学知识点更重要。
|
||||
|
||||
我举个例子,专栏中讲到单元测试的时候,并没有讲跟某个测试框架相关的技术点。因为我觉得这些很容易通过看文档学习,而我也不可能写得比文档更全面、更权威。实际上,通过那节课,我想要让你了解的是单元测试的好处,让你真正意识到单元测试的重要性,从心底认可这件事。还有,我在讲到重构的时候,也一直在强调要建立持续重构意识。整个专栏也都是在传递给你代码质量的重要性,让你意识到好代码和差代码的差别在哪里。
|
||||
|
||||
在学完专栏的时候,如果某些原则、思想、模式你记不大清了,那也没关系,只要你能在写代码的时候,能不由自主地去思考代码质量,有意识地去打磨代码,对代码质量有所追求了,那就说明你入门了,也就达到了我们专栏学习的目的。至于具体的知识点,随着时间的推移有所忘记,实际上并不碍事,多看几遍,多实践实践就好了。
|
||||
|
||||
这里,我也问你一个问题,你可以想一想,你写代码或者读别人代码的时候,是否开始思考代码质量问题呢?如果还没有,那再给你布置一个任务,在今后的一个月内,写代码前、中、后,都思考一下代码的扩展性、可读性、可维护性、可测试性等代码质量问题,看看自己编写的代码是否符合这些质量要求,有没有需要继续优化重构的地方。
|
||||
|
||||
## 3.主动学习而非被动学习
|
||||
|
||||
“师傅领进门,修行靠个人”,这句话说得特别好。同样听一个老师讲课,一个班级里面总有人会考90分,甚至满分,也会总会有人考不及格。差距在哪里呢?道理很简单,那就是你有没有用心学习。
|
||||
|
||||
类比到我们的专栏学习中,如果你只是走马观花地看一遍、跟听小说一样听一遍,收获肯定是甚微的,也就会出现常说的“过不几天就忘了”的情况。因为这是一种被动学习方法,左耳朵进右耳朵出,脑子里怎么会留住东西呢?相反,如果你能学会主动学习、主动思考,遇到不会的、理解不了的知识点,自己主动去思考一下、查查资料,或者跟同事讨论一下,试着把专栏里的内容自己总结一下,认真思考每一个课后题,这样的学习效果要比被动学习强好几倍。
|
||||
|
||||
关于这一点,我也给你留个作业:找一篇你觉得还没有透彻理解的文章,花上一天的时间,把里面的代码自己实现一遍,把文章的重点内容自己思考、整理,输出成文章。你可以看看,这样是否要比单纯看一遍收获更多呢?
|
||||
|
||||
## 4.多读几遍更有收获
|
||||
|
||||
《设计模式之美》专栏的内容都不难理解,每篇文章仅有四五千字,十几分钟的音频,但是,多读几遍你就会发现,每读一遍都会有不同的收获。
|
||||
|
||||
如果你只是看一遍、听一遍,怎么能达到像我一样对知识点的理解程度呢?我自己在写专栏的时候,可是查阅了大量的文章和资料。有的时候,一篇文章我要写好几天,这期间有长时间、高强度的阅读、思考和揣摩。你如果都不愿意花跟我一样多的时间,怎么能期望跟我有一样的水平呢?
|
||||
|
||||
一个人的认知和理解能力是受限于他的经历和经验的。如果你刚毕业不久,开发经验不多,看专栏的时候,难免会抓不住重点或者理解得不够透彻。那该怎么办呢?我的建议是,千万不要把学习专栏看成一蹴而就的事情,看完一遍就丢在一边了,而是要反反复复进行学习。看一遍理论之后,你可以在项目中尝试着实践一下,然后回过头来再看一遍,直到没有新的知识点可以汲取为止。这个过程可能需要持续很长时间,可能是1年、2年甚至是3年、5年,但只有这样,你才能积累出真正的能力、建立真正的竞争壁垒,而不只是学一些快餐知识、填补眼前的焦虑。
|
||||
|
||||
在《数据结构与算法之美》专栏中,我也说过,你要做一个长一点的学习计划。实际上,学习《设计模式之美》专栏也是如此,毕竟这两门课都是比较基础的,而且跟我们平时的开发比较相关,多花点时间在基础的知识上,收益要远大于学习很多花哨的新技术、新框架。
|
||||
|
||||
关于这一点,我再给你布置一个作业:找专栏中一篇文章,反复读上10遍(当然是带着思考去读哈)。你看看是不是比只读一遍要理解得更透彻?是不是之前不能理解的地方自然就理解了呢?是不是每次读的时候都有新的收获?
|
||||
|
||||
## 5.学会把代码写到极致
|
||||
|
||||
我经常说,写100段烂代码都不如写1段好代码,对代码能力的提高大。实际上,这个道理也可以应用到任何学习工作中,堆量只需要时间,但并不是每个人都能把事情做到极致,而能把一件事情做到极致的人,往往也能把其他很多事情做到极致。这也是为什么,很多人在某一行业做得很好,跨行去做另一个看似不相干的事情也同样能做得非常好。牛人往往都是能把一件事情做到极致的人。如果所有的事情都只能做到一般好,那你注定也只能做一个平凡的人。
|
||||
|
||||
关于这一点,我也布置一个作业给你:找一段你觉得写得很烂的代码,花上一个礼拜的时间,反复思考如何优化,把它优化到足够好。
|
||||
|
||||
## 总结
|
||||
|
||||
说了这么多,说实话,我知道这些道理很多人都知道。但是,能真正落实执行,并且执行到位的人不多。就光我说的这几个作业,估计能100%完成的也没有几个人。
|
||||
|
||||
你说人和人之间的差距在哪里?就在这里。
|
||||
|
||||
不要期望我的专栏有什么杀手锏可以教给你,不要期望看了我的专栏之后不费力气就能成为代码高手。还是那句话,师傅领进门,修行靠个人。我能做的就是尽量地将知识讲得通俗、透彻,把我的经验尽可能地传授给你,而这些只占1%,剩下99%都要靠你自己去努力。
|
||||
|
||||
如果说成为代码高手是万里长征,那我只能给你指明方向,告诉你如何去走。剩下的万里长征没人能替你去走,需要你一步一步、踏踏实实,自己去走完。
|
||||
|
||||
## 课堂讨论
|
||||
|
||||
最后,你可以在留言区讲一讲自己的**新年学习计划**。
|
||||
|
||||
如果有收获,欢迎收藏这篇文章,并把它分享给你的朋友。
|
||||
Reference in New Issue
Block a user