拉巴力的纸皮箱


  • 首页

  • 标签

  • 归档

  • 关于

  • 搜索

职场中“马后炮”现象

发表于 2024-03-27

职场中有一种奇怪又平常的现象:没出事就没人重视,出事了就各种马后炮。

  • 以软件开发人员平常应对的事情为例,这里其实有一种无奈的解释:

    1. 需求这么多还没做完,有什么充分的理由去重视这个问题?
    2. 你把事情做好了,完全不出事,怎么证明是你的功劳?
  • 普通的干实事的程序员,最讨厌跟行外人谈收益。就像把代码写好了,自然后续维护成本就低了。但是硬要把他转化为节约多少人力。只想一心老老实实写代码的程序员,好心做个事情还要花费心力想办法给你解释,久而久之自然是多一事不如少一事。所谓劣币驱逐良币,有追求的程序员自然离开了,剩下的可想而知。

  • 那么,难道这个问题就无解吗?

    • 当然不是。要建立在不干涉和充分信任的基础上。CEO相信CTO,CTO当然知道把代码写好的好处,所以也不需要底下做事的人过分解释。
    • 但实际上很多公司,CTO不做CTO的事,只是专注向上汇报,还把汇报的事情层层外包给下面的人。导致本应该自己屏蔽,让底下安心做事的事情,层层透传,苦了干实事的人。而自己就成了汇总PPT的汇报员。
  • 最后讲一个故事

    魏文王问扁鹊曰:“子昆弟三人其孰最善为医?”
    扁鹊曰:“长兄最善,中兄次之,扁鹊最为下。”
    魏文王曰:“可得闻邪?”
    扁鹊曰:“长兄于病视神,未有形而除之,故名不出于家。中兄治病,其在毫毛,故名不出于闾。若扁鹊者,镵血脉,投毒药,副肌肤,故名出闻于诸侯。”
    魏文王曰:“善。”
    
  • 善战者无赫赫之功

  • 防患于未然的人不如亡羊补牢者获得的赞誉多

小团队管理经验

发表于 2024-03-26

转眼工作十年了,从20年10月开始,断断续续做了近三年的小团队管理,这里作简要总结一下。

所谓小团队管理,其实就是现在说的虚线组长,需要写代码、给团队提供指导等,但是由于不是高级别大领导,不需要应付很多烦人的破事。从这层来看,挺适合我这种性格的人。

以下是以小团队为背景来总结的,格局显得较小;当然每个人的观点不一样,不一定是正确的理解。

核心要点(对自己)

  • 情商、基于别人的角度思考
    • 个人习惯采取对内温和对外强硬的方式;当然结合自身情况和环境具体选择;这个方法可以让你更好的理解人和事情;我不认为所谓的“情商高”就是“老好人”。
  • 以身作则
    • 以自己为榜样,让团队其他成员看到正确的做事方式等;包括技术方案、沟通方式等,当然包括一些无法避免的脏活累活等;用高效和人性化等方式应对 。
  • 令人信服的技术功底
    • 小团队管理的特点,就是领头的人也是需要写代码和干实事,而且跟团队成员的距离是最近的;需要保持自己良好的技术功底,才能更好的给团队提供有效的建议;另外作为有追求的技术人,谁都想跟着比自己优秀的人一起共事。
  • 保证成员尽量免干扰、休息时间如无必要不打扰
    • 这一点是我基于人性化的角度考虑的,有些人可能会觉得不重要。给团队提供深度工作的环境,才能提升效率;在一些不紧急的事情少,要做到不随意打扰,减少团队的负面情绪。对应上面第一条,将心比心,每个人都想要良好的工作体验。
  • 真诚、谦虚、透明
    • 尽量保持团队一定的透明度,减少不必要的暗箱操作。大部分情况下不需要开会,只需要一篇简明扼要的文档,即可让团队快速了解事情的内容。团队成员也在发展,要清楚有一天他们的能力会超过你。而我一直坚持的做法是,业务上坚持写文档,尽量减少业务壁垒(也是为自己放假偷懒准备),技术上提供合理的建议,不遗余力的提高自己的“可替代性”。
    • 认清自己。领导需要团队的力量才能发挥作用。不要错把平台的能力当作自己的能力。把公司的给予当作自己的给予。
  • 人性化管理
    • 现在很多公司都追求狼性文化,说着各种假话哄下属为自己加班干活
    • 个人管理经验理念是,先做人再做领导
    • 如非必要。不严厉。许多人还没到那个层级就采取低端没人情味的管理方式。要和同事成为朋友,营造友好的工作环境,而不是一味向上管理。
  • 尽量保持技术更新升级
    • 在确保充分测试,稳定灰度的同时,适量的升级有利于系统的稳定,增加维护人员的积极性。这种东西无法直接给出具体收益,但应该长远考虑,一味的保守只会让技术越来越落后

核心要点(对团队)

  • 聪明、叙述简明扼要、能抓重点
  • 乐于分享、采用高效的分享手段(文章即可)、实事求是
  • 有团队主人翁意识,主动了解业务
  • 对技术原理好奇并积极探索
  • 尊重别人的时间
  • 跟进事情有反馈和结论
  • 在正确的事情面前,敢于说不
  • 重视自己的“可替代性”、免于个人单点、提升团队容错性

小团队技术管理者的事项列表

  • 业务侧
    • 快速满足需求
    • 通用业务组件抽象
    • 旧业务熟悉
    • 定期删除无用代码,增加代码可维护性
    • 遗留需求记录和跟进
    • 业务知识文档化,方便查阅和备忘
    • 需求上线时间定时跟进(你就是项目经理)
  • 技术侧
    • 旧业务梳理和重构
    • 架构灾备和优化、资源隔离等
    • 通用工具类封装
    • 管理后台搭建 (解放技术)
    • 服务异常监控(后端接口,前端APM等各个维度)
    • 技术组件升级,提升团队技术广度
    • 废弃业务下线,回收资源
    • 业务技术调研,团队具备快速满足产品新需求的能力
    • 分享,相互学习,个人认为文档就行了,会议实际上挺形式和浪费大家的时间
    • 帮助review方案和代码
    • 技术债务登记和逐步处理(分优先级[每个季度一定要完成一定比例的低优先级任务],保持代码洁癖,不给后来人挖坑)
    • 开发规范制定(避免后续维护混乱,也方便大家日常开发查阅)
    • 开发阶段和上线阶段checklist,避免犯重复的错误,避免上线遗漏导致项目延期
    • 技术面试
    • 应急处理、日常维护等文档化(公开、透明、高效)
    • 团队文档整理规划
      • 新人指引
      • 业务模块(服务模块、业务知识整理、业务交接记录、业务安全风险点)
      • 工作规划(需求列表、技术规划、技术债务)
      • 开发规范(项目上线流程、公共库说明、开发协议、服务架构图、业务逻辑开发套路等)
      • 工作文档(应急、日常维护等)
        • 常见问题处理导航
      • 技术文档(技术型、分享类)
      • 技术方案(日常需求上线方案归档)
      • 复盘、故障报告
      • 业务调研
      • 其他备份

Reference

  • 个人管理经验总结

如何在大量数据中判断给定的是否在其中

发表于 2023-07-30

1、 Bloom Filter

  • 缺点:只能增不能减,且有误判场景需要单独处理
  • 可以使用当前进程级的Bloom Filter,也可以使用Redis的Bloom Filter

2、 文件存储

  • 可以使用类似Java的MappedByteBuffer来保存数据

  • 缺点:只能保存连续的一定范围的数字对应的值

  • Java文件读写与MappedByteBuffer

  • 使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class MappedByteBufferTest {
public static void main(String[] args) {
System.out.println("=="+ ID_SIZE);
System.out.println("=="+ getBufferIndex(1032387525));
System.out.println("=="+ getBufferIndex(227081157));
// 两个数字模结果冲突
// 这种方案只能保存连续的一定范围的数字对应的值
}

private static final int ID_SIZE = 1024 * 1024 * 32 * 8;

private static int getBufferIndex(long idx) {
//每个id占用8个字节
return (int) ((idx % ID_SIZE) * 8);
}

/**
*
* 写入:mappedByteBuffer.putLong(int index, long value);
* 读取:mappedByteBuffer.getLong(int index);
* 注:MappedByteBuffer对index的最大范围是Int.MaxValue()
*/

// 上面的表述计算有问题
/**
* 2G = 2^31 字节
* ==> 1b= 2^3 ; 1k = 2^10 b ; 1M = 2^20 b ; 1G = 2^30 b; 2G = 2^31 字节
* long 64 位,即 2^3 字节 = 2^3
* 2G = 2^31 字节 能存储多少个,应该是 2^31 / 2^3 = 2^28
*/

// 31 - 3 = 28 = 10 + 10 + 5 = 1024 * 1024 * 32 * 8
// 根据每个模之后的倍数放在不通的文件,所以不会冲突
//如果分文件,比如10个,那么78在第8个文件的低第七个; 78%10、78/10

/**
* https://zhuanlan.zhihu.com/p/353988136
* @throws IOException
*/
@Test
public void testMappedByteBuffer() throws IOException {
File file = new File("/Users/kingsonwu/downloads/test.log");
if(!file.exists()){
file.createNewFile();
}
FileChannel fileChannel = FileChannel.open(Paths.get(URI.create("file:/Users/kingsonwu/downloads/test.log")),
StandardOpenOption.WRITE, StandardOpenOption.READ);
MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, Integer.MAX_VALUE);
//fileChannel.close();
//mappedByteBuffer.position(1024);
//mappedByteBuffer.putLong(10000L);

mappedByteBuffer.putLong(getBufferIndex(1032387525), 1032387528111L);
mappedByteBuffer.putLong(getBufferIndex(1032387526), 1032387529567L);
mappedByteBuffer.putLong((ID_SIZE - 2)*8, 4032387529569443654L);
//mappedByteBuffer.putLong((ID_SIZE_2)*8, 1032387529569L);

mappedByteBuffer.force();

System.out.println(mappedByteBuffer.getLong(getBufferIndex(1032387525)));
System.out.println(mappedByteBuffer.getLong(getBufferIndex(1032387526)));
System.out.println(mappedByteBuffer.getLong((ID_SIZE - 2)*8));
//System.out.println(mappedByteBuffer.getLong((ID_SIZE_2 )*8));

}
}

3、Tendis

  • 使用tendis可以将数据存储到磁盘,避免全部数据都保存在内存,从而节约内存
  • Redis的痛点之一就是内存成本高,访问频率(QPS)没那么高, 依然占用大量机器, 维护成本很高
  • Redis vs Tendis:冷热混合存储版架构揭秘
  • 使用 rocksdb 作为存储引擎, LSM Tree

记一次socket泄露问题排查记录

发表于 2023-07-30

结论先行

  • 服务死锁导致大量请求hang住,进程无法提供服务且大量socket泄漏

具体过程

  • 服务某些逻辑处理不当导致死锁
  • 大量请求hang住没有响应
  • 上层的nginx超时主动关闭连接
  • 服务被关闭连接,导致大量CLOSE_WAIT
  • 由于服务对连接处理不当(待分析原因TODO),导致大量socket泄漏

前置知识

TCP状态图

  • 从网上找的

相关排查命令

sudo lsof | grep sock | awk '{++S[$1]} END {for(a in S) print a, S[a]}' | sort -nr
sudo lsof | awk '/sock/ {++S[substr($0, index($0, $9))]} END {for(a in S) print a, S[a]}'
sudo lsof | grep sock|grep 'identify protocol'|awk ' {++S[$2]} END {for(a in S) print a, S[a]}'| sort -nr
//打开句柄数目最多的进程
lsof -n|awk '{print $2}'| sort | uniq -c | sort -nr | head
//查看close_wait连接统计:
sudo netstat -anp|grep 'CLOSE_WAIT'|grep 'ssogo'| awk '{print $5}'|sort |uniq -c | sort -nr
//查看FIN_WAIT2连接统计:
sudo netstat -anp|grep 'FIN_WAIT2'|grep 'ssogo'| awk '{print $5}'|sort |uniq -c | sort -nr
//查看CLOSE_WAIT最多的进程
sudo netstat -anp|grep 'CLOSE_WAIT'| awk '{print $7}'|sort |uniq -c | sort -nr
sudo netstat -anp|grep 'FIN_WAIT2'| awk '{print $7}'|sort |uniq -c | sort -nr

ss

  • 在 ss -s 命令的输出中,”closed” 表示已关闭的 TCP 连接的数量。

具体地,TCP 的 “closed” 状态表示连接已经关闭,不再使用,并且不再具有任何网络连接或状态信息。这些连接处于已经结束的状态,但它们的套接字资源还未被完全释放或回收。

在输出结果中,”closed” 数量是指当前处于已关闭状态的 TCP 连接的数量。这些连接可能是先前已经建立的连接,已经完成了其通信任务,双方都关闭了连接,并且连接的套接字资源等待系统进行资源回收。

需要注意的是,已关闭的连接数量的增加和减少是动态的,因为在系统的运行过程中,套接字的打开和关闭是常见的网络操作。

lsof

  • lsof| grep "can't identify protocol"
    如果存在很多,则代表socket泄漏,同时会显示哪个进程使用的sock未关闭。

  • tcp-socket文件句柄泄漏


架构图

  • TODO

处理过程1

  • 紧急重启服务(业务Go服务)后socket数量下降

  • 在现场已经没了的情况下,分析发现机器上本身已经存在大量socket泄漏的情况

![](20230730-记一次socket泄露问题排查记录/identify protocol.png)


  • nginx和gateway都reload,那么nginx会产生新的worker进程,但是应该shutdown的老进程因为和gateway还有连接,所以也不会销毁,这样时间长了会有很多处于shutting状态的进程,这些进程都会占用资源。

  • 初步怀疑是这些异常的nginx worker进程导致的,于是处理所有机器上这些异常(kill)

    1. 如果清掉这些异常进程后,问题不再发生,那么很大可能就是这个原因导致的
    2. 如果问题还继续发生,说明是其他的原因

处理过程2

  • 即使上次清理了所有有问题的nginx worker进程,释放了大量泄漏的socket,相同的问题后续还是发生了

  • 还是出现了大量的closed状态,已经大量的close_wait和fin_wait2状态

  • 通过lsof查看,确实是Go业务进程泄漏的socket

  • 上图的正常状态下,close_wait和fin_wait2状态的数量,并没那么多

  • todo: 后续统计一下:

//查看close_wait连接统计:
sudo netstat -anp|grep 'CLOSE_WAIT'|grep 'ssogo'| awk '{print $5}'|sort |uniq -c | sort -nr
//查看FIN_WAIT2连接统计:
sudo netstat -anp|grep 'FIN_WAIT2'|grep 'ssogo'| awk '{print $5}'|sort |uniq -c | sort -nr
//查看CLOSE_WAIT最多的进程
sudo netstat -anp|grep 'CLOSE_WAIT'| awk '{print $7}'|sort |uniq -c | sort -nr
sudo netstat -anp|grep 'FIN_WAIT2'| awk '{print $7}'|sort |uniq -c | sort -nr
  • 通过pprof输出进程的goroutine情况,从数量和堆栈分析,大量goroutine锁住,导致请求被hang住

  • 至此,问题的基本表现分析如下

    1. Go进程出问题hang住大量请求
    2. 上层的nginx超时主动关闭连接,状态变成FIN_WAIT2,而Go进程对应的socket拦截则变成CLOSE_WAIT
      • 查看设置为 proxy_read_timeout 10(即10s):proxy_read_timeout 是用来设置与后端代理服务器之间的读取超时时间,它控制 Nginx 从后端代理服务器读取响应的最长等待时间。当从后端服务器读取响应数据的时间超过了设置的超时时间,Nginx 将认为后端服务器的响应已经超时,并且会中断与后端服务器的连接。
    3. Go进程对已关闭的连接处理异常,导致大量“can’t identify protocol”
      • 请求被hang住,进程没释放,socket会占有(不然被新的请求占有造成数据包混乱)

扩展

can’t identify protocol 是怎么出现的?

  • https://idea.popcount.org/2012-12-09-lsof-cant-identify-protocol/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import socket
import os
import sys

PORT = 9918

sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sd.bind(('0.0.0.0', PORT))
sd.listen(5)

for i in range(10):
if os.fork() == 0:
sd.close()
cd = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
cd.connect(('127.0.0.1', PORT))
sys.exit()

print "Server process pid=%i" % (os.getpid(),)
sockets = []
for i in range(10):
(cd, address) = sd.accept()
sockets.append(cd)
cd.shutdown(socket.SHUT_WR)

os.system("lsof -p %i" % (os.getpid(),))
```

+ `cd.connect(('127.0.0.1', PORT))`之后没有执行`cd.close()`(关闭客户端套接字,确保连接被正确关闭), 直接执行 sys.exit(),导致连接没有正确关闭,从而出现了"can't identify protocol"的问题

#### 为什么lsof和ss的执行结果不同
+ ss命令显示closed状态的socket,在lsof显示的是can't identity protocol
+ 大概是两个命令实现的原理差异吧

#### 通过模拟client断开,server端hang住
+ https://raw.githubusercontent.com/Kingson4Wu/awesome-tools/main/network/http-print.c 加上 `sleep(600);`的代码
+ curl --connect-timeout 10 -m 20 "http://XXXXXXX"
+ 执行lsof 只出现了‘CLOSE_WAIT’,没有出现 can't identity protocol

#### go进程为什么没正确关闭socket
+ todo
+ strace -p

#### strace 怎么使用
+ todo

### gin怎么设置接受的socket数量
+ todo
+ gin接收请求数量上限设置


---

## 处理过程3
+ 分析Go进程死锁原因

+ 通过分析pprof的goroutine堆栈

```go
type GuardPolicy struct {
mu *sync.RWMutex
errData map[*sql.DB]int
}

type sortPool struct {
connPool gorm.ConnPool
errCnt int
}

func (s *GuardPolicy) countErr(db *gorm.DB) {
if db.Error == nil || errors.Is(db.Error, gorm.ErrRecordNotFound) {
return
}
if ins, ok := db.Statement.ConnPool.(*sql.DB); ok {
s.mu.Lock()
defer s.mu.Unlock()
s.errData[ins] = s.errData[ins] + 1
}
}

func (s *GuardPolicy) Resolve(connPools []gorm.ConnPool) gorm.ConnPool {
var x = make([]*sortPool, 0, len(connPools))
for i := range connPools {
p, ok := connPools[i].(*sql.DB)
if !ok {
x = append(x, &sortPool{connPool: connPools[i], errCnt: 0})
} else {
s.mu.RLock()
defer s.mu.RUnlock()
x = append(x, &sortPool{connPool: connPools[i], errCnt: s.errData[p]})
}
}
sort.Slice(x, func(i, j int) bool {
return x[i].errCnt <= x[j].errCnt
})
return x[0].connPool
}

(1) goroutine1: s.mu.RLock()
(2) goroutine2: s.mu.Lock() - 等待(1)
(3) goroutine1: s.mu.RLock() - 等待(2)
相当于goroutine1自己等待自己

  • 问chatgpt:
    是的,提供的代码存在死锁风险。死锁可能发生在Resolve方法中。

在Resolve方法中,对于sql.DB类型的连接,当读取errData映射的错误计数时,使用了RWMutex的读锁(s.mu.RLock())。但是,在循环的每次迭代中都会调用defer s.mu.RUnlock(),这会在for循环结束时解锁,而不是在每次迭代结束时解锁。

这意味着如果在某次循环迭代中获取了读锁,但在获取下一个读锁之前已经进入了循环的下一次迭代,那么这两次迭代将持有读锁,但没有释放,从而导致死锁。

要解决这个问题,可以将读锁的获取和解锁放在同一次循环迭代中,确保每次获取读锁后都会及时释放,而不会在后续迭代中持有读锁。以下是修改后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func (s *GuardPolicy) Resolve(connPools []gorm.ConnPool) gorm.ConnPool {
var x = make([]*sortPool, 0, len(connPools))
for i := range connPools {
p, ok := connPools[i].(*sql.DB)
if !ok {
x = append(x, &sortPool{connPool: connPools[i], errCnt: 0})
} else {
s.mu.RLock()
errCnt := s.errData[p]
s.mu.RUnlock()
x = append(x, &sortPool{connPool: connPools[i], errCnt: errCnt})
}
}
sort.Slice(x, func(i, j int) bool {
return x[i].errCnt <= x[j].errCnt
})
return x[0].connPool
}

扩展

  • 跟这个很像:线上一次大量 CLOSE_WAIT 复盘

Reference

  • tcp socket文件句柄泄漏
  • 确认是否有socket泄露
  • 记一次排查socket fd泄漏
  • 又一次排查socket fd泄漏
  • socket句柄泄漏问题的定位: losf和strace的联合使用

我接触过的几种服务发现和rpc

发表于 2023-07-04

公司V

  • 主要Java语言
  • 最原始
  • 没有服务发现
  • 通过域名调用,服务器ip配置在nginx
  • 数据传输使用JSON协议

公司U

  • 主要Java语言
  • 公司基础团队自己实现服务发现机制
  • 服务发现使用netty做tcp长链,用于服务注册等
  • 服务sdk从服务中心获取所调用的对端服务的ip和端口
  • 通过tcp长链通知服务上下线等
  • 通过服务的ip和端口调用
  • 数据传输使用hessian协议

公司K

部门1

版本v1

  • 主要Java语言
  • 使用Eureka做服务发现(HTTP协议)
  • 服务sdk从Eureka获取所调用的对端服务的ip和端口
  • 通过HTTP接口从Eureka定时更新服务实例
  • 通过服务的ip和端口调用
  • 数据传输使用Thrift协议/JSON协议

版本v2

  • 在版本1的基础上增加LocalProxy 作为代理
  • 加入local proxy (service mesh)
    (服务a)->本地LP ->(服务b)

版本v3

  • 在k8s 部署
  • 让每个pod都是单独的实例,ip和物理机一样可以访问,使用calico打通网络,兼容原来的服务发现机制,暂时不使用k8s的service功能
    (服务a)->远程LP ->(服务b)

版本v4

  • 使用Istio替换LP
  • LP(linkerd)使用Euerka,Istio使用k8s service
  • (服务a)->istio-istio →(服务b)
  • 内部调用:(服务a,istio-envoy1)-》(istio-envoy2,服务b)
    ()标识同一个pod

部门2

  • 使用nginx二次开发,作为localproxy,以域名作为服务名
  • 比较原始的方案(公司起步比较早,当时的方案一直沿用至今)

谈谈定时任务的原理和应用

发表于 2023-07-03

定时任务的原理

  • 本质是开一个线程,无限循环,检查本地的当前时间,是否符合执行的条件

  • Redis: 比如redis-5.0.8,起了一个线程不停的循环检查,比对当前时间(gettimeofday)判断是否需要执行

  • Golang: 起一个goroutine无限循环,从最小堆中取符合时间的任务

  • Java: 单线程, 无限循环,最小堆: java.util.TimerThread#mainLoop

定时任务类型

  • 定时任务一般分为 本地定时任务 和 分布式定时任务

  • 比如定时加载数据到本地缓存的时候,这时一般就使用本地定时任务

  • 而有些任务定时只需要执行一次, 现在很多服务都不是单点了,这就需要分布式定时任务来进行调度了

分布式定时任务使用示例

  • 业界上可选择的定时任务工具很多,在工作中使用最多的是Saturn,个人觉得还是很方便的,其他分布式定时任务的原理其实基本大同小异

  • 官网地址: https://github.com/vipshop/Saturn

  • Saturn架构文档

Saturn

  • 如果是Java服务,可以很方便的接入Saturn,可以直接通知到服务
  • 但如果是其他语言,则是通过执行shell命令间接实现的

使用域信号通知通知服务

  • 这里Go应用为例子,通过域信号结合shell命令,从而方便使用saturn定时任务

  • client端:提供shell命令,供saturn定时调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const SockPath = "/tmp/notify-os.sock"

func notifyRun(task *notifyTask) {

httpc := http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", SockPath)
},
},
}
response, err := httpc.Get("http://unix/" + task.name + "?" + task.args)
if err != nil {
panic(err)
}
var buf = make([]byte, 1024)
response.Body.Read(buf)
logger.Infof("finish notify task: %s, args:%s, resp: %s", task.name, task.args, string(buf))
}

  • server端:提供uds服务,介绍请求触发执行相应的任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

type ser struct{}

func (s ser) ServeHTTP(rw http.ResponseWriter, r *http.Request) {

defer func() {
if err := recover(); err != nil {
logger.Errorf("notify server panic, r: %s, err:%s", r.RequestURI, err)
}
}()

name := r.URL.Path

if strings.HasPrefix(name, "/") {
name = name[1:]
}

if job, ok := jobs[name]; ok {
args := map[string]string{}
for k, v := range r.URL.Query() {
args[k] = v[0]
}
if job.Handler(args) {
rw.Write([]byte("ok"))
logger.Infof("job run success, name:%s, args: %s", name, args)
} else {
rw.Write([]byte("fail"))
logger.Errorf("job run fail, name:%s, args: %s", name, args)
}
return
}

rw.Write([]byte("not exist"))
logger.Warnf("job not exist, name:%s", name)

}
func NotifyServe() {
sockPath := utils.BizConfig("notify_uds_file", "")

if sockPath == "" {
panic("sockPath is nil")
}

logger.Info("Unix NotifyServe ...")
os.Remove(sockPath)
server := http.Server{
Handler: ser{},
}
unixListener, err := net.Listen("unix", sockPath)
if err != nil {
panic(err)
}
server.Serve(unixListener)
}

  • windows 平台没有uds,可以使用普通的HTTP接口代替

对工作中接触过的几种编程语言及其部署架构的看法

发表于 2023-07-02

公司V

  • 使用Java作为编程语言

  • 使用Spring-MVC框架

  • 使用Tomcat作为Web容器

  • 打包运行方式:

    1. 服务器预安装了Java和Tomcat
    2. 将代码打包成war包
    3. 将war包上传到服务器的Tomcat的web目录
    4. 重启tomcat更新服务

公司U

  • 使用Java作为编程语言

  • 使用二次开发的Play1.x作为web框架(底层基于Netty)

  • 公司在框架自行研发了服务发现等功能

  • 打包运行方式:

    1. 服务器预安装了Java
    2. 将代码打包成Zip包
    3. 将zip包上传到服务器的指定目录
    4. 通过信号停止服务(kill),通过Java命令启动服务

公司B

  • 使用Java作为编程语言

  • 使用Spring-Boot框架

  • 使用Tomcat作为Web容器

  • 打包运行方式:

    1. 服务器预安装了Java和Tomcat
    2. 将代码打包成war包
    3. 将war包上传到服务器的Tomcat的web目录
    4. 重启tomcat更新服务

公司K

Java

  • 使用Java作为编程语言

  • 使用二次开发的Spring-Boot和Spring-Cloud作为web框架

  • 公司在框架自行研发了服务发现,服务治理,数据库切换、容灾相关等功能

  • 打包运行方式:

    1. 服务器预安装了Java
    2. 将代码打包成Zip包
    3. 将zip包上传到服务器的指定目录
    4. 通过信号停止服务(kill),通过Java命令启动服务

Lua

  • 使用Lua作为编程语言

  • 使用OpenResty作为服务器

  • 公司开发了一些通用的sdk,在OpenResty配置中include即可

  • 打包运行方式:

    1. 服务器预安装了OpenResty
    2. 将代码文件上传到指定的目录
    3. 执行 nginx -s reload 更新OpenResty的lua文件即可

PHP

  • 使用PHP作为编程语言

  • 使用OpenResty作为服务器

  • 打包运行方式:

    1. 服务器预安装了OpenResty和PHP
    2. 将代码文件上传到指定的目录
    3. 执行 nginx -s reload 更新OpenResty的PHP文件即可

Go

  • 使用Go作为编程语言

  • 打包运行方式:

    1. 将代码打包成二进制可执行文件
    2. 使用nohup运行二进制即可(有的使用supervisor,有的使用systemctl)

对这些编程语言和运行方式的理解和看法

Java

  • 编译语言
  • Java服务需要运行在JVM上,而JVM是使用C++实现的
  • Java代码编译后本质上是一堆字节码文件,不具备单独运行的能力
  • 运行Java字节码,需要JRE环境

PHP

  • 脚本语言
  • PHP通常和Web服务器搭配(比如Apache和Nginx),对外提供Web服务
  • 以Nginx为例,Nginx不能直接处理PHP脚本,需要使用FastCGI协议将请求转发到PHP解释器
    (因此,首先需要安装PHP和FastCGI进程管理器,例如php-fpm)
  • 通常情况下,PHP解释器会安装在机器本机上。当Nginx通过FastCGI协议与PHP解释器进行通信时,它会将请求转发到运行在本机的FastCGI进程管理器,然后再将请求转发到本机上运行的PHP解释器

Lua

  • 脚本语言
  • 以OpenResty作为web服务器运行Lua脚本是一种方式
  • Nginx + LuaJIT = OpenResty

OpenResty

  • OpenResty本质上是将 LuaJIT 的虚拟机嵌入到 Nginx 的管理进程和工作进程中,同一个进程内的所有协程都会共享这个虚拟机,并在虚拟机中执行Lua代码。在性能上,OpenResty接近或超过 Nginx 的C模块,而且开发效率更高。
  • OpenResty中的核心技术cosocket将 Lua 协程和 Nginx 的事件机制结合在一起,最终实现了非阻塞网络IO。不仅和HTTP客户端之间的网络通信是非阻塞的,与MySQL、Memcached以及Redis等众多后端之间的网络通信也是非阻塞的。

Openresty 是怎么嵌入lua虚拟机的

  • OpenResty 是一个基于 Nginx 的 Web 应用服务器,它可以通过嵌入 Lua 脚本语言来实现高性能的 Web 应用程序。OpenResty 在运行过程中通过 LuaJIT 虚拟机来解释执行 Lua 代码。
  • OpenResty 在编译时会将 LuaJIT 虚拟机源代码打包成动态链接库,然后将其嵌入到 Nginx 中。OpenResty 运行时会通过 LuaJIT 虚拟机来加载和执行 Lua 代码,从而实现了高性能的 Web 应用程序。

Go

  • 编译语言
  • 编译成二进制文件后,可以直接在服务器运行,相比其他语言,一般可以认为没其他依赖

个人看法

  • Lua比较小众,不适合做大型的业务开发,而且debug比较不方便;
  • PHP在业界已经是快被淘汰的语言了,不做仔细研究,初步体验感觉一般(可能是受限于公司的维护环境过于糟糕,各种老版本,和高深莫测的代码);
  • Java是我职业生涯接触最久的编程语言,谈不上喜欢也谈不上讨厌,但自从学习了Go之后,有了新的体会;
  • 当初学习Go的其中一个原因是自己的个人项目比较轻量,Go其中一个优势是不依赖其他软件就可以运行,而且分发方便;
  • Go使用AOT的方式编译,针对特定平台,除了加快启动速度,也使程序打包体积大大减少;
  • 当然Java也可以用graalvm打成二进制文件启动(没尝试过,感觉还是有不少前置条件);
  • 除此之外,还有很多其他以后补充

软技能_代码之外的生存指南_notes

发表于 2023-03-02

献言

  • 谨以本书献给所有自强不息、孜孜不倦地持续自我改进的开发人员。他们具备下列素质: 永远不会对“不错”感到心满意足永远寻求每一个机会来拓展自己的视野,探索未知事物对知识的渴求永远不会熄灭笃信软件开发并不仅仅意味着编写代码。知道失败不是结束,失败只是人生旅程上的小小一步有过挣扎,有过失败,但仍然会爬起来继续战斗拥有强烈意愿和决心,在人生的道路上不畏艰难以及最重要的,愿意一路上帮助他人。

前言

  • 不能只编写代码,还要有精彩的人生。

第1章 为何这本书与你先前读过的任何书籍都迥然不同

  • 我所说的“优秀的软件开发人员”,是那些能够把控自己的职业生涯、达成目标、享受生活的人。
  • 如果你想真正成为一个更好的软件开发人员(或者其他真正优秀的人才),你需要把重点放在整个“人”上,而不只是你生活中的一两个领域。
  • 想为这些内容分类和分组,最简易的方法是将它们看成是事业、思想、身体和精神四个方面。

第一篇 职业

  • 职业发展的驱动力一定是来自个体本身。记住:工作是属于公司的,而职业生涯却是属于你自己的。

  • 当你为了谋生一头扎进写代码的世界时,其实你和中世纪小镇上开铁匠铺的铁匠没什么差别。

  • 当你和别人打交道的时候,你应该知道的最重要的一个概念就是:以自己为核心,每个人都希望自己很重要。这是人类最深邃、最致命的欲望之一,也是社会和生活中取得伟大成就的主要动机。

面试

  • 与主流观念相反,大多数面试官决定雇用某个人其实是基于各种各样的非技术因素。

  • 简而言之,通过面试的最快捷的方式是让面试官对你怀有好感。达成该目标有很多方法,其中大多数可以在面试之前完成。

  • “破解”面试的要诀就是在面试开始之前就思考应对面试的策略。

  • 与雇用技术高超但需要生拉硬拽才能干活的人相比,我宁愿雇用这样的开发人员:知道的东西可以少一点,但是明确知道要做什么,以及怎样去做。从某种程度上,在你可控的范围之内,面试的时候你要集中精力证明自己就是无需督促也能自动自发做好事情的员工。

  • 你还必须要证明:在技术上你确实胜任工作。同时,如果你能说服面试官相信你非常能干,不会被困难阻挡,那么他们不仅会喜欢你,而且更有可能会录用你。

专业化

  • 专业化的规则是:专业化程度越深,潜在的机会就越少,但获得这些机会的可能性越大。

  • 做一个技术全面、多才多艺的软件开发人员非常棒。能够使用多项技术和多种编程语言,有助于你的职业发展,能让你比那些仅了解一项技术或一种编程语言的软件开发人员更有价值。然而,这种“万金油”式的人才在市场上并不吃香。

  • 从薪资和福利的角度评价一个潜在的工作机会是很容易的,但是从长期发展和工作环境的角度去评价可能对你更为重要。

大中小公司

  • 在为一家大公司工作时,你会注意到的最大的事情也许就是那里大量的规范和流程。

  • 在大公司工作时,你要遵守这里已有的做事方式。鲁莽和“变节者”在这种企业文化里不受欢迎。

  • 在大公司里倒是很容易就隐藏在芸芸众生之中。在我曾供职的几家大公司里里,有一些开发人员基本上终日无所事事,除非赶上一轮全公司范围内的大裁员,否则根本不会有人注意到他们。不过,这种自主权也可以被善加利用。你能够去琢磨自认为重要或有趣的项目,无需背负产品压力。

  • 如果公司的业务重心并非软件,那自然也不会给软件开发人员足够的尊重和发展空间。这些公司的软件开发实践极有可能非常松散。

  • 另一方面,那些以软件开发为生的公司则会更重视自己雇用的软件开发人员的价值。他们的工作环境不一定会更好,但会大不一样。

  • 在推行敏捷软件开发方法的时候,这两类公司之间的差异非常明显。软件为非核心业务的公司在采用敏捷过程中困难重重,这是由于敏捷过程通常是由开发团队驱动的。敏捷过程需要自上而下地采纳推行,但是仅仅因为一些开发人员认为敏捷是个好主意,就让公司改变自己的做事风格,异常困难。

突颖而出

  • 在任何公司里能让你脱颖而出的最重要法宝就是承担更多的责任。

  • 没有人愿意涉足的领域是搜寻机会最好的地方。

  • 如何能让自己承担更多责任
    有一个不受重视的项目,你能去负责它吗?
    你能帮助团队里的新人快速成长吗?
    你能负责文档制作流程,并保证及时更新这些文档吗?
    哪项工作是没有人愿意去做,你愿意承担起来,并将其简化或者自动化的?

  • 如何令自己引人注目
    每天都记录自己的活动日志——把这个日志以周报的形式发送你的经理。
    提供演讲或培训——选择一个对你的团队有用的话题。
    发表意见——只要在会议上就这么做,或者只要你能得到的机会就这么做。
    保证“曝光度”——定期与老板会面,确保你经常被注意到。

  • 在任何公司中,最有用的就是那种看似没有克服不了的障碍的人。

  • 有时候只要意识到自己的工作毫无前途,就需要寻找更好的机会。也许你的工作环境很艰苦,残害身心,也许裙带关系盛行,你只能原地踏步。无论什么原因,你可能都需要换工作了。

成为专业人士

  • 成为专业人士是一种心态。如果我们总是与恐惧、自毁、拖延和自我怀疑作斗争,那么问题就是:我们正在像外行那样思考问题。外行毫不起眼,外行人废话连篇,外行屈从于逆境。专业人士可不这么想。不管怎样,他引人注目,他恪尽职守,他始终如一。

  • 成为专业人士的全部在于:引人注目,恪尽职守,以及不屈服于挫折。

  • 专业人士会严肃对待自己的责任和事业,愿意作出艰难的选择去做自己认为是正确的事情——往往还要自己承担代价。

  • 作为一名专业人士需要养成的另一个强大的习惯是时间管理技能。

  • 有时候,专业人士必须对工作的优先级做出艰难的抉择。

  • 专业人士会评估需要完成的工作,判定优先级后再开始工作。

  • 专业人士是通过持续不断的自我完善达到自己所追求的高品质的。

为自己工作

  • 如果想辞职为自己打工,需要一个切实可行的计划。你必须要想方设法积攒够足够多的收入来支撑自己,直到你的新生活步入正轨。

  • 如果你想让自己的产品也同样成功(虽然也许在规模上达不到),首先打造一个成功的博客,使用播客、演讲、视频和其他媒体来发展自己的受众。接下来,一旦你有了受众,你就能够向这些受众销售自己的产品。你之所以购买这本书可能就是因为你已经是我博客的粉丝,或者因为关注我的其他工作而无意中发现这本书,或者你之前听过我的播客。这就是发展自己的受众的威力。

  • 你必须明白并意识到,自己的首次创业可能会失败,很可能第二次、第三次也是如此。直到经过足够多的失败,你才可能真正成功。如果你倾尽所有投入创业,如果你为一次创业成功赌上自己的整个未来,你可能会把自己置于绝境——没有资源,甚至没有意志再去尝试一次。所以别这么做。从小处着手,作为副业开发你的第一个产品。

  • 我们不能过分相信自己可以不受外界干扰或者能够智慧地管理时间。我们需要提前做好计划,否则会屡屡经受不住诱惑。

对技术保持开放

  • 如果你能让自己不成为某种技术的信徒,你会在职业生涯之路上走得更远。

  • 没有理由去强烈坚持自己选择的技术就是最好的,而轻视甚至无视其他技术。如果固执己见,最终受损失的是你自己。

  • 另一方面,如果你愿意技术保持开放的心态,而不是固守在自己已经了解的技术,声称它是最好的,你会发现有更多的机会为你敞开大门。

第二篇 自我营销

  • 营销就是一场争夺人们注意力的竞赛。

  • 营销追求的是“实现价值在先,要求回报在后”。

  • 自我营销的正确方式就是为他人提供价值。

  • 只要营销得法,即便是“菜鸟”或者“业余爱好者”的身份都是你的优势所在——很多人都喜欢向只比自己稍微优秀一点点的人学习,因为这些人才是可望而又可及的。

  • 自我营销的基本机制是,要想让人们追随你、倾听你,你就要带给他们价值:你能为他们的问题提供答案,甚至是给他们带去欢乐。如果你在持续自我提升的同时并没有给他人带来价值,那么你终究不会走得太远,因为每个人都会离你而去。

  • 要打造一个品牌,你需要四个要素——品牌所要传递的信息、品牌的视觉符号、品牌的一致性和品牌的曝光率。

打造自己的博客

  • 即使你对上面提及的博客能带给你的所有好处都打了折扣,有一个好处是你无法轻易抹杀的——提高你的沟通技巧。组织自己的思想,并将其转化为文字,是一项颇具难度却也极具价值的技能。

  • 定期写作能帮助你打磨此技能,有了很好的沟通能力会让你在生活的诸多领域受益。此外,如果你能约束自己定期更新博客,你也就在持续刷新自己的技能,保证自己处于自己所在专业领域的前沿。

  • 作为软件开发人员,学习如何写博客实际上都能帮你写出更好的代码,因为你能更轻松地传达自己的意图。博客还能帮你更好地传达自己的想法,令想法更有说服力。

为他人增加价值

  • 不要努力成为一个成功的人,而要努力成为一个有价值的人。——阿尔伯特·爱因斯坦

  • 当你营销自己的时候,如果你所做的一切都只是为了自己的利益而不给别人带来真正的价值,那么即使你所做的都正确无误,那也无济于事。

  • 人们最关心的还是自己。没人想听到你的成功故事,也不想知道为什么他们要帮你获得成功,但是他们肯定想听到你会怎样帮他们获得成功。所以,要想让自我营销的所有努力奏效,基本的方法就是帮助他人获得成功。

  • 免费内容比付费内容更容易被分享。你撰写博客、制作视频或者播客,然后将这些内容免费提供,与收费内容相比,人们更可能会分享和传播这些免费的内容。分享免费内容就跟在Twitter上发链接或发邮件一样简单。与付费内容相比,免费内容能让你触及更多的目标受众。

  • 虽然免费做这些事情看起来是在浪费时间,但是你要把它视为对未来的一项投资。通过为人们创造价值并且免费提供这种方式自我营销,你就赢得了为他人提供价值的声誉,也为自己的未来创造了机会。这种声誉的价值是无法衡量的。它能帮你赢得更好、更高薪水的工作,获得更多的客户,或者成功地发布一款产品。

  • 你很容易落入这样的陷阱:一直谈论自己并试图证明自己价值连城。然而,你会发现,能解决他人的问题,真正能够帮到他人,你更容易获得成功。

  • 帮助他人实际上就是在帮助自己获得成功。

克服恐惧

  • 如果你真的想在自我营销方面获得成功,你就一定要学着克服我们大多数人都会有的一种恐惧——看起来像个傻瓜。

  • 如果你想成功,你必须要学会收起自己脆弱的自尊心,勇敢走出去,别害怕让自己出丑。

  • 在我的职业生涯中,我一共错失了9000多次投篮,输掉了近300场比赛。我本来有26次绝杀的机会却投球不进。我失败了一次又一次。这就是我能够成功的原因。——迈克尔·乔丹

第三篇 学习

  • 教育就是当一个人把在学校所学全部忘光之后剩下的东西。——阿尔伯特·爱因斯坦

  • 软件开发人员可以学到的最重要的一项技能就是自我教育能力。

  • 无论如何,学会学习是自我教育的核心技能。

  • 最好的方法就是付诸于实践,如果你也能承担将自己所学的内容教给别人的任务,那么你会理解得更深刻。所以,你在自我教育方面的努力,应该聚焦在如何让自己切实参与,并且尽早付诸实践。

  • 我觉得学习知识的最好方式就是立即将其用于实践,即使你还不知道自己在做什么。

让学习玩起来

  • 如果关于某个主题你能够获得足够的知识能够操作,你就可以发挥自己心灵深处强大的创造力和好奇心。当我们能够在一件事情上尽情发挥的时候,我们的内心就更倾向于吸收更多的信息,思考更有意义的问题。这似乎有些奇怪,但事实的确如此。

  • 本方法的关键指导原则是通过玩儿、探索以及将自己所学教给他人来学习。这一简便易行的方法更符合我们的天性——在某种程度上,抛弃了“填鸭式教学”的自主学习才是最简单和最纯粹的学习方式。

如何快速学习

  • 我发现,为了能够掌握一门技术,我需要了解以下三个要点。
    1.如何开始——要想开始使用自己所学的,我需要掌握哪些基本知识?
    2.学科范围——我现在学的东西有多宏大?我应该怎么做?在开始阶段,我不需要了解每个细节,但是如果我能对该学科的轮廓有大致的了解,那么将来我就能发现更多细节。
    3.基础知识——不止在开始阶段,要想使用一项特定的技术,我需要了解基本的用户案例和最常见的问题,也需要知道自己学的哪20%就能满足80%的日常应用。

  • 熟知了这三个关键点后,我可以高效地学习一门技术,无需通晓全部细节。我发现,如果我了解三项主题——如何开始,我能做什么,以及相关基础知识,那么我就能随着学习深入学会所需的其他知识。

  • 如果我想提前掌握所有知识,那只是在浪费时间,因为真正重要的内容会湮没在那些细枝末节中。

  • 这种新方法能让我关注重点。当我确实需要了解更多细节时,我可以利用参考资料来弥补这些不足。

  • “十步学习法”的基本思想就是:要对自己要学的内容有个基本的了解——了解自己不知道什么就足矣。然后,利用这些信息勾勒出学习的范围,即需要学哪些内容,以及学成之后又会获得什么。依靠这些知识,你可以找出各种资源(不局限于书)来帮助自己学习。最后,你可以创建自己的学习计划,列出要去学习哪些相关课程,筛选学习材料,只保留能帮助自己达成目标的优质内容。

“十步学习法”体系

  • 一旦完成这些工作,你对自己要学什么和怎样学都了然于胸,你就可以把控自己的学习计划中的每个关键点,通过“学习—实践—掌握—教授”(Learning, Doing, Learning and Teaching,LDLT)的过程,获得对该学科的深刻理解,同时你也向着自己的目标前进。

  • “十步学习法”的第一部分是研究,它是一次性完成的。但是从第7步到第10步则是重复的过程,贯穿于你的学习计划的各个模块。这个方法非常奏效,因为它迫使你提前明确自己的学习目标,也持续不断的激励你通过实践(而不仅仅是读书或听讲座)向着目标前进。

  • 通过“聚焦学习范围,让你关注重点内容”来学习的一种快速学习方法,它迫使你通过“自我探索”和“主动教学”的方式将真正重要的内容印刻在自己的大脑中。

  • 在学习过程中,大家很容易犯的一个错误就是试图解决太大的问题而把自己搞得不堪重负。

  • 你无需提前了解全部内容,你要做的首要的一件事情就是亲自操作和亲身体验。

  • 采用这种方法,你通过探索和实践进行学习。

  • 把那些暂时还没有答案的问题记录下来,你在下一步中会有机会找出这些问题的答案。

  • 不要害怕回头再去操作,付出更多,因为这不仅能让你找到问题的答案,也能让你学到新东西。给自己足够多的时间去深入理解自己的主题,你可以阅读,可以实验,可以观察,也可以操作。

  • 不过请记住,你依然没有必要把收集到的所有资料全部仔细看一遍。你只需要阅读或观看与当前所学相关的部分。我们很少能有足够的时间把一本书从头读到尾。

  • 这些资料只是帮你自学,基本上你可以以解决在动手操作中发现的问题为主要目的。

  • 做导师的好处
    帮助他人时的成就感。
    深入学习和领悟知识的途径。
    你的徒弟有朝一日会帮到你。
    自身的成长。
    帮助别人成长的过程也就是自己成长的过程。

  • 学习知识的一大方法,或许是唯一可以做到深入学习的方法,就是传道授业。

  • 知识短板会阻碍你进步。准确识别它们的最佳方式之一就是看看自己在哪些工作上花费了大量的时间,或者一直进行重复性劳动。通常,你会发现,自己的知识短板使工作速度放缓,额外需要大量的时间完成任务。

  • 另一种识别知识短板的方法就是,时刻都要试图了解自己不理解或不清楚的事物。你可以维护一份清单,列出自己需要去研究或者自己不清楚的所有事物,追踪有哪些主题总是不断出现在这个清单上。你会惊讶地发现这份清单的增长速度有多快。你只要对自己坦诚:如果遇到不理解的知识,不需要马上就学会,但是一定要把它添加到清单中,这样你至少可以找出自己的知识短板。

  • 假如你在准备面试,需要明确自己要学什么,这一方法最管用。尽量找出尽可能多的你在面试中可能会被问到的问题。

  • 检查知识短板

第四篇 生产力

  • 产量多只表明生产效率高,只有完成正确的工作才会成为高效的人。

一切始于专注

  • 想要达到专注工作的状态很难,但是一旦进入专注状态,就能轻松保持。

  • 要进入专注模式,必须要克服将自己的思绪集中于单一任务时的那种痛感。除非你完全享受完成这项任务,否则这种痛感一开始会很强烈。但是,这正是关键所在。你必须要意识到,这种痛苦和不适只是暂时的,不会持续很久。

工作计划

  • 我的计划都是从“季度”开始的。我把我的一年分成4个季度,每个季度3个月。在做季度计划时,我会尽力列出我想在本季度完成的每一个大项目,我还会制订一些较小的目标。我会思考我在每一周或每一天分别完成哪些工作。

  • 每个月的第一天我会打印出当月的月历,并且规划出每天要完成的工作。

  • 每个月我都会将该月要完成的所有任务列入计划。

  • 每周一的早晨,我会做我的周计划。

番茄工作法

  • 它的基本思路是:你规划出打算一天之内完成的工作,然后设置一个时长25分钟的定时器,去完成计划中的第一项任务;在这25分钟之内,你只专注于这一项任务,心无旁骛。一旦有干扰,可以用各种方法屏蔽掉干扰,但是通常你要努力保证自己完全不被打扰。总之,你不希望自己的专注的工作状态被打断。

  • 在25分钟结束的时候,设置一个5分钟的定时器,休息一下。这就是所谓的一个“番茄钟”。每4个番茄钟后,你都需要休息一会儿,通常为15分钟。从技术上讲,如果提前完成任务,你应该将剩余时间设置为“过度学习”时间。也就是说,你需要继续对已完成的工作做出小幅改进,或者重新阅读材料以便于你能够再学一些新东西。我往往会忽略这部分,立即跳转到下一个任务。

  • 这就是“番茄工作法”的基本流程。它就是这么简单。弗朗西斯科最初使用了一个番茄形状的厨房定时器给自己设置番茄钟

  • 第一次使用番茄工作法的时候,我并没有严格做到它规定的要求。我只是每天用它来设置若干个“25分钟”的番茄钟。我并没有留意自己每天完成了几个番茄钟,也没有估算某项任务要用掉几个番茄钟;因此我并没有从中受益。

  • 有一个大问题一直困扰着我:我总为自己没有做更多的事情而感到内疚。这与我一天完成多少工作无关,就好像我永远不能放松似的。我总觉得自己应该在做事,以至于坐下来玩游戏(我最喜欢的消遣之一)时我都无法享受其中,因为我觉得自己在浪费时间,我本应该做更多的工作。也许你也有同感。

  • 这个问题的根源在于,你无法准确地评估每天到底自己完成了多少任务,也没有为自己每天到底要完成多少任务设定明确的目标。

  • 制订任务列表全凭主观臆断,每天能够专注完成的工作量才是最重要的。

  • 这正是番茄工作法的真谛之所在。当你在一天中为自己设置了x个番茄钟的工作目标(这一目标你完全可控)并且达成的时候,你就可以知道自己一天到底可以完成多少工作,这会让自己感觉良好,更重要的是,还能让自己放松身心。

  • 对番茄工作法的正确理解令我的工作生活大为改观,它不仅能帮我能做更多事情,而且能让我可以尽情享受业余时间。一旦我完成了当天的目标(以番茄钟来度量的),我就可以自由自在地做自己想做的事情。

  • 如果我觉得自己状态不错,我可能还会多做一些工作。但是,如果我想坐下来玩游戏,甚至看电影消磨时间,或者其他不费脑子的活动,我也不会感到内疚,因为我知道我已经努力工作一整天了。

  • 如果你使用番茄工作法度过充实的一天,你完成的工作的要比平常完成的多很多。好消息是,你的生产效率更高;坏消息则是,你需要花一段时间才能适应它(我没骗你)。

  • 我一周的目标是50~55个番茄钟。如果我可以达成目标,我就知道自己做得很好,也能希望每周都能持续改进目标。

  • 如果你也打算采用番茄工作法,要先确保你对自己的能力有符合实际的预期。你每周工作40小时并不意味着你能完成80个番茄钟。(如果你能实现这一壮举,我会大吃一惊的。而且,坦白讲,我会担心你的心理健康。)

  • 每人每天能够专注地、富有成效地工作的时间是有上限的。你的时间只有这么多,要怎么利用你自己说了算。

定额工作法

  • 我用“定额工作法”确保自己每天、每周都朝着自己最重要的目标取得明确的、可度量的进展。

  • 我开始意识到,要想确保自己在追求目标的道路上获得持续的进展,唯一的方法就是确立一个明确的目标,规定自己要在预先确定的时间段内需要取得多大的进展。

  • 实行定额制后,我发现自己的工作成果比以往多了很多。最大的好处在于,长期坚持这么做,我就能随着时间的推移度量并标记自己的进度。我可以确切知道自己在给定的一段时间内能够完成的工作量。

  • 承诺是“定额工作法”的核心。除了想方设法完成自己的工作,不给自己留下任何其他的选择。在你心中,失败不是一个可以被接受的选项。因为如果你让自己失信一次,就会有第二次,很快定额在你眼中就会变得一文不值。

  • 如果你的承诺力度不够,“定额工作法”顷刻就会分崩离析,所以你必须选择可实现、可持续的定额。不要对自己承诺自己明知不可能达到的目标,否则你就把自己逼入注定失败的绝境。开始的时候承诺可以小一点,在能够达成之后再逐步做大胆的承诺。

  • 定额工作法的规则
    挑选一项重复性任务。
    明确有效时限,在此期间该任务被重复执行。
    明确在给定的有效时限内该任务应该完成的次数的定额。
    给自己承诺:一定要达成定额。
    调整。调高或者调低定额,但是不能在有效时间段之内调整。

  • 定额工作法成功的秘密可以追溯到“龟兔赛跑”的故事。以缓慢但稳定的节奏工作,要优于快速但缺乏持久和坚持的工作方式。

  • 定额工作法还可以帮你克服意志力薄弱的问题,通过预先设定好的必须要遵循的过程,消除需要做出决策的部分。因为已经预先承诺在规定时间段内完成同一任务很多次,所以就不需要再判断要不要做某事——你知道必须要做。每一天,任何需要做决策的时刻,你都不得不被迫动用自己仅存的有限的意志力。以定额的形式将决策转变为命令,你无需再做决策,也就避免了意志力耗尽的问题。关于这一主题,可参考Kelly Mc Gonigal写的《自控力》

  • 采取行动
    列出自己生活中需要重复做的所有任务。特别要专注于那些目前你还无法持续完成但一旦完成就会从中受益的事情。
    选择至少一项任务,承诺在规定时间段内要完成的额度。认真对待这一承诺,试着坚持至少5个时间段。想象一下,如果自己能坚持几个月或几年,会发生什么。

对自己负责

  • 让人们完成工作主要有两大动机——内部动机(来自内心的动机)和外部动机(来自外部奖励或惩罚的动机)。

  • 内部动机要比外部动机有效得多。在内部动机的激励下工作时,我们能完成更多的工作,也更倾向于把工作做得更好。所以,秘诀是让你的主要动机来自内心而非外部。

  • 培养出在没有人监督自己的时候也能高效工作的自我责任感非常重要。

  • 要培养“对自己负责”的精神,首先要让自己的生活井然有序。

  • 你可能会发现,只对自己负责的时候很容易违反自己制订的规则。在这种情况下,需要借助一点儿外力。你仍然可以制订自己的规则,因此动机还是来自内部——因为你还是规则的制订者,只是你可以让别人帮你强制执行这些规则。

  • 请别人来监督自己履行责任,完成自己的承诺,并没有坏处。找到责任监督伙伴——理想情况下,最好是跟你有类似目标的人,这样会很有帮助。你可以告诉他你给自己制订的规则,或者你想达成的目标,通过定期互相汇报进度(不论成败),可以互相帮助对方强化责任感。

  • 通常,想到要告诉自己的责任监督伙伴自己没能完成设定的目标,就足以阻止自己不够自律的行为。

  • 采取行动
    抉择一下:你想如何度过自己的一生。花点儿时间创建一些自己的规则,确保自己朝着正确的方向前进。
    创建自己的责任制度,帮助自己严格执行规则。

是否多任务并行

  • 有的任务适合多任务并行,有的则不适合。如果你真想最大限度地提升自己的工作效率,就必须知道什么时候需要多任务并行,什么时候不需要,以及如何高效地进行多任务并行。

  • 对于很多活动,我们可能会自认为是在进行多任务并行,但实际上我们做的不过是在不断地进行任务切换。这样的任务切换看起来确实是工作效率下降的罪魁祸首。任务切换越多,浪费的时间也就越多,因为你的大脑并不能专注于一项任务。

  • 如果你认为自己出于专注状态时工作效率最高,且需要花些时间才能到达这种状态,你就能明白,在各种任务间快速切换并不会提高效率。

  • 真正的多任务并行使我极大地提升了自己的生产力。如果你可以将两项任务组合起来,并且真正做到同时处理它们两个,你才能完成更多。诀窍在于搞清楚哪些任务可以被真正组合起来而不会降低单独执行每项工作的生产效率。

  • 我发现,最有可能的就是,将一项不费脑筋的任务和一项一定程度上需要精神专注才能完成的任务组合起来。现在,我正一边听着耳机里的音乐一边打字写这一章。当然,听音乐本身并不是一项富有成效的工作,不过事实证明,在写作的时候听音乐能让我比单纯写作更富有成效。音乐似乎能让我写作更流畅,还能帮我减少其他会分散注意力的外界干扰。

  • 再来一个更有效率的例子?我通常会尝试把体育运动与培训活动组合在一起。在健身房跑步或举重的时候,我经常会听有声读物或者播客。我发现,一边做健身活动一边听一些培训材料没有任何负面影响。通过一边健身一边听有声读物,我已经读完了很多书。

  • 采取行动
    停止任何并非真正的多任务并行的多任务并行。每天力争在一个时间段内只做一件事。番茄工作法对此有很大帮助。
    一次性批量处理小任务,而不是每天或每周里做许多次。
    找出能够真正实现多任务并行的领域。任何不需要耗费脑力的活动都可以跟其他活动结合起来。只要进行任何需要耗费脑力的活动,就将其与体育运动结合起来。

职业倦怠

  • 提高生产力的最大障碍之一就是身体和心理上的倦怠。

  • 项目刚开始的时候,我们总是热情高涨、精力旺盛,但是一段时间之后,即便我们再有激情,一想到它们也会让我们反胃。

  • 如果能咬紧牙关坚持到底,如果能穿越那堵墙战胜自己,最终你会发现,简单地无视它的存在,你的倦怠感已经不治而愈。经历痛苦就是克服倦怠的秘诀。你以后还会撞到更多的墙,但每穿越它一次,你将会体验到全新的动力、充沛的活力。另外,你的竞争者的数量会越来越少。

  • 本质上,你需要为自己创建一套确保自己继续前行的规则。
    你需要突破这堵墙就以写这本书为例。刚开始动笔的时候我兴奋极了,想不出来有什么能比坐下来整天写“自己的书”更有趣的事情了。但是,没过多久这种新鲜感就消失殆尽。但是,你能读到这本书就证明我已然坚持到了最后。我是如何在动力和兴趣消失殆尽的时候坚持到底的呢?我为自己设定了一个时间表,并且坚决执行。无论刮风下雨,无论自己感觉如何,我都坚持每天写完一章。有些日子还会多写一点儿,但是总是保证至少一章。你可以采用类似的方法来帮自己突破阻挡了你的那堵围墙。想学会弹夏威夷四弦琴?每天留出一定的时间练习。在上第一堂课之前就制订好这样的计划——那时你的兴趣和动机都处于最高点。当你不可避免地撞到这样一堵墙的时候,这个计划能帮助你穿过它。

  • 采取行动
    想一想以前都有哪些项目是你付出努力却没有最终完成而半途而废了。是什么原因让你放弃的?你现在对这件事儿有什么感受?
    下次开始新项目的时候,下定决心:你一定会完成,或者完全掌握。设定规则和约束条件,强迫自己穿过那堵不可避免的墙。
    如果你正面临职业生涯或者个人生活中的一堵墙,试着去穿越它。想想在墙的另一侧会有怎样的收获等着你。想象自己的动机和兴趣终将获得回报。

时间杀手

  • 一些常见的时间杀手
    看电视。
    社交媒体。
    新闻网站。
    不必要的会议。
    烹饪。
    玩电子游戏(尤其是网络游戏)。
    工间喝咖啡休息。

  • 地雷:烹饪、工间喝咖啡休息或者其他你喜欢做的事情是在浪费时间吗?也是也不是。答案取决于你为什么做这些事情。为了享受快乐有意识地做这些事情,就不是浪费时间,只要你是因为喜欢才特意做这些事情,而不是为了逃避自己应该完成的实际工作。我曾经把玩电子游戏视为浪费时间,但是我喜欢玩电子游戏。这是否意味着我要完全放弃玩电子游戏呢?不是的。但是,当我有任务需要完成的时候,我就不能玩电子游戏。我不能用玩电子游戏来逃避自己本该完成的工作。同样的原则也适用于烹饪。也许你喜欢烹饪,为自己制作健康美食。如果是这样,那就太棒了。但是,如果你不特别喜欢烹饪,却要耗费大量时间来准备简单的一餐,那你就需要找出其他的健康饮食的方法来减少用于烹饪的时间。我的目的不是让你抛弃生活中的喜好,只是确保你没有把时间浪费在一些没必要做或者不那么喜欢做的事情上,或者吞噬掉你所有业余时间的事情上。

  • 采取行动
    下一周,你精心地跟踪一下自己的时间花费情况。获取精确的数字,了解每天的每小时你都是怎样花掉的。看看数据,找出你最大的2~3个时间杀手。
    如果你有看电视的习惯,尝试离开电视一周,即尝试度过一个“无电视周”,看看如果不看电视你都会做些什么。
    弄清楚哪些时间是可以“买回来”的,如雇人为你修剪庭院、做保洁等。(如果切断有线电视,你甚至可以用这笔省下来的钱来支付上述费用。)

形成惯例的重要性

  • 生产力的真正秘诀在于:长期坚持做一些小事。

  • 他们没有意识到,横亘在自己与梦想之间的无非就是“惯例”。惯例塑造你的生活,让你变得更有生产效率,惯例是让你实现目标最强大的方式之一。你每天的行为日积月累下来,可以让你生活的每个方面都得到提升。

  • 每天都安排时间处理这些任务,以便你可以确保它们被完成。当我在办公室工作的时候,每天我会抽出30分钟时间学习自己工作中会用到的技术,我习惯将其称为“研究时间”。

  • 每天的生活越有条理,就越能把控自己的生活。

  • 想想看,如果你一直对外界作出反应,如果你总是在事情出现的时候被动地处理事情而不是主动地规划,那么周围的环境会左右你的生活,而不是你自己。

  • 例行安排示例

  • 地雷:注意不要过于沉迷于惯例你应该有自己遵循的惯例,但是也要有一定的灵活性。你可能会打乱一天的日程安排。不要忘记会有像车坏了这种不可预测的事件发生,车坏了可能会打乱你的例行安排。你需要学会从容应对这些事情。

  • 采取行动
    你目前有哪些惯例?跟踪一下你的日常活动,看看你已经在遵循的惯例有哪些。
    选择一个大目标,以每个工作日为单位制订例行安排。计算一下,如果你每天都朝着这个目标前进,一年下来你会取得多大的成就。

培养习惯

  • 成就我们的恰恰就是那些不断重复做的事情。因此,优秀不是一种行为,而是一种习惯。——亚里士多德

  • 我们每个人都有习惯,有好有坏。好习惯能够推动我们前进,帮助我们成长;坏习惯则阻止我们前进,阻碍我们成长。培养和养成良好的习惯可以让你不需要刻意努力就保持很高的生产效率。如同惯例可以帮我们缓慢而坚定地每次只砌好一块砖,最终建起一面巨大的墙一样,习惯也可以通过日积月累的努力,让我们前进或者后退。二者最大的区别在于,惯例是我们可以控制的,而习惯却不受控于我们。

  • 习惯主要由三个要素构成:暗示,惯例和奖励。

  • 我们的大脑非常善于养成习惯。我们会根据周围的事物自发地养成习惯。一件事情做的越多,越可能形成习惯。习惯的力量往往基于奖励的价值。我们都喜欢做能够带来更好回报的事情。然而,奇怪的是,可变化的奖励要比已知的标准奖励更让人着迷。这就是在赌场能看到那么多人的原因。不知道自己是否能得到奖励或者不知道奖励有多大,会形成一种很坏的习惯,即公认的“上瘾”。

分解任务

  • 造成拖延的首要原因之一,同时也是造成生产力低下的祸根,就是总是在感慨一个问题:好忙啊,问题好大啊……实际上,你并没有真正试着去解决问题。当我们从任务的全貌来审视任务的时候,它们看起来比真实情况都要大,并且更吓人。

  • 克服拖延的提高生产力的窍门:分解任务。通过将大任务分解为小任务,你会发现自己更有动力去完成它们,也更加稳妥地向着目标前进。

  • 这些大任务或大项目给我们带来了心理上的伤害,也削弱了我们的生产力——因为我们无法看清楚未来的前景。从宏观上审视一项大型任务的全貌时,它看起来几乎是不可能完成的

  • 大型任务给人带来沉重的心理负担。面对大问题时,我们倾向于花更多的时间思考问题本身,而不是采取行动去解决问题。人类倾向于选择阻力最小的路径。

  • 但是拖延还不是我们不喜欢大型任务的唯一原因。任务越大,越难明确定义。

  • 大型任务往往也很难估算完成时间。

  • 大型任务是一种智力挑战,与小任务相比,大任务更可能导致拖延,通常描述也更少,更容易出错,也更难估算完成时间。

  • 当把任务分解成小块的时候,这些任务就变得更易于完成,对完成任务所需的时间的估算也更精确,你也更有可能正确地完成它们。即使有些小任务没有正确完成,你也有很多机会改正,而不至过多地影响大项目。我发现,把大任务分解成小任务真是一个好主意。

  • 在管控代码的复杂程度问题上,我们也会做一些工作。这就是我们不会将所有的代码都写入一个方法中的原因。我们会将自己的代码分解为方法、函数、变量、类以及其他结构,从而简化代码。

  • 不管编程问题有多难,它总是可以被分解为更小的单元。如果你想要写出一个难度很大的算法,在一头扎进去写代码之前,先把这个问题分解为能够依次独立解决的小模块会更有帮助。无论应用程序多么庞大、多么复杂,它都可以被分解成一行行的代码。单独一行代码的复杂度绝对不会超过任何一位程序员的理解能力和编码水平,所以,如果你愿意将问题分解得足够小,只凭借写出单行代码的能力你就能写好任何应用程序。

努力工作的价值

  • 现实的情况是,一切有价值的东西无一不是努力工作的结果。生活中,特别是在软件开发的职业生涯中,如果你想看到成果,你就必须要学会坐下来,做好自己并不想做的工作——并且要坚持不懈。

  • 如果真想富有成效,你就不得不学会工作的时候既聪明又努力。光有聪明是不够的。一定量的机智是必须具备的,然而要想获得真正的成功,面对挫折的时候一定量的毅力也是必要的。

  • 努力工作总是枯燥的如果我必须猜测一下,为什么我们逃避艰苦的工作,我会说这是因为它们太枯燥了。在我刚开始写博客的时候,我很兴奋。我对这个表达自己的机会充满热情。然而,随着时间的推移,它变成了一项苦差事。如果我没有学会坚持,设法应对这项单调乏味的苦差事,我就不可能看到自己的行动的好处。

  • 你必须认识到,你要想实现目标,要想发挥出自己的全部潜力,唯一的途径就是自愿咬紧牙关、硬着头皮、开始工作

  • 你曾经投身到哪些艰苦的工作中?有哪些任务你会因为不喜欢而拖延?找出其中一项任务,毫不犹豫地马上去做。养成雷厉风行的习惯,并且立即在需要做的工作中付诸行动。

任何行动都比不采取行动好

  • 任何行动往往都比没有行动好,特别是当你一直停滞在不愉快的情势下很长时间的时候。如果这是一个错误,至少你学到了一些东西。这样一来,它就不再是一个错误。如果你仍然选择停滞不前,那么你就学不到任何东西。

  • 很少有人会后悔自己基于所掌握的最好的知识采取的行动,但是很多人会后悔自己没有采取行动。他们错失机会,只因为过分害羞、谨慎或者犹豫,让他们裹足不前,无所作为。

  • 很多时候,你需要试错好多次之后才能找出正确的行动方向。在任何行动上耽误的时间越长,完成整个试错过程找出正确方向的用时也就越长。

  • 大多数我们急于做出的选择往往都是微不足道的。我们经常试图耗费300%的努力寻找95分的解决方案,而不是满足于找到90分的解决方案。我们的生活就是这样的,我们写代码的时候也是这样的,我们甚至在决策该买什么样的电视机时也是这样的。

  • 即使是一些看似重要的选择——改变生活的那种,用随机掷骰子的方式都比优柔寡断、无所作为要好。很多大学生认为,选择专业和选择职业都是非常重要的决定。尽管这一决定可能很重要,但也不会比其他选择更重要,有多少大学生毕业的时候只有华而不实的学位或者是泛泛而谈的专业正是因为他们没有做到当断则断呢?举棋不定、优柔寡断让他们丧失了采取行动的机会。

  • 跑起来的汽车更容易转向

  • 通常,要找出一个方向是错的,唯一的方法就是向着那个方向前进。如果错误的代价很小,有所作为总好过无所事事。

  • 现在要怎么做那么,如何将上述原理现在就应用于你的生活呢?今天你要怎么采取行动?仔细查看表48-1所示的简单的检查表,看看它是否能帮你下定决心采取行动。

  • 表48-1 采取行动时的检查表

第五篇 理财

  • 金钱只是一种工具。它会带你去往任何你想去的地方,但不会取代你成为司机。
    ——爱思·然德(Ayn Rand)

  • 即使你对此心存疑问,我也鼓励你认真思考一下:改变财务状况会如何显著地改变你的生活,改变你在职业生涯中所做的决定。

  • 所谓资产,是指实用价值高于维护成本的东西。也就意味着,一样东西如果有资格被定义为“资产”,必须能够带来比自身成本更高的价值。

  • 但是,负债的含义则恰恰相反。所谓负债,是指成本高于带来的价值的东西。也就是说,要保有“负债”,你不得不往外掏钱,但是你永远也拿不回来与自己掏出的钱一样多的钱。

  • 关于资产,一个清晰的例子就是你持有的每个季度派发一次红利的股票。持有股票并不会花你分文,但是只要一直持有,每3个月它就会给你带来一次收入。股票自身的价格会上涨也可能会下跌,但是按照我的定义,只要它能带来红利,它就是资产。

  • 某些东西你买来后能够给你带来产出,或者产生的价值会高于你最初的投资,而别的东西则会消耗你的收入,或者不值你为它花的钱。

  • 如果想在财务上获得成功,就必须学会如何投资,别无选择。

薪酬谈判

  • 我强烈建议软件开发人员打造个人品牌,并积极地营销自己。

  • 为了做到这一点,基本策略就是尽可能让自己的名字出现在各种的媒体上。写博客、做播客、写书或文章、在大会或用户组中发表演讲、制作视频教程、为开源项目贡献代码等,尽一切可能让自己的名字出现在各种场合。

  • 获得工作的方式至关重要

  • 第一种,你看到一份招聘启事,然后发送自己的简历去申请该职位,最好再附上一封优美的求职信。事实上,许多求职者想当然地认为这是获得工作的唯一方式。其实,这是获得工作最糟糕的一种方式。如果以这种方式获得一份工作,很难在薪酬谈判时占据有利地位,因为和雇主比起来,你处于明显的弱势。你是竭尽所能渴望求得那份工作的人。

  • 需求最大的人在任何谈判中通常都会处于劣势。

  • 获得工作的另一种方法是通过他人推荐。

  • 你认识一家公司里的某个人,他们亲自推荐你应聘某个职位,最终你获得了这份工作。这种方式绝对要比自己申请职位好很多。

  • 你的最佳状态就是:一家公司知道你,然后无需任何面试就直接为你提供一个职位。在这种情况下,你尽可以根据自己的声望为自己标价。所以,任何时候,只要有雇主直接找你,你在谈判时就拥有有利地位。

  • 先出价者输

  • 你必须要了解的一条重要法则就是:先出价的人会处于明显的劣势。

  • 然而也有例外,唯一的例外会出现在雇主刻意压低价钱的时候。这种情况是非常罕见的,但是,如果你有充分的理由怀疑这种情况会发生,你可能会想先出价来设定个保底数。为什么?因为如果雇主给你的出价极低,你很难让他把价格抬高很多。当然,在这种情况下,无论你做什么,都不大可能成功。

  • 被要求先出价该怎么办千万不要先出价。直接说“不”。

期权

  • 期权背后的基本思想就是允许某人为在未来的某个日期买入或卖出股票的权利付费

  • 期权从根本上说就是赋予你在未来某个日期之前以固定价格购买一定数量股票的选择权。

  • 但你也可以购买另一种让自己在未来某个日期之前以固定价格出售一定数量股票的选择权。这种期权能让你在股价下跌的时候也赚钱,与附录B中讨论的卖空股票类似。

  • 允许在未来一段时间内以固定价格购买股票的期权被称为“看涨期权”,允许在未来一段时间内以固定价格出售股票的期权被称为“看跌期权”。

房地产

  • 在所有个人可以做的投资中,我认为房地产投资是目前为止最好的。再没有其他投资方式像房地产一样能够保障长期收益,能够允许如此高的资本负债。

  • 尽管房地产价格可能会大幅波动,但是我建议投资的是可租赁房产。这种房产的稳定的收入就是——租金。

  • 你选中的这处房产属于我们所说的“以租养贷”,意思是说所有费用,包括抵押贷款、税费和保险,都由它产生的租金收入来提供保障。在这种情况下,我们假设租金能够支付全部费用,不会有多余的现金流,或现金流很少。

  • 聪明的房地产投资(不是投机)始于认识到房地产投资是一项长期投资。如果你相信自己可以通过倒卖房产或者低价购买抵押房产而快速致富,那你终究会自食恶果。

  • 好的物业管理公司将会管理与物业出租有关的一切事务,包括寻找租户、确定租约、筛选租户、维修保养以及收取房租等。但是找到一家好的物业管理公司是很困难的。你要货比三家,找最诚信的物业管理公司。我因为能力不足、维修费用造假和玩忽职守等问题,至少解雇了三家物业管理公司。

退休计划

  • 事实是,在热带海滩上度过退休生活并非理所当然,也不只是60岁以上人群的专利。

  • 事实上,如果你希望乐享退休生活,你必须开始为此做一些计划,并且从现在就开始计划。

  • 一旦算出自己退休以后每个月的生活开销是多少,当你的“被动收入”达到每月所需的生活开销的时候,你就可以正式退休了。

  • 所谓被动收入,就是不用工作就能获得的收入。你必须确保被动收入会随着通货膨胀而增加——这也是说房地产是一个很好的投资选择的主要原因。

债务危害

  • 真正获得财务成功的唯一方法就是用钱生钱。

  • 采取行动
    列出你的所有债务的清单,把它们区分为两类:好的债务和不好的债务。
    把不好的债务按照利率从高到低排序,计算一下多久你可以清偿所有的债务。

额外馈赠

  • 相反,我把退休定义为“自由”,具体而言,即财务自由——一种不会囿于财务状况被迫用自己别无选择的方式将自己的时间花费在不合心意的事情上的能力。

  • 我从不追求永远不再工作,但是我一直追求在我不想工作的时候就不工作。这就是我目前的状态。我有足够丰厚的“被动收入”去对抗通货膨胀,如果我愿意,我也可以躺在沙滩上来一杯鸡尾酒;但是,我依然可以投身自己感兴趣的项目——那只是因为我想投身于该项目,而不是因财务原因必须投身于该项目。

  • 我的观点是,运气是必要的。我不会假装自己从来没得到幸运女神的眷顾,但在一定程度上,是你给自己创造运气。如果你脚踏实地、努力工作,总是尝试提升自己和周围的人,那你获得好运气的可能性会大大增加。等式的最后一部分是努力工作。Pluralsight的很多作者也有着和我一样的机遇。我不是说他们不努力,只是我更积极、更努力,我是Pluralsight课程库中课程最多的作者。为了让自己梦想成真,我静下心来工作到很晚,周末也不例外。

  • 仅仅获得机遇是不够的——即便这一机会千载难逢。你必须充分利用机遇,否则再好的机遇也没用。

第六篇 健身

  • 如果你不注意自己的身体健康,老实说我并不看好你能成为顶尖的程序员。

  • 在很长一段时间内,我都认为,在软件开发人群中教育和普及体育健身方面的知识是非常迫切的需要。在我刚开始从事编程工作时,软件开发人员的典型形象就是一个书呆子,瘦骨嶙峋,戴着一副厚厚的眼镜,活脱一付笔尖保护套的模样。现在,这一形象似乎已经改变,不过是变得更糟了。如今,很多人认为,软件开发人员都是胖胖的男士,留着络腮胡子,穿着一件脏兮兮的白色T恤还吃着比萨。

  • 显然这两种刻板形象都是错的——有很多软件开发人员,不管是男性还是女性,都不是这种形象,但是第二种形象比第一种形象更让我害怕,因为我觉得有些开发人员已经开始认为自己应该就是那样的。本篇的目的是让你了解健身的基础知识,鼓励你打破成见,并且让你认识到,身为软件开发人员并不意味着男的不能健康,不能英俊潇洒,女的不能光彩照人。你同样可以保持好身材,可以拥有健康,但一切都始于正确的教育和坚定的信念——相信这些都是可能的。

破解自身健康密码

  • 健身不仅是保持健康体魄的关键要素之一,也是灵活的、具有创造性的脑力活动的基础。——约翰·肯尼迪

  • 健身能让你成为更好的软件开发人员。这就是原因。

  • 自信心

  • 从我的个人经验出发,我可以告诉你,我锻炼得越多就越健康,我在工作中的表现也越好。我注意到,当我体能最好的时候,我的注意力最集中,效率也最高。

  • 当你总觉得疲倦、无心工作的时候,或者你觉得自己状态不佳的时候,你可能会发现,改变饮食和加强锻炼可以让你的身心同时获得新活力。

  • 恐惧我不想马上打出恐惧牌,但我认为它仍然是如此重要,值得一提。如果你体重超标、处于亚健康状态,那你罹患各种可预防性疾病的风险就很高。

  • 不要让自己醒悟得太晚,从现在起就认真对待。不要等到出了健康问题才开始关心自己的健康。

设定健身标准

  • 没有目标,你永远也达不成目标,健身也不例外。正如你需要知道自己写的代码是用来做什么的一样,你也需要知道在忍饥挨饿、挥汗如雨之后,你要得到怎样的结果,否则你就是在浪费时间。

  • 挑选一个具体的目标

    • 减肥
    • 增肌
  • 这些应用还可以帮你找到举重或者跑步的同伴,甚至能让你开始新的节食计划,或者向朋友发起挑战。与他人交流,分享自己的经验,不论好坏,都能让你的健身之旅更乐趣无穷,并能让你持久保持动力。我发现,当我有一个举重同伴的时候我总是更勤快地跑去健身房。

  • 计划了就一定要执行如果你能让自己持久保持动力,这确实很棒。但是,有时候不论有没有动力,你都得咬紧牙关坚持计划。一定要提前做好决定,这能给你约束,让你致力于自己想要采取的一系列行动。

  • 试着通过提前计划,尽可能减少生活中的各种抉择。

  • 当你的动力消失殆尽的时候,用原则来代替激励。每当我精疲力竭不想再跑步的时候,我都会用自己高度尊崇的“善始善终”原则提醒自己。为自己的人生创建一组格言,在世事艰难的时刻信守这些格言。

  • 人生格言
    善始善终。
    成功者决不放弃,而放弃者永远不会成功。
    一分耕耘,一分收获。
    时间短暂,如果想在生命中做某件事,现在就去做。
    一切都会过去。
    坚持到底就是胜利。采取行动
    列出你要健身或改善健康状况的原因。
    从这份清单中,明确三项最重要的激励因素,打印出来并张贴在不同的地方,确保自己每天都能看到。

如何增长肌肉

如何获得腹肌

跑步

站立办公

高科技健身装备

  • 本章介绍的都是能帮助你实现健身目标的或者能让你的健身过程更充满乐趣的科技装备。我们已经进入了全新的时代,当下我们比以往任何时候都更了解自己,了解自己身体的运转规律。这种自我认知也被称为“量化自我”。在本章中,我会带领你领略各种技术,并从中选出一些最有用的装本来帮你“量化自我”。

  • 步行计数器和计步器我觉得从步行计数器和计步器开始说起可能比较合适,因为它们是你现在能看到的最常见的科技装备。我是拥有某种计步器的超级粉丝,因为它不仅能帮你明确自己的实际运动量是多少,还能通过了解你的运动量来改变你的行为习惯,从而让你更有活力。

  • 它不仅能记录我的体重,还能记录我的体脂率。尽管体脂率读数的精确性有待商榷,但我更关心的是读数是如何随时间变化而变化的。尽管可能我获得的数据不够精确,但我能够看到相对变化,了解自己的体脂率是在升高还是降低。

  • 我强烈推荐我正在用的这款体重计,因为它能让你更好地了解自己的当前体重和变化趋势。有人说有了测量才能改进。即使你每天都站在体重计上,但只有看到体重随着时间的变化曲线时,你才会真正受到触动,向着正确的方向前进。

  • 组合设备健身科技最令人兴奋的领域莫过于组合设备了,尽管目前尚不成熟,但正被逐渐推广。这些组合设备能够通过各种传感器测量多个数据点,为你提供大量关于你的身体的信息。

  • 耳机在我锻炼的时候,最重要的技术装备就是耳机。我经常在锻炼的时候听播客或有声书,因此我需要一副可以插入手机的好耳机。

  • 应用我们也别忘了应用。市面上有大量针对各种锻炼目的的健身应用。

第七篇 精神

  • 精神如果你不征服自己,你就会被自己征服。——拿破仑•希尔

  • 我们不只是一个与思想相连的躯壳。我们不能只下达指示然后就期望身体能完成执行这些指令。这个世界存在着另一股很强大的力量,它能带领我们走上成功之路,把我们推向成功。你可以按照自己的意愿随意称呼这种力量,但是为了本书的目的,我称之为精神。

  • 我的目标是用工具武装你,征服你所面对的最强大的敌人——你自己。

心灵如何影响身体

  • 从心灵开始如果你不相信自己能够做到,你几乎做不成任何事情。你的思想对身体的影响有多大、对你能够获得成功的影响有多大,这是令人惊叹的。“如果你相信,你就能做到”这个观点很容易被迅速忽视,但是这个观点确实有些道理。至少,这个观点的反面更有道理:如果你不相信,你肯定不会获得成功。

  • 那些想要改变自己信念、控制自己想法的人们,通过积极的正念可以将其想要的变为现实。

  • 信念决定思想,思想决定言语,言语决定行动,行动决定习惯,习惯决定价值,价值决定命运。——圣雄甘地

  • 不管这个机制是如何运转的,重要的是你要理解自己的所思所想影响并塑造了你现在的生活。你甚至不用读这一章就可以证明这一点。看看周围就知道了。

  • 如果你真的想为自己的生活定好方向并控制好它,那你就要学会如何利用心灵的力量、思想的力量。

  • 采取行动
    找出心灵和身体之间的联系。试着在你自己的生活中找一个例子,什么样的想法给现实带来了积极的影响,什么样的想法又给现实带来了消极的影响?
    你最近一次取得巨大成功的时候心态是什么样的?
    你最近一次遭遇重大挫败的时候心态是什么样的?

拥有正确的心态

  • 让我问你一个问题:你将自己的想法归类为积极的还是消极的?这可不是给你自己贴上乐观主义者或悲观主义者的标签。有很多的乐观主义者,他们在表面上满怀期望和希望,但内心却怀着各种会直接破坏他们的工作成果的负面想法和情绪。实际上,积极思考的观点有科学证据可以支撑——积极思考不只是外表乐观,而且还对健康有益,能延年益寿,并且给你的生活提供其他的好处。同时——或许是更重要的——反过来想,消极的思考会产生完全相反的效果。消极思考会对你产生实质伤害,而且会妨碍你通向成功的人生.

  • 积极思考与现实主义是不矛盾的。事实上,积极思考在应用层面上是现实主义的最终体现,因为它是一种信念,这种信念让你有力量改变现实,让你确信你不是环境的受害者。

  • 积极思考问题的根源是这样一种信念——你比你随处的环境更伟大。这种信念让你总能先看到事物好的一面,因为无论身处何种环境,你都有能力改变自己的未来。这是人类成就的最高信念,是世界上最强大的力量。这种信念能让你利用这种力量,这股力量就静静地躺在你的心田,却又不那么虚无缥缈。

  • 积极的心态就是来自于这些想法的积累,随着时间的推移这些想法会由内向外地彻底改变你。当你拥有一个积极态度的时候,你就不是活在与现实分离的虚幻世界里,而是生活在一个最理想的世界里,一个你能看到的最理想的未来世界,一个你一直以来都在苦苦追求并努力实现的未来世界。

  • 从更现实的层面来讲,积极思考就是选择从好的一面(而不是从坏的一面)去思考问题。你对生活中遇到的每一种状况都可以有自己的理解。这些状况本身并不存在“好”或者“坏”。是你自己来解释这些状况,所以是你决定它是“好”的还是“坏”的。一个持有积极心态的人看到的好的一面往往比坏的一面要多,并不是因为这些状况客观上就是好的,而是因为他们认识到他们有选择的权利。

  • 积极性的正面作用记得当我说有真实存在的科学证据证明积极思考会对你的生活产生影响吗?我不是在开玩笑。这里有一份被证实效果的清单,这些效果都是由积极思考产生的。这些结果来自实际的科学研究:
    发展友谊;
    婚姻美满;
    收入更高;
    身体更健康;
    延年益寿。

  • 我知道的一个事实是,我的工作态度会直接影响我的工作表现。关于这一点,我是用自己的工作效率来做的度量。我知道,当我保持一个积极的态度时我就更愿意去面对任何障碍,把挑战看成要克服的困难,而不是消极地认为是环境把我逼到了绝境。

  • 如何养成积极思考的习惯呢?大多数情况下,使用养成其他任何习惯的方法就能养成这个习惯——通过坚定地、持续不断地、有意识地重复做一件事情,直到由潜意识来掌握大局。

  • 劳逸结合
    我个人可以追踪我的许多负面情绪与我忘记休息之间的关联关系。我发现当我花时间休息后更容易保持积极心态。可能这种方法没什么大不了,但是还是值得参考。

  • 一些帮助你养成一个积极心态的好书。如果你现在就想找到相关的书,试着看看由Norman Vincent Peale写的《积极思考就是力量》(The Power of Positive Thinking)[Touchstone,2003再版]。关键是积极思考不会从天而降,也不是一夜间就能获得的,你要付出持续的努力,将思想转向积极的方向。但这是值得付出的努力。不单是因为积极思考能让你活得更长久、更健康、更成功,还因为这绝对会让你活得更有乐趣,同时你可能会影响你周围的人同样生活得越来越有乐趣。

构建一个积极的自我形象

  • 那些不能激励自己的人一定是甘于平庸的人,无论他们的其他才能有多么令人印象深刻。——Andrew Carnegie

  • 自我形象是在甩掉别人对你的看法,摆脱所有用来自我安慰的谎言和欺骗以后,你看到的自己的样子。

  • 对你的大脑“重新编程”如何有目的性地对你的大脑“重新编程”?如何像我当年那样改变自我形象?公式相当简单:只需要花点儿时间,再加上持之以恒地正确执行。一开始,设定一个你想成为的清晰形象。你的大脑有惊人的能力去寻找摆在它面前的任何目标。你只需要想象一下这些目标,直到这个目标足够清晰到让你的大脑能够带领你走向你需要走向的那条道路。

  • 为你树立一个理想形象。在你的脑海中牢固地树立起一个形象——“这就是我想要成为的形象,没有什么能够阻止我”。想象一下你自己更坚定、更有自信地走进房间;想象一下你优雅地跳跃着、奔跑着,而不是将自己绊倒;想象一下你可以激励别人,可以非常时尚。不要给自己设定任何的人为限制,除非是那些你没有办法改变的身体特征(例如,不要把自己想象成个子很高,除非这么做能让你感到更自信。只是别指望这么想真的能让你长高。)一旦你在自己的脑海中设立了这样的形象,下来的任务就是开始执行“仿佛”模式。“仿佛”你已经变成了你想变成的那个人。无论是言行举止,还是穿着打扮,都像你想成为的那个人一样,甚至像你想成为的那个人一样刷牙。不要太关注现实是怎么样的,不要太在意别人如何议论你的“变化”;相反,假装你已经达到了你想要的目标,你的新行为只是这个新个性的自然延伸。你还要给自己很多正面的肯定,这会在你潜意识深处植下你的新思维模式的种子。事实证明,正面的肯定不是胡言乱语,你的大脑会真的开始相信你告诉它很多遍的东西。还记得我说过的改变信念是多么难的一件事吗?如果持续传递一致的信息给你的大脑,你就能改变自己的信念。

  • 我建议用一句名言或者一个肖像提醒你,你理想中的那种精神状态。让每一天都充满正面的肯定,这样就能更加确认并加强你的新信念。花一些时间,在精神层面上虚构一个你想成为的那个自己。很多体育运动员就是利用这样的过程来提高自己的成绩的。在参加重大赛事之前,他们会在脑海中做一次彩排。

爱情与恋爱

  • 总的来说,我们总想得到自己得不到的东西,我们总想得到别人也想得到的东西。所以,希望越大,失望越大,你就越不可能得到。

  • 关键是你要真正表达出这个意思。你必须要对自己表现出足够的自信,你真的相信你不需要别人给你带来快乐。你必须要相信你和别人在一起是因为你能给对方的生活带来好处,当然这并不意味着你自认为你是上帝恩赐给别人的礼物……来填补空白,但这确实意味着你对自己足够尊重,你只出现在自己想去的地方,你只想和想和你在一起的人相处。

  • 这并不意味着保证能成功,我无法保证。但是,如果你能明白大多数情侣关系其实是“你追我逃”的微妙心理游戏作用的结果,你就会更容易找到真爱。这不只适用于爱情问题,也适用于各种人与人之间的关系。做一个绝望的、缺乏自信的人,你可能会发现自己真的孤立无援。如果你发现你面试的对象就像大街上一个垂死挣扎的乞丐一样祈求你施舍给他工作岗位,你也会觉得他很惹人生厌。

  • 太多人会犯这样的错误——挑选一个人,然后把他/她当作理想人选放在神龛上,时刻想念着那个能让他们觉得“开心”的完美女生或者男生。假设只有这么一个完美的人,这种想法不但荒谬而且缺乏策略。如果扩大搜索范围,你的机会更好。

  • 所以,请不要害怕失败,哪怕失败很多次;不要害怕被拒绝,没什么大不了的。最差的情况又能差到哪里?你可能就像去敲开一扇扇门的销售员,他们面对上百扇甩向他们的门,只为做成一笔交易。你要知道,你每天需要做的就是完成一笔交易。

  • 除此之外,所有那些拒绝最终都会把你带到一个想和你在一起的人那里,这总比和不想和你在一起的人在一起要好很多。

私房成功书单

  • 人性的弱点

  • 让别人做你想做的事情的唯一方法就是让他们自己也想做这件事。

  • Napoleon Hill的《思考致富》(Think and Grow Rich)[Wilder Publications, 2007]

  • Robert Kiyosaki的《穷爸爸,富爸爸》(Rich Dad, Poor Dad)[Demco Media,2000]这是另外一本改变我生活的书,它改变了我对金钱和财富的看法。这本书改变了我对钱是如何运作的认识,改变了我对“拥有一份工作”以及“为别人工作意味着什么”的看法。读完这本书之后,我清楚地理解了建立资产和减少自己的开销有多么重要。

积极面对失败

  • 跌倒七次,爬起来八次。——日本谚语

  • 为什么我们总是害怕失败畏惧失败似乎是大多数人的本能。人都喜欢做自己擅长的事情,逃避做那些自己不能胜任的或是缺乏技能的事情。我们似乎与生俱来就畏惧失败。

  • 如果非要我猜猜为什么大多数人如此害怕失败,我不得不说这可能是基于保护脆弱的自尊的想法。或许我们害怕失败就是因为我们太过将失败归咎于个人,我们认为在特定领域下的失败是个人价值的流逝。

  • 我认为,对“失败”性质的误解还会助长这种对个人价值伤害的恐惧感。

  • 即使我们知道失败并不是终点,我们似乎也能感受到这一点。我们往往太过较真,把失败看得太重。因为我们接受过把失败看作通往成功道路——很多情况下这也是唯一的一条道路——的训练,所以我们不惜任何代价地避免失败。

  • 失败并不是被打败

  • 失败不同于被打败。失败是暂时的,被打败是永恒的。失败是那些碰巧发生在你身上的——你不能完全控制它。被打败却是你可以选择的——是对失败的某种程度的接受。

  • 要实现不畏惧失败,第一步就是真正意识到失败不是终点——除非你选择把它看作是终点。生活不易,你随时都会被击垮,但是否要重新站起来却完全取决于你自己。它取决于你是否决定为自己最值得拥有的东西战斗,取决于你是否要享受获得成功后的喜悦和乐趣,大多数情况下,它来自于战胜困难的成就感。

  • 如果在第一次受挫败被打死的时候你就扔掉了控制器,会发生什么?某种程度上,从很多次失败中获得的经验反而让你最终获得了成功的体验,这是不是更令你乐在其中?如果是这样,你为什么要把失败当作是一种永恒的状态而逃避生活中的失败呢?你不能指望拿起电玩遥控器,不经历掉下陷阱或者被火球烧焦就能通关,那么你为什么要指望一生不经历失败呢?

  • 失败是通往成功的必经之路不要畏惧失败,要拥抱失败。不只是因为失败和被打败不同,还因为失败是通往成功的必经之路。生活中所有值得拥有、值得去完成的事情都需要经历失败。问题是,我们学到的都是用负面的视角去看待失败。上学的时候,作业得了F,这被看为退步。没有人教你要把这个失败看作能让你离自己的目标越来越近的学习经验,你反而会被告知这整个都是负面的事情。现实生活不是那样的。我不是说你不应该为了考试而学习,也不是说为了获得学习经验和塑造个性而一定要努力考一个F,我想说的是,在现实生活中失败通常是必要的里程碑,它能带领我们离成功越来越近。在现实世界里,当你在某件事上失败的时候,你从中学到了经验并且有可能成长。我们的大脑就是被这样训练的。如果你曾经试过学习如何玩杂耍,或者打篮球,或者其他需要相互配合的体育活动,你会知道在成功前会失败很多次。

  • 学会拥抱失败重申一遍,我必须要说,即使你在本书中什么都没有学到,那也要记下下面这条建议:学会拥抱失败、期待失败、接受失败,并准备直面失败。只是不畏惧失败还不够,还要主动寻觅失败。想成长就必须把自己放在保证会失败的环境中。我们常常会因为停止做那些对我们有挑战或者危险的事情而停滞不前。我们寻找生活中的温室,关上小屋的门,拉上窗户,任凭外面狂风暴雨,我们绝不冲到雨中。但是,有时候你需要被淋湿,有时候你需要把自己放到一个不舒服的环境下强迫自己成长,有时候你需要积极地走出去寻找这样的环境,要知道,你越将你的船驶向失败,将你吹向失败的另外一面(成功)的风就会越强。要如何拥抱失败?要如何说服自己跳入波涛汹涌的大海?从接受失败是生活的一部分开始。你必须明白,在生活中你要面对很多失败,很多是不可避免的,任何事情第一次做都不可能做到完美,你会犯错。你还要明白,就算失败也没关系。犯错也没关系。你可以尝试避免犯错,但是不要因为害怕伤害自尊而以付出错失良机为代价。一旦你意识到失败是好事,失败并不能定义你的价值而你对待失败的态度恰恰才能说明你的价值,你才会真正学会对失败无所畏惧。最后,我还是要建议你将自己暴露在失败的环境里。去做那些让你不舒服的事情。在本书的前面我们讨论过不要害怕看起来像个傻瓜,对待失败我也要说一样的话。事实上,这两个观点是紧密相连的。走出去,有目的地去把自己放在那些不可避免地会导致某种失败的困境中。但关键是不要放弃——让失败点亮通往成功的道路。去经历尽可能多的失败吧,畏惧失败本身才会让你失去克服困难的能力。

  • 我要留给你最后一句关于失败的话,摘自Napoleon Hill的《思考致富》一书:“大多数伟大的人取得的最大成功与他们所经历的最大失败只有一步之遥。”

  • 采取行动
    对失败的恐惧是如何让你退缩的?想想生活中那些你想做但由于一时犹豫或者自尊受损而没有做的事情。
    承诺至少做一件因为害怕失败而一直回避的事情。不要敷衍了事。很多人明知道有些事会失败还去“尝试”,这样做不会让他们真正失败,因为“没有真正尝试过”才会是失败。真的去尝试,真的去体验失败吧。

结束语

  • 好吧,就到这里吧。我们终于来到了这本书的结尾。之所以说“我们”,是因为我希望你把读这本书当作是跟我写这本书一样的冒险旅程。当我开始动手写这本书的时候,我并不知道写一本这么长、这么厚的书这么难。我只知道我想要写一本书,分享我在自己作为软件开发人员的职业生涯中已经学到的一些重要的经验和教训——并不是关于如何编写优质代码、推动职业生涯上进的经验,而是关于如何做好更全面的人的经验,以及如何把我的人生价值发挥到最大同时又有利于他人的经验。我不是天才。我甚至都不是一位能够在反思他几十年的生活经验之后给你可以受益50年的智慧的长者,所以不要把我的这本书当作福音。这本书就是我的经验以及到目前为止让我获得成功的关键要素的分享。希望你能从中找到一些有用的东西,即便你可能不同意书中的所有观点——那也没关系。这正是这本书的要点。你不能把别人说的话都当作福音。没有人可以垄断真理。现实中,很大程度上,正是你自己发现了真理。这并不意味着你可以忽视这世界上的公认真理、只管自行其是,但这意味着你可以决定你想要过怎样的生活,你该怎样去生活。如果你能学会管理诸如成功、理财、健身以及自己的心理状态等事务的基本原则,你就可以利用这些原则来塑造你自己的现实世界。希望在读完这本书之后,你已经得出结论:那些你过去已经被告知的关于“你该如何生活”的狭窄的、笔直的道路,如你要取得好成绩、尽量不要搞砸了、上大学、找份工作然后安心工作50多年直到退休吧……并不是你可以走下去的唯一道路。当然,你也可以继续沿着过去被告知的那条道路前进,只要你愿意;不过,如果你正在读这本书,我相信你已经意识到,生活原本要比你所厌恶的朝九晚五的工作丰富多彩得多。希望这本书已经让你意识到,全世界都是你的机会,都在你的掌控之下。你可以更好地管理自己的职业生涯,可以从中获益更多,甚至可以把自己的职业生涯带向全新的方向,可以学会实际构建自己的个人品牌、营销自己——把自己的软件开发职业生涯提升到一个认为不可能达到的全新高度,让自己有机会影响更多的人。希望这本书教会了你学习和吸收信息的新方法,给了你足够的信心去超越自我——不只是为了学到东西而去学习,还要把你学到的知识与他人分享、使他人受益,不管你是沿着哪条路径前进。希望这本书能够激励你更有成效,更谨慎地管理和善用你的时间,并且能够激励你看到努力工作的价值,并付诸于实践——即使是在你觉得缺乏动力继续前行的时候。希望这本书能激励你以某种方式去健身,更好地照顾自己的身体健康,使你意识到实际上你也可以保持身材,并不因为你是软件开发人员就不能成为健壮的、运动型的人,只要你愿意,你至少可以主动控制自己的健康。最后,我希望这本书已经帮你意识到意志力是多么强大、多么重要,你的头脑可以作为一种工具,要么推动你前进,要么在你来不及做出反应、来不及应用自己所学的时候就摧毁你的前程。我希望这本书可以让你意识到你有能力成为你想成为的人,你也可以通过积极思考和坚持到底的力量重新塑造自己。

  • 是的,这些都是任何一本书都向往的崇高目标,尤其是一本与软件开发有关的书。不过,只要我能在一些很小的地方帮到你,让你改善了自己的生活哪怕一点点,我都会认为这是一场胜利。在你放下这本书之前,我有一个小小的请求:如果你发现这本书对自己有帮助,如果你认为其他人也可能会从中受益,请把它分享给别人。我这么说不是为了提高这本书的销量——尽管我很愿意这么做,但是着手写这本书真不是为了赚钱——我花500小时可以做很多很多更有利可图的事情,写这本书只是因为我认为我们不仅应该不遗余力地做好一个软件开发人员,而且应该做好一个人:去帮助他人。感谢你抽出时间来阅读这本书,并真诚地希望你能在本书中发现一些永久的价值。John Sonmez,http://simpleprogrammer.com

N年前的笔记备忘查阅

发表于 2023-01-28

  • 正则表达式和Matcher,Pattern的简单用法
  • 如何在同一台电脑使用不同的账号提交到同一个github仓库
  • Spring源码阅读之数据自动绑定
  • Hessian跨语言调用实例
  • 关于Java权限控制SecurityManager的理解
  • 关于系统间数据一致性(跨进程事务)的解决方案
  • wireshark抓包简单查看HTTP keep-alive原理
  • 继续深入理解HTTP keepalive

借《黑客与画家》记录一下想法

发表于 2023-01-14

借本书记录自己的想法(从前混乱的头脑,没能及时总结),阅读这本书有种相逢恨晚的感觉,有相似或者认同的想法.

“黑客精神”是这本书的核心理念所在。“黑客”本身具有各种各样的描述和象征意义。在不同场景下,人们对“黑客”的定义也不一样。在保罗的观念里,以及在YC和奇绩创坛的实践观察中,我们发现,黑客精神的真谛是动手去创造性地解决问题。“解决问题”必须跟人的需求有关,需要持久地满足越来越多人的需求。“动手”需要有勇气,很务实,以行动为导向,除此以外,黑客还必须是一个积极向上的人。“创造性”则意味着不受束缚、敢于探索。此外,黑客精神还意味着独立思考,坚持说真话。“动手去创造性地解决问题”代表了创造者一系列的核心行为和思想状态。这句话虽然听上去很简单,但它具有深刻含义,且完全反映了创造者的核心要素。

在本书中,“黑客”就是指最优秀的程序员,而不是入侵计算机系统的人。

作者想让公众了解,黑客并不神秘,更不是技术怪人。《黑客与画家》这个书名就是在提示应该把黑客与画家当作同一种人看待。和画家一样,黑客只是怀有一门特殊手艺、有创造天赋的普通人。这个书名还有另一层含义,即编程是一种艺术创作,黑客就是艺术家,开发软件与画家作画、雕塑家雕刻、建筑师设计房屋并没有本质不同。

  • 写通用的基础sdk就是一种艺术创作,封装,易用,优雅,安全,高效

第一部分 黑客如何成长及看待世界

1为什么书呆子不受欢迎

为什么黑客那么在乎言论自由?我认为,部分原因在于,革新对于软件行业实在是太重要了,而革新和异端实际上是同一件事。优秀的黑客养成了一种质疑一切的习惯。

  • 我很喜欢质疑, 有些理论上成立的东西, 如果直觉不认可, 我喜欢亲自去验证它。

我认为,这就是问题的根源。“书呆子”的目标具有两重性。他们毫无疑问想让自己受欢迎,但是他们更愿意让自己聪明。

  • 很多事情并是只有0或1, 不是你不想要, 只是事情总有优先级
  • 来自微信读书评论: 想和去做是两码事,没人不希望自己受欢迎,但聪明人有更重要的事要做。不在乎名利不见的有多聪明。
  • 来自微信读书评论: 没有人喜欢孤独,怎么样才会受欢迎很多人都知道,只不过不想去做罢了。

举例来说,大多数人似乎认为,绘画能力与生俱来,画家就像高个子一样,是天生的。事实上,大多数“会画”的人,本身就很喜欢画画,将许多时间投入其中,这就是他们擅长画画的原因。同样,受欢迎也不是天生的,而是需要你自己争取来的。

  • 之前投入的大量时间, 才让现在似乎得心应手。

一般来说,成年人就不会去欺负书呆子。为什么小孩子会这样做呢?一个原因是,青少年在心理上还没有摆脱儿童状态,许多人会残忍地对待他人。他们折磨书呆子的原因就像拔掉一条蜘蛛腿一样,觉得很好玩。在一个人产生良知之前,折磨就是一种娱乐。

  • 确实,很多人小时候都这样,特别是男孩子,后天正确的引导很重要。

没有什么比一个共同的敌人更能使得人们团结起来了。

  • 这提醒我有时要看清问题的本质以及别人的真正目的,避免被误导,毕竟希望自己是个聪明的人。

如果我没记错的话,最受欢迎的孩子并不欺负书呆子,他们不需要靠踩在书呆子身上来垫高自己。大部分的欺负来自处于下一等级的学生,那些焦虑的中间层。

  • 确实, 人类社交属性的同时, 也会产生对比和嫉妒, 时刻提醒自己不做这种无意义的事

没错,成年人不知道孩子们内部发生的事。认识到这一点很重要。在抽象意义上,成年人知道孩子的行为有时是极端残酷的,这正如我们在抽象意义上知道贫穷国家的人们生活极端艰难。但是,像所有人一样,成年人不喜欢揪住这种令人不快的事实不放。你不去埋头探寻,就不会发现具体的证据,就会永远以为这件事是抽象的。

  • 很多成年人都忘记自己小孩子时所经历的感觉, 表现出很不理解小孩子的行为, 并粗暴的归结为叛逆, 其实他们根本不想去了解和回忆, 觉得这浪费他们的精力, 毕竟他们还有很多“正经事”

总体上看,我就读的学校与上面说的监狱差不多。校方最重视的事情,就是让学生待在自己应该待的位置。与此同时,让学生有东西吃,避免公然的暴力行为,接下来才是尝试教给学生一些东西。除此以外,校方并不愿意在学生身上多费心思。就像监狱的狱卒,老师们很大程度上对学生是放任自流的。结果,学生就像犯人一样,发展出了野蛮的内部文化。

  • 将心比心, 很多人都这样, 无可厚非, 毕竟大部分人工作仅仅为了维持生活的收入, 多一事不如少一事, 当然还是有很多伟大负责任的老师

当你所做的事情能产生真实的效果,那就不仅仅是好玩而已了,发现正确的答案就开始变得重要了,这正是书呆子的优势所在。你马上就能联想到比尔·盖茨。他不善于社交是出了名的,但是他发现了正确的答案,至少从收入上看是如此。

  • 当你有影响力的时候, 别人才会高看你, 很现实但很真实

至于学校,不过是这个虚假环境中关住“牲口”的围栏。表面上,学校的使命是教育儿童。事实上,学校的真正目的是把儿童都关在同一个地方,以便大人白天可以腾出手来把事情做完。我对这一点没有意见,在一个高度工业化的社会,对孩子不加管束,让他们四处乱跑,无疑是一场灾难。

  • 工作的束缚, 时常在想这是什么阴谋和圈套, 我们真的需要每天工作这么长的时间? 或者我们真的需要这样被限制性的工作? 太多的疑问了.

这种看法无所不在,甚至孩子们自己都相信了,但是相信这种话可能一点帮助也没有。你告诉一个人,他的脚天生就是坏的,并不能阻止他去怀疑他可能穿错了鞋子。

  • 时刻记住, 逻辑的严谨: 充分必要条件, 控制变量法

还有别的问题存在,甚至可能是更糟糕的问题。那就是我们没有得到真正的工作,没能发挥我们的才能。人类喜欢工作,在世界上大多数地方,你的工作就是你的身份证明。但是,我们那时做的所有事情根本就是无意义的,至少那时看来是这样。

而且,没有办法回避那些事情。成年人已经达成共识,认定通往大学的途径就是这样的。逃离这种空虚生活的唯一方法,就是向它屈服。

  • 读大学前学的很多知识, 很大概率是你下大半辈子没用的, 学习它仅仅是因为通向大学的筛选机制

我们有一个专门的短语描述这种情况,即对于在没有任何严肃标准的前提下产生排名的情况,我们会说情况“倒退至人缘比赛”(degenerate into a popularity contest)。

  • 微信投票、升级加薪、绩效等

没有外在的对手,孩子们就互相把对方当作对手

如果存在针对真正能力的外部测试,待在等级关系的底层也不会那么痛苦。球队的新人并不会怨恨老队员的球技,他希望有一天自己也能球技高超,所以很高兴有机会向老队员求教。老队员可能也会因此产生一种传帮带的光荣感(noblesse oblige)。最重要的是,老队员的地位是通过他们本身出色的能力获得的,而不是通过排挤他人获得的。

  • 共同的敌人? 共同的目标?

我误解最深的一个词是“老成”(tact)。成年人使用这个词,含义似乎就是“闭上嘴巴,不要说话”。我以为它与“缄默”(tacit)和“不苟言笑”(taciturn)有着相同的词根,字面意思就是“安静”。我对自己发誓,我绝不要变成“老成”的人,没有人能够让我闭上嘴巴。可是事实上,这个词的词根与“触觉”(tactile)相同,它真正的意思是“熟练”。“老成”的反义词是“笨拙”(clumsy)。进入大学以后,我才搞明白了这个词。

  • 叛逆、愤青? 很多人根本不知道怎么解释, 抑或是自己被洗脑了, 懦弱, 只会站在道德制高点给你贴标签. 而我可能注定“叛逆”到死
  • 来自微信读书评论: 许多人的所谓成熟,不过是被习俗磨去了棱角,变得世故而实际了。那不是成熟,而是精神的早衰和个性的夭亡。真正的成熟,应当是独特个性的形成,真实自我的发现,精神上的结果和丰收。 ——尼采

校园生活的真正问题是空虚。除非成年人意识到这一点,否则无法解决这个问题。可能意识到这个问题的成年人,是那些读书时就是书呆子的人。

  • 作为一个“坏孩子”, 有时我很理解别人所认为的“坏孩子”的感受

2黑客与画家

黑客与画家的共同之处,在于他们都是创作者。与作曲家、建筑师和作家一样,黑客和画家都试图创作出优秀的作品。他们本质上都不是在做研究,虽然在创作过程中,他们可能会发现一些新技术(那样当然更好)

  • 有时候, 写代码, 特别是对一些通用逻辑进行抽象的时候, 确实有种愉悦感, 甚至完成之后还会反复的欣赏自认为是优雅的设计

我一直不喜欢“计算机科学”这个词,主要原因是根本不存在这种东西。

计算机科学就像一个大杂烩,由于某些历史意外,很多不相干的领域被强行拼装在一起。这个学科的一端是纯粹的数学家,他们自称“计算机科学家”,只是为了得到国防部研究局(DARPA)的项目资助。中间部分是计算机博物学家,研究各种专业性的题目,比如网络数据的路由算法。另一端则是黑客,只想写出有趣的软件,对于他们来说,计算机只是一种表达的媒介,就像建筑师手里的混凝土,或者画家手里的颜料。所以,在“计算机科学”的名下,数学家、物理学家和建筑师都不得不待在同一个系里。

  • 很多技术的实现就是那样, 但有些人总能包装成高大上的东西, 特别是在大公司. 我并不是批判这种行为, 相反我实际上有点羡慕这种能力.

黑客搞懂“计算理论”(theory of computation)的必要性,与画家搞懂颜料化学成分的必要性差不多大。一般来说,在理论上,你需要知道如何计算“时间复杂度”和“空间复杂度”(time and space complexity);如果你要写一个解析器,可能还需要知道状态机(state machine)的概念;除此以外,并不需要知道特别多的理论。这些可比画家必须记住的颜料成分少很多。我发现,黑客新想法的最佳来源,并非那些名字里有“计算机”三个字的理论领域,而是其他创作领域。与其到“计算理论”领域寻找创意,你还不如在绘画中寻找创意。

  • 就像现在IT行业盛行的八股文一样, 简直走火入魔. 我并不认为理论和原理并不重要, 但是跟清楚“颜料成分是多少”一样, 你很厉害, 但实际上大部分情况下对工作用处不大. 世界上的知识太多了, 这些细节没有人的全部掌握. 而知识的广度, 快速学习和搜索知识的能力, 对于程序员来说才是更重要的. 当然我能理解, 考核人员的无能以及巨大的岗位竞争, 产生了如今的现状.

如果黑客认识到自己与其他创作者——比如作家和画家——是一类人,这种诱惑对他就不起作用。作家和画家没有“对数学家的妒忌”,他们认为自己在从事与数学完全不相关的事情。我认为,黑客也是如此。如果大学和实验室不允许黑客做他们想做的事情,那么适合黑客的地方可能就是企业。不幸的是,大多数企业也不允许黑客做他们想做的事情。大学和实验室强迫黑客成为科学家,企业强迫黑客成为工程师。

  • 确实, 想任性的做自己的事, 可能是创业吧, 但是需求是什么?

直到最近我才发现这一点。雅虎收购Viaweb的时候,他们问我想做什么。我对商业活动从来都没有太大兴趣,就回答说我想继续做黑客。等我来到雅虎以后,发现在他们看来,“黑客”的工作就是用软件实现某个功能,而不是设计软件。在那里,程序员被当作技工,职责就是将产品经理的“构想”(如果这个词是这么用的话)翻译成代码。这似乎是大公司的普遍情况。大公司这样安排的原因是降低结果的标准差。因为实际上只有很少一部分黑客懂得如何正确设计软件,公司的管理层很难正确识别到底应该把设计软件的任务交给谁,所以,大部分公司不把设计软件的职责交给一个优秀的黑客,而是交给一个委员会,黑客的作用仅仅是实现那个委员会的设计。

  1. 很奇怪的现象, 很多大公司很喜欢全部员工一起开总结大会, 然后说员工需要提出自己的产品想法之类的. 实际上, 平常的工作中, 产品说了算, 甚至都不会听程序员的意见, 直接扔出一句“这是老板的需求”, 所以我一直认为开这种大会, 其实就是形式主义. 甚至开会的内容和现实对比, 可笑至极, 讽刺至极.
  2. 这样的产品, 把自己当成传话筒, 工具人, 直接躺平混日子了. 他们的目标只是满足老板的需求, 而不是用户的需求. 他们的目标只是保住工作混工资. 可是仔细想想, 很多人包括我自己, 又到达哪种境界呢? 可能大家其实半斤八两吧.
  3. 公司的目的是降低风险. 有时交给委员会, 实际上也是对普通员工的一种“保护”

所有创作者都面临这个问题。价格是由供给和需求共同决定的。好玩的软件的需求量,比不上解决客户麻烦问题的软件的需求量;在小剧场里演出的酬劳,比不上穿着卡通大猩猩服装、在展览会上为厂商站台的酬劳;写小说的回报比不上写广告文案的回报;开发编程语言的收入,比不上把某些公司老掉牙的数据库连上服务器的收入。黑客如何才能做自己喜欢的事情?我认为这个问题的解决方法是一个几乎所有创作者都知道的方法:找一份养家糊口的“白天工作”(day job)。这个词是从音乐家身上来的,他们晚上表演音乐,所以白天可以找一份其他工作。更一般地说,“白天工作”的意思是,你有一份为了赚钱的工作,还有一份为了爱好的工作。

  • 对于“晚上”工作, 其实我并没有找到明确的目标, 又或者自身太过于“急躁”了

因为黑客更像创作者,而不是科学家,所以要了解黑客,不应该在科学家身上寻找启示,而是应该观察其他类型的创作者。那么,从画家身上,我们还能借鉴到什么对黑客的启示呢?有一件事情是可以借鉴的(至少可以确认),那就是应该如何学习编程。画家学习绘画的方法主要是动手去画,黑客学习编程的方法也理应如此。大多数黑客不是通过大学课程学会编程的,而是从实践中学习,有的13岁时就自己动手写程序了。即使上了大学,黑客学习编程依然主要通过自己写程序。

  • 确实, 需要先模仿, 再创新. 很多东西确实有共同的特点

绘画还有一个值得借鉴的地方:一幅画是逐步完成的。通常一开始是一张草图,然后再逐步填入细节。但是,它又不单纯是一个填入细节的过程。有时,原先的构想看来是错的,你就必须动手修改。无数古代油画放在X光下检视,就能看出修改痕迹,四肢的位置被移动过,或者脸部的表情经过了调整。绘画的这个创作过程就值得学习。我认为黑客也应该这样工作。你不能盼望先有一个完美的规格设计,然后再动手编程,这样想是不现实的。如果你预先承认规格设计是不完美的,在编程的时候,就可以根据需要当场修改规格,最终会有一个更好的结果。

  1. 软件的设计, 比如一些通用框架, 或者服务架构, 当然是最好一开始就想清楚, 并设计好(并不代表后续不能改动), 这样有助于后续细节的实现, 也有一个基本的大局观, 同时也可以提前发现存在的问题, 避免后续的无用功, 还有提前确认好项目风险等等.
  2. 这个问题其实我是潜意识知道的,但还是因为懒,感觉太累不想思考,选择做一下具体的细节先,但有时也算是一种适当的放松吧

黑客就像画家,工作起来是有心理周期的。有时候,你有了一个令人兴奋的新项目,你会愿意为它一天工作16个小时。等过了这一阵,你又会觉得百无聊赖,对所有事情都提不起兴趣。为了做出优秀的工作,你必须把这种心理周期考虑在内。只有这样,你才能根据不同的事情找出不同的应对方法。你有一辆手动变速的汽车,你把它开上山,有时不得不松开离合器,防止汽车熄火。同样,暂时放手有时也能防止热情熄火。对于画家和黑客这样的创作者,有些工作需要投入巨大的热情,另一些工作则是不需要很操心的日常琐事。在你厌倦的时候再去做那些比较容易的工作,这是一个不错的主意。对于编程,这实际上意味着你可以把bug留到以后解决。消灭bug对我来说属于轻松的工作,只有在这个时候,编程才变得直接和机械,接近社会大众想象中的样子。消灭bug的过程就像解一道数学题,已知许许多多的约束条件,你只要根据条件对方程求解就可以了。你的程序应该能产生x 结果,却产生了y 结果。哪里出错了?你知道自己最后肯定能解决这个问题,所以做起来就很轻松,就好像刷墙一样,接近于休闲了。

  1. 深有同感, 松弛有度, 这样才能更愉快和保持热情的工作
  2. 一味的逼迫自己把同一件事做好, 有时却会适得其反, 因为厌倦和抗拒, 虽然工作完成了,但是实际上完成质量和效率是存在疑问的. 或许你先做另一件事,在回来做这件事,整体的效率和质量是更高的.
  3. 以前看过一种说法, 有时觉得累了并不是需要休息, 而是你的大脑需要换其他的事情

我认为,这也是多人共同开发一个软件的正确模式。需要合作,但是不要“合”得过头。如果一个代码块由三四个人共同开发,就没有人真正“拥有”这块代码。最终,它就会变得像一个公用杂物间,没人管理,又脏又乱,到处堆满了冗余代码。正确的合作方法是将项目分割成严格定义的模块,每一个模块由一个人明确负责。模块与模块之间的接口经过精心设计,如果可能的话,最好把文档说明写得像编程语言规范那样清晰。

  • 提前分工明确能避免无用功, 同时能尽量确保交付时间

普通黑客与优秀黑客的所有区别之中,会不会“换位思考”可能是最重要的单个因素。有些黑客很聪明,但是完全以自我为中心,根本不会设身处地为用户考虑。这样的人很难设计出优秀软件,因为他们不从用户的角度看待问题。

  • 换位思考实在是太重要了, 很多事情都能以此为切入点, 找到解决方案或者事情的本质

判断一个人是否具备“换位思考”的能力有一个好方法,那就是看他怎样向没有技术背景的人解释技术问题。我们大概都认识这样一些人,他们在其他方面非常聪明,但是把问题解释清楚的能力却低下得惊人。如果聚会上外行人问他们“什么是编程语言”,他们会这样回答:“哦,高级语言就是编译器的输入代码,用来产生目标码。”高级语言?编译器?目标码?……如果对方不知道什么是编程语言,那么他显然也不会知道这些概念。

  • 学会类比, 使用通俗的语言, 言简意赅

把代码写得便于阅读,并不是让你塞进去很多注释。我想引申一下阿尔贝森和萨斯曼的那句话:“程序必须写得供人们阅读,偶尔供计算机执行。”一种好的编程语言应该比英语更容易解释软件。只有在那些不太成熟、容易出现问题的地方,你才应该加上注释,提醒读者注意,就好像公路上只有在急转弯处才会出现警示标志一样。

  1. 以前学了很多设计模式, 经常把自己搞乱, 也看了很多别人的代码, 搞了很多设计模式, 看起来好像高大上, 实际上阅读起来非常痛苦. 后来我相通了, 只有简单的代码才是最好最容易理解的, 复杂重复的地方就抽取封装, 至此, 我基本上没听说有人说我代码很难阅读, 至少在我没听过.
  2. 当然, 遇到使用了设计模式, 实现优雅可读性强的代码, 也要借鉴学习.

3不能说的话

让我先问你一个问题:大庭广众之下,你有没有什么观点不愿说出口?如果回答“没有”,那么你也许应该停下来想一想了。你的每一个观点都能毫不犹豫地说出口,你自己深深赞同这些观点,并且你也确信肯定会获得别人的赞同,这是否太过于巧合了?一种可能是,也许事情并没有这么巧合,你的观点就是从别人那里听来的,别人告诉你什么,你就相信了什么,你把别人灌输的观点当作了自己的观点。

另一种可能是,你的思想观点确实是独立思考得到的,碰巧与社会主流的思想观点一模一样。这种情况的可能性似乎不大,因为这意味着,如果别人犯错了,你也必须碰巧犯一个同样的错误。

有时候,别人会对你说:“要根据社会需要,改造自己的思想。”这种说法隐含的意思似乎是,如果你不认同社会,那么肯定是你自己的问题。你同意这种说法吗?事实上,它不仅不对,而且会让历史倒退。如果你真的相信了它,凡是不认同社会之处,你连想都不敢想,马上就放弃自己的观点,那才会真正出问题。

过去和现在之间的变化有时代表了一种进步。在物理学领域,如果我们与前人看法不一样,那是因为我们是对的,他们是错的。但是,物理学是一门硬科学4,换成其他学科,我们很快就无法确定谁对谁错了。如果你遇到的是社会问题,请问过去的看法与现在的看法哪一个更正确?很多时候你无法回答,因为过去与现在之间的变化往往不是因为对错,而是因为社会观念变了。比如,法定结婚年龄的变化。

4 在学术上,“硬科学”指的是那些严格精确、以事实为依据的学科,典型代表是自然科学,比如物理学。相对应的概念则是“软科学”,指的是不那么严格精确、难以用事实检验的学科,典型代表是社会科学。——译者注

我们可能自以为是地相信,当代人比古人更聪明、更高尚。但是,了解的历史越多,就越明白事实并非如此。古人与我们是一样的人,他们既不更勇敢,也不是更野蛮,而是像我们一样通情达理的普通人。不管他们产生怎样的想法,都是正常人产生的想法。所以,我们就有了找出“不能说的话”的第三种方法:将当代观念与不同时期的古代观念diff5一下。diff得到的结果,有一些用当代标准衡量是很令人震惊的。古人认为可以说的话,我们认为是不可以说的。但是,你有把握断言你比古人更正确吗?

但是,流行的道德观念不是这样,它们往往不是偶然产生的,而是被刻意创造出来的。如果有些观点我们不能说出口,原因很可能是某些团体不允许我们说。那些团体神经越紧张,它们所产生的禁止力量就越大。

为了在全社会制造出一个禁忌,负责实施的团体必定既不是特别强大也不是特别弱小。如果一个团体强大到无比自信,它根本不会在乎别人的抨击。美国人或者英国人对外国媒体的诋毁就毫不在意。但是,如果一个团体太弱小,就会无力推行禁忌。

  • 来自微信读书评论: 强权就是公理。因为强权可以制造任何的其他客观条件,不管是社会舆论还是特定事件营销。并不觉得他们不在意,而且他们掌握更多的话语权,其他的话语流星般转瞬即逝。

  • 来自微信读书评论: 思考:
    人也是如此。
    当你手里有千万资产,你会在乎别人说你穷吗?不会,你甚至都不想证明。
    同样,当你真的有能力,你会在乎别人说你无能吗?不会。

有一种行为怪癖叫作“嗜粪症”,它的患者人数以及影响力眼下似乎就不太足够,无法把自己的观点推广给其他人。我猜想,道德禁忌的最主要制造者是那些在权力斗争中略占上风的一方。你会发现,这一方有实力推行禁忌,同时又软弱到需要禁忌来保护自己的利益。

其次,我这样做是因为我不喜欢犯错。如果像其他时代一样,那些我们自以为正确的事情将来会被证明是荒谬可笑的,我希望自己能够知道是哪些事情,这样我就不会上当。

为什么?可能仅仅是因为科学家比其他领域的学者更聪明。如果有必要的话,大多数物理学家有能力拿到法国文学的博士学位,但是反过来就不行,很少存在法国文学的教授有能力拿到物理学的博士学位。13或者,另一种原因是,在科学中,命题的真伪更显而易见,所以这使得科学家能够更勇敢地质疑传统观点。(这句话也可以这样说,因为科学命题的真伪更显而易见,所以你想在科学界谋职,就不得不训练自己的智力,去发现并解决那些真正的问题,而不能仅仅当一个政治家,通过搞人事关系和派系斗争立足。)

13 这句话本身就是一种明显的“不能说的话”。它犯了大学中的一个大忌:评判各种学科的难易。大学校园中有一条默认的公理——各种领域的研究所要求的智力水平都是相同的。毫无疑问,这条公理确实能够减少冲突,让一切平稳运作。但是,如果这条公理为真,那将是多么巧合的事情啊,所有学科的难易程度居然一模一样!而且,承认这条公理比不承认它会使得一切都方便得多!你只要想到这些,怎能不质疑它呢!尤其是当你想到,一旦接受了这条公理所产生的必然推论,就更无法不质疑它了。比如,它意味着不会出现单个学科的停滞或爆发式发展,所有学科的发展形态必须是完全同步的,因为这条公理告诉我们,各个学科面对的问题难度是一样的!(要弥补这个推论,你真的会伤透脑筋。)此外,如果大学开设了烹饪系或运动管理系,你会怎么想?如果你接受上面的公理,那么大学到底还要开设什么系?你真的认为微分几何和烹饪学的难度相同吗?

不管是哪一个原因,看来都存在一个很清晰的关系:智力越高的人,越愿意去思考那些惊世骇俗的思想观点。这不仅仅因为聪明人本身很积极地寻找传统观念的漏洞,还因为传统观念对他们的束缚力很小,很容易摆脱。从他们的衣着上你就可以看出这一点:不受传统观念束缚的人,往往也不会穿流行的衣服。做一个异端是有回报的,不仅在科学领域,在任何有竞争的地方,只要你能看到别人看不到或不敢看的东西,你就有很大的优势。

一旦发现了“不能说的话”,下一步怎么办?我的建议就是别说,至少也要挑选合适的场合再说,只打那些值得打的仗。

如果你以此作为人生目的,一定要为黄颜色平反昭雪,现在的局面可能正中你下怀。但是,如果你的兴趣主要是别的事情,变成他人眼里的“黄色分子”对你则是极大的干扰。与笨蛋辩论,你也会变成笨蛋。

  • 来自微信读书评论: 真理越辩越明?不会的,争辩让你妄想说服对方,争辩让你学会讨好观众,这些有时会让你失去自由。

这时你要明白,自由思考比畅所欲言更重要。如果你感到一定要跟那些人辩个明白,绝不咽下这口气,一定要把话说清楚,结果很可能是从此你再也无法自由理性地思考了。

  • 社会本来就需要各种各样的人, 有时候不说话的人的利益, 就是说话的人牺牲的人带来的.

  • 来自微信读书评论: 可如果所有人都遵守这个准则,那么又何来变化和进步呢?每个大的进步和改革背后,都是一群不愿闭嘴的人推动而成吧

  • 来自微信读书评论: 谭嗣同愿意以身犯险,最终奔赴黄泉,但推行“戊戌变法”,叫醒国人他功不可没!你说的没毛病,就看你怎么选择了

我认为这样做不可取,更好的方法是在思想和言论之间划一条明确的界线。在心里无所不想,但是不一定要说出来。我就鼓励自己在心里默默思考那些最无法无天的想法。你的思想是一个“地下组织”,绝不要把那里发生的事情一股脑说给外人听。“格斗俱乐部”的第一条规则,就是不要提到格斗俱乐部。15

我承认,“守口如瓶”看上去是一种“怯懦”的行为。可是问题在于,“不能说的话”太多了,如果口无遮拦,你就没时间做正事了。为了与他人论战,你不得不变成一个语言学家

“守口如瓶”的真正缺点在于,你从此无法享受讨论带来的好处了。讨论一个观点会产生更多的观点,不讨论就什么观点也没有。所以,如果可能的话,你最好找一些信得过的知己,只与他们畅所欲言、无所不谈。这样不仅可以获得新观点,还可以用来选择朋友。能够一起谈论“异端邪说”并且不会因此气急败坏的人,就是你最应该认识的朋友。

你的策略,简单地说,就是不赞同这个时代的任何一种歇斯底里的行为,但是又不明确告诉别人到底不赞同哪一种。

如果你想要清晰地思考,就必须远离人群。但是走得越远,你的处境就会越困难,受到的阻力也会越大,因为你没有迎合社会习俗,而是一步步地与它背道而驰。小时候,每个人都会鼓励你不断成长,变成一个心智成熟、不再耍小孩子脾气的人。但是,很少有人鼓励你继续成长,变成一个怀疑和抵制社会错误潮流的人。

如果自己就是潮水的一部分,怎么能看见潮流的方向呢?你只能永远保持质疑:什么话是我不能说的?为什么?

  • 来自微信读书评论: 离经叛道不是一件好事,尤其在我国。
    作者让人们保持质疑,虽然只想不说,也很难说是不是好事。
    这跟郑板桥提倡的难得糊涂恰好相反,我支持郑,因为对大部分个体,发现真相却不能做什么,只会陷入深切痛苦。
    这时作者唤醒的就不是“嘲笑鸟”,而是沉睡的恶魔。

第二部分 黑客如何工作及影响世界

4良好的坏习惯

对于适当的不服从管教保持宽容,这不会有太大的坏处,反而很有利于造就美国的国家优势,它使得美国不仅能吸引聪明人,还能吸引那些很自负的人。黑客永远是自负的。

这种事情早有先例:人们惊慌失措时采取的措施到头来产生了适得其反的效果。

  • 来自微信读书评论: 紧急情况下猛打方向,结果汽车撞上护栏,最终翻车;碰到劫匪声嘶力竭地大叫,导致劫匪因惊慌临时动了杀心;碰到地震火情冲向还闭着的门,导致踩踏,打不开门,最终自食恶果。极度惊慌,是人类的最强大武器——头脑失效的时刻,也就演变成坐以待毙的时刻。

那些占据高位、本能地想要约束黑客、强迫黑客服从的人,请谨慎施为,因为你们真有可能成为千古罪人。

5另一条路

早一点发现bug就不容易形成复合式bug,也就是互相影响的两个bug。举例来说,一个bug是楼梯很滑,另一个bug是扶手松了,那么只有当这两个bug互相作用时,才会导致你从楼梯上摔下来。在软件中,复合式bug是最难发现的bug,往往也会导致最大的损失。

  • 来自微信读书评论: 复合式bug有一个子类型:两个bug是互相弥补的,好比“负负得正”,软件反而能正常运行。这种bug可能才是最难发现的bug。当你修正了其中的一个bug,另一个bug才会暴露出来。这时对你来说,你会觉得刚才修正错了,因为那是你最后修改的地方,你就怀疑自己在那里做错了,但是你其实是对的。

向一个项目增加人手,往往会拖慢项目进程。随着参与人数的增加,人与人之间需要的沟通成本呈现指数级增长。人数越来越多,开会讨论各个部分如何协同工作所需的时间越来越长,无法预见的互相影响越来越大,产生的bug也越来越多。

  • 来自微信读书评论: 《人月神话》是一本软件项目管理名著。所谓“人月”就是一个人在一个月内所能完成的工作量。假如某个项目预估需要12个人月,那么派4个人处理这个项目,理论上需要3个月,派6个人则只需要2个月。但是,布鲁克斯认为这种换算机制在软件业行不通,是一个神话,因为软件项目是交互关系复杂的工作,需要大量的沟通成本,人力的增加会使沟通成本急剧上升,反而无法达到缩短工期的目的。在本质上,软件项目的人力与工期是无法互换的,当项目进度落后时,光靠增加人力到该项目中,并不会加快进度,反而有可能使进度更加延后。

人数越来越少,软件开发的效率将呈指数式上升。

不要只因为对方的头衔是市场专家、设计师或产品经理,就盲目听从他们的话。如果他们的观点真的很好,那就听从他们,关键是你要自己判断,不要盲从。只有懂得设计的黑客,才能设计软件,不能交给对软件一知半解的设计师。如果你不打算自己动手设计和开发,那就不要创业。

  • 实际在大公司, 通常只能按照产品说的做
  • 心中放置一种观点: 虽然我按照你说的做了, 但实际上我并不认同, 仅仅是因为工作需要

6如何创造财富

承受较大的压力通常会为你带来额外的报酬,但是你还是无法逃避基本的守恒定律。

现在先不考虑比尔·盖茨,因为名人不适合用来举例子,媒体只报道那些最有钱的人,而他们往往属于特例。比尔·盖茨很聪明,有决断力,工作也很勤奋,但是单单这样还不足以让你成为他,你还需要非同一般的好运气。

任何公司的成功历程中,运气都是一个很大的随机因素。

致富的方法有许多种,本文只谈论其中的一种,也就是通过创造有价值的东西在市场上得到回报,从而致富。

通过创造有价值的东西而致富,这种方法的优势不仅仅在于它是合法的(许多其他方法如今都是不合法的),还在于它更简单,你只需要做出别人需要的东西就可以了。

3 近代历史上,政府有时都搞不清楚金钱和财富的区别。亚当·斯密在《国富论》中提到,许多国家政府为了保住“财富”,禁止出口白银或者黄金。但是,黄金和白银实际上只是一种交换媒介,留住它们并不会让一个国家变得更富有。如果物质财富保持不变,金钱越多,导致的唯一结果就是物价越高。

财富是最基本的东西。我们需要的东西就是财富,食品、服装、住房、汽车、生活用品以及外出旅行等都是财富。即使你没有钱,你也能拥有财富。

  • 来自微信读书评论: 如此说来,以后还是尽量避免说自己穷,如果真的要说的话直接说自己现在没有钱好了。

你真正需要的是财富。财富才是你的目标,金钱不是。

虽然在某些特定的情况下(比如某个家庭当月的收入),你能用来与他人交换的金钱数量是固定不变的,但是大多数情况下,世界上可供交换的财富不是一个恒定不变的量。人类历史上的财富一直在不停地增长和毁灭(总体上看是净增长)。

假设你拥有一辆老爷车,你可以不去管它,在家中悠闲度日,也可以自己动手把它修葺一新。这样做的话,你就创造了财富。世界上因为多了一辆修葺一新的车,财富就变得更多了一点,对你而言尤其是如此。这可不是隐喻的用法,如果你把车卖了,你得到的卖车款就比以前更多。

通过修理一辆老爷车,你使得自己更富有。与此同时,你也并没有使得任何人更贫穷。所以,这里明显不是一个面积不变的大饼。事实上,当这样观察的时候,你会很好奇,为什么有人会觉得大饼的面积无法增大。

  • 来自微信读书评论: 财富是创造出来的。如果我们养成健康的体魄,坚持锻炼,节制饮食,这也是我们所创造出的健康财富呀!

如果在修理旧车的过程中,你对环境造成了一些微小的破坏,那么你可能使得每个人都变得更贫穷了一点。但是即使把环境的成本考虑在内,这依然不是一个零和游戏,依然存在财富的净增长。我们可以举出这样的例子,一台坏机器里有一个零件松了,你把零件拧紧,机器可以重新运作,那么你就没对环境造成任何破坏,并且创造了财富。

最可能明白财富能被创造出来的人就是那些善于制作东西的人,也就是手工艺人。他们做出来的东西直接放在商店里卖。但是,随着工业化时代的来临,手工艺人越来越少。目前还存在的最大的手工艺人群体就是程序员。

要致富,你需要两样东西:可测量性和可放大性。你的职位产生的业绩应该是可测量的,否则你做得再多,也不会得到更多的报酬。此外,你还必须有可放大性,也就是说你做出的决定能够产生巨大的效应。

  • 来自微信读书评论: 可放大性:使用人数的指数型上涨,如果你所创造的财富有缺陷,会被无限放大;可测量性:每个员工所做的工作都有其明确的反馈。

任何一个通过自身努力而致富的个人,在他身上应该都能同时发现可测量性和可放大性。我能想到的例子就有CEO、电影明星、基金经理和专业运动员。

有一个办法可以发现是否存在可放大性,那就是看失败的可能性。因为收入和风险是对称的,所以如果有巨大的获利可能,就必然存在巨大的失败可能。

黑客都是极度厌恶风险的人

我们宁愿以百分之百的把握去赚100万美元,也不愿以20%的把握去赚1 000万美元,尽管后者理论上的期望值比前者高出一倍。

保险的做法就是在早期卖掉自己的创业公司,放弃未来发展壮大

缓慢工作的后果并不仅仅是延迟了技术革新,而且很可能会扼杀技术革新。只有在快速获得巨大利益的激励下,你才会去挑战那些困难的问题,否则你根本不愿意去碰它们。

每一个这样做的人差不多应用了同样的诀窍:可测量性和可放大性

一旦自己的财产有了保证,那些想致富的人就会愿意去创造财富

要鼓励大家去创业,只要懂得藏富于民,国家就会变得强大。让“书呆子”保住他们的血汗钱,你就会无敌于天下。

7关注贫富分化

一旦通过创造财富而使致富成为可能,社会从整体上就会快速地变得更富有。

首先,技术肯定加剧了有技术者与无技术者之间的生产效率差异,毕竟这就是技术进步的目的。一个勤劳的农民使用拖拉机比使用马可以多耕6倍的田,但是前提条件是他必须掌握如何使用新技术。

但是,苹果公司推出了强大而且便宜的个人计算机,使得一切成为可能,这本身就是在创造财富。程序员马上接了上去,使用苹果公司的产品,再去创造更多的财富。

技术应该会引起收入差距的扩大,但是似乎能缩小其他差距。100年前,富人过着与普通人截然不同的生活。他们住在大房子里,有许多仆人服侍,穿着华丽但是不舒适的服装,乘着马车旅行(因此还有马厩和马夫)。

现在,由于技术的发展,富人的生活与普通人的差距缩小了。

汽车就是一个很好的例子。如果富人不购买普通汽车,而是购买全手工制作、售价高达几十万美元一辆的豪华车,对他反而不利。因为对于汽车公司来说,生产那些销量很大的普通汽车要比生产那些销量很小的豪华车更有利可图,所以汽车公司会在普通车辆上投入更多的精力和资金,进行设计和制造。如果你购买专为你一个人定制的汽车,质量反而不可靠,某个部件肯定会出问题。这样做的唯一意义就是告诉别人你有能力这样做。

无法被技术变得更便宜的唯一东西,就是品牌。这正是为什么我们现在越来越多地听到品牌这个词。富人与穷人之间生活的鸿沟正在缩小,品牌是这种差距的遗留物。

无论在物质上,还是在社会地位上,技术好像都缩小了富人与穷人之间的差距,而不是让这种差距扩大了。

如果参观雅虎、英特尔或思科公司,你会看到每个人都穿着差不多的衣服,有着同样的办公室(或者小隔间)、同样的家具,彼此直呼对方的名字,不加任何头衔或敬语。表面看大家没什么差距,但如果看到每个人银行户头上的余额差别之大,你一定会感到震惊不已。

技术的发展加大了贫富差距,这是不是一个社会问题?

好像没有那么严重。技术在加大收入差距的同时,缩小了大部分其他差距。

我想提出一种相反的观点:现代社会的收入差距扩大是一种健康的信号。技术使得生产率的差异加速扩大,如果这种扩大没有反映在收入上面,只有三种可能的解释:(a)技术革新停顿了;(b)那些创造大部分财富的人停止工作了;(c)创造财富的人没有获得报酬。

如果得不到报酬,人们是否愿意创造财富?唯一的可能就是,工作必须能提供乐趣。会有人愿意免费写一个操作系统,但是他们不愿意免费为你安装、提供电话支持、进行客户培训等。即使是最先进的高科技公司,也有至少90%的工作没有乐趣、令人生厌。

一个社会需要有富人,这主要不是因为你需要富人的支出创造就业机会,而是因为他们在致富过程中做出的事情。

我在这里谈的不是财富从富人流向穷人的那种涓滴效应(trickle-down effect),也不是说如果你让亨利·福特致富,他就会在下一场宴会雇用你当服务员,而是说如果你让他致富,他就会造出一台拖拉机,使你不再需要使用马匹耕田了。

9设计者的品味

但是,如果你是一个设计师,并且你不承认有一种人们共同认可的东西叫作“美”,那么你就没有办法做好工作。

如果品味只是一种个人偏好,那么每个人都是完美无缺的:你喜欢自己看上的东西,那就足够了。

就像别的工作一样,只要你不断地从事设计工作,你就会做得越来越好。你的品味会出现变化,你会像别人一样有所提高。如果这样的话,那么你以前的品味就不只是与现在不同,而是不如现在的好。因此,所谓“品味没有好坏之分”的公理也就顿时见鬼去了

众多不同学科对“美”的认识有着惊人的相似度。优秀设计的原则是许多学科的共同原则,一再出现。

  • 来自微信读书评论:
    • 比如:艺术上的美感包括什么类型?鲜明、丰富、和谐、简约等多种类型。把这种美感映射到代码上,体现是:模块功能清晰、齐全、借口调用方便、设计简洁等等。映射到科研上,体现是:工作思路巧妙、分析严密、逻辑通畅、简明扼要等。

    • 懂审美买美的,爱慕虚荣的买贵的,懂技术的买性价比高的,爱明星买明星代言的。这些属性会有重合,重合越多这个产品的消费群体就越广。

    • 作者总结的共同原则有:
      好设计是简单的设计。
      好设计是永不过时的设计。
      好设计是解决主要问题的设计。
      好设计是启发性的设计。
      好设计通常是有点趣味性的设计。
      好设计是艰苦的设计。
      好设计是看似容易的设计。
      好设计是对称的设计。
      好设计是模仿大自然的设计。
      好设计是一种再设计。
      好设计是能够复制的设计。
      好设计常常是奇特的设计。
      好设计是成批出现的。
      好设计常常是大胆的设计。

    • 一般拥有这种品位和能力的人,都让人觉得有点洁癖,强迫症以及所谓的完美主义倾向,这些特质不是所谓的作秀和装逼,而是内心觉得看到觉得不对的就内心极为难受,压抑不住,创造者的特质就是在细节方面让人觉得有吹毛求疵的倾向。

    • 丘吉尔:Perhaps I can implore you not to feel the need to be too accurate.(我想恳请你不必画得太准确。)
      给丘吉尔画肖像画的画家:Why? Accuracy is truth.(为什么?准确才是真实。)
      丘吉尔:No. For accuracy, We have the camera. Painting is the higher art. And I never let accuracy get in the way of truth if I don’t want it to.(不。想准确的话,我们有相机。绘画是更高一层的艺术。我从来不会让准确遮挡真相。)
      ——美剧《王冠》第一季

    • 以前历史老师总说,是历史成就了一个人,而不是一个人成就了历史,尽管当时不是那个人,也会有另一个人出现。经常是大势和环境成就了你,不一定因为你就多么与众不同。

    • 时势造英雄,个人的能力是渺小的,无论你认为你多么强大,在历史的洪流之下,我们顺势而行。无论你认为你做出多么英明的决策也不过是在环境和条件的自然反射。

    • 不得不说,发展就是让平均每个人可利用的资源越来越多。当总资源无法满足每个人的需求时,就会催生技术变革;当总资源很大程度可以满足每个人的需求时,生活水平就会极速提高。

第三部分 黑客的工具和工作方法

10编程语言解析

一个操作所需的代码越多,就越难避免bug,也越难发现它们

程序员的时间要比计算机的时间昂贵得多,后者已经变得很便宜了,所以几乎不值得非常麻烦地用汇编语言开发软件。只有少数最关键的部分可能还会用到汇编语言,比如开发某个计算机游戏时,你需要在微观层面控制硬件,使得游戏速度得到最大限度的终极提高。

语言设计者之间的最大分歧也许就在于,有些人认为编程语言应该防止程序员干蠢事,另一些人则认为程序员应该可以用编程语言干一切他们想干的事。Java语言是前一个阵营的代表,Perl语言则是后一个阵营的代表。(美国国防部很看中Java也就不足为奇了。)

  • 现在的人信息量太大了,没大多时间深入学习精通,大多数水平有限,但又要避免出错,所以go的限制,静态语言,一定程度上符合大家的利益
  • 来自微信读书评论: rust的设计哲学恰恰相反,认为编码的都是傻x,事实上rust这种思路更符合现实

11一百年后的编程语言

任何一种编程语言都可以分成两大组成部分:基本运算符的集合(扮演公理的角色)以及除运算符以外的其他部分(原则上,这个部分可以用基本运算符表达出来)。

如果我们把一种语言的内核设想为一些基本公理的集合,那么仅仅为了提高效率就往内核添加多余的公理,却没有带来表达能力的提升,这肯定是一件很糟的事。

没错,效率是很重要,但是我认为修改语言设计并不是提高效率的正确方法。

正确做法应该是将语言的语义与语言的实现予以分离。在语义上不需要同时存在列表和字符串,单单列表就够了。而在实现上做好编译器优化,使它在必要时把字符串作为连续字节的形式处理。

  • 来自微信读书评论: Common Lisp的变量是动态的,数据类型是静态的。比如declare function的时候,任何数据类型都可以作为变量;而一个有string type的语言,变量名就只能是string
    用动态语言编写的程序会更简洁,互动性更强,更多hacks,更常用prototype而不是class。但同时运行的时候也会有更多type error,所以需要好好写测试。
    用静态语言编写的程序在设计上更直观,程序更稳定,更常用class而不是prototype。程序在编译的时候就可以捕获大多数错误。
    另一种理解动态静态的方式是:动态的思维是离散的、公理化的、prototypical的、象征着直觉;静态的思维是抽象的、定理推导式的、classified and hierarchical的、遵循着逻辑。
    这篇文章既然在讨论程序语言的进化,那么一定是从动态的角度出发,从设计简洁的基本公理开始,以期达成创新。(后文提到是否应该用list来表达数字正是作者对简化公理的猜想。或许新的计算机出现以后这真会成为现实呢?)
    由此推算,可能初创公司更适合用迭代快速的动态语言,而成熟的企业更需要静态语言来确保代码的可读性和实用性。
    我等菜鸡还是先乖乖练好静态语言再说吧。动态语言也就是作者这样的满级人类用得比较爽,毕竟他已经把写代码比作写文章了……

对于大多数程序,速度不是最关键的因素,所以你通常不需要费心考虑这种硬件层面上的微观管理。随着计算机速度越来越快,这一点已经越发明显了。

essay(论文)这个词来自法语的动词essayer,意思是“试试看”。从这个原始意义来说,论文就是你写一篇文章,试着搞清楚某件事。软件也是如此。我觉得一些最好的软件就像论文一样,也就是说,当作者真正开始动手写这些软件的时候,他们其实不知道最后会写出什么结果。

  • 来自微信读书评论: 好的软件是边探索边写边迭代出来的,作者大概指的是黑客写的小而精美的软件,而不是软件工程下的大型软件

一般来说,如果你动手创造一种新语言,那是因为你觉得它在某些方面会优于现有的语言。Java语言之父詹姆斯·高斯林在第一份《Java白皮书》中说得很清楚,之所以要设计Java,就是想解决C++的一些弱点。所以结论就是,各种编程语言的编程能力是不相同的。

编程时提高代码运行速度的关键是使用好的性能分析器(profiler)

为了写出优秀软件,你必须同时具备两种互相冲突的信念。一方面,你要像初生牛犊一样,对自己的能力信心万丈;另一方面,你又要像历经沧桑的老人一样,对自己的能力抱着怀疑态度。在你的大脑中,有一个声音说“千难万险只等闲”,还有一个声音却说“早岁那知世事艰”。这里的难点在于你要意识到,实际上这两种信念并不矛盾。你的乐观主义和怀疑倾向分别针对两个不同的对象。你必须对解决难题的可能性保持乐观,同时对当前解法的合理性保持怀疑。

  • 有很多工作并不像计算机一样,不是0就是1,对待任务,我很有信心做好,但同时以往的经验告诉我,随着工作进行的深入,会有很多细节需要考虑,可能并不是简单就能完成的事,毕竟内心还是想尽可能接近完美

做出优秀成果的人,在做的过程中常常觉得自己做得不够好。其他人看到他们的成果觉得棒极了,而创造者本人看到的都是自己作品的缺陷。这种视角的差异并非偶然,因为只有对现状不满,才会造就杰出的成果。

如果你能平衡好希望和担忧,它们就会推动项目前进,就像自行车在保持平衡中前进一样。在创新活动的第一阶段,你不知疲倦地猛攻某个难题,自信一定能够解决它。到了第二阶段,你在清晨的寒风中看到自己已经完成的部分,清楚地意识到存在各种各样的缺陷。此时,只要你对自己的怀疑没有超过你对自己的信心,就能够坦然接受这个半成品,心想不管多难我还是可以把剩下的部分做完。

让这两股相反的力量保持平衡是很难的。初出茅庐的年轻黑客都很乐观,自以为做出了伟大的产品,从不反思和改进。上了年纪的黑客又太不自信,甚至故意回避一些挑战性很强的项目。

  • 来自微信读书评论: 达克效应的两面:无知的人认为自己无所不知、无所不能,能力越差越自信无比;能力强的人经常怀疑自己的能力,自信不足。学会平衡两种状态

大家都知道,让一个委员会负责设计语言是非常糟糕的主意。委员会只会做出恶劣的设计。但是我觉得,委员会最大的问题在于他们妨碍了“再设计”。在委员会的主持下,修改一种语言是非常麻烦的事,没有人愿意自讨苦吃。而且,即使大多数成员不喜欢某种做法,委员会最后的决定往往还是维持现状。

  • 大公司会有很多制度,有些人很不喜欢,但我恰恰认为这是保护员工的机制

设计与研究的区别看来就在于,前者追求“好”,后者追求“新”。优秀的设计不一定很“新”,但必须是“好”的;优秀的研究不一定很“好”,但必须是“新”的。

我认为这两条道路最后会发生交叉:只有应用“新”的创意和理论,才会诞生超越前人的最佳设计;只有解决那些值得解决的难题(也就是“好”的难题),才会诞生最佳研究。所以,最终来说,设计和研究都通向同一个地方,只是前进的路线不同罢了。

如果把创造一种编程语言看成设计问题,而不是科研方向,那么有何不同?最大的不同在于你会更多地考虑用户。

优秀的建筑师不会先设计,然后强迫用户接受,而是先研究最终用户的需求,然后做出用户需要的设计。

注意,我说的是“用户需要的设计”,而不是“用户要求的设计”。

  • 来自微信读书评论:
    • 乔布斯:“人们不知道他们想要什么,直到你把产品放到他们面前。” 用户不可能了解所有选择,特别是那些还未被创造的选择,直到你创造出了它们。王维嘉《暗知识》里对这种情况做了更basic的梳理:有些需求是已知的,有些需求是未知的。在你把未知的选项呈现在它们面前之前,你永远不可能通过倾听需求而得到最优解。
    • 用户提的需求不一定都是对的,要经过思考后加以取舍。分清目标和手段,目标只有一个,手段途径却有很多
    • 并不是来自用户的所有需求都是合理的,即便是面对合理的需求,从用户提出需求所解决的问题着手,去挖掘出他们的根本目的,再设计出完备的解决方案,会比直接照搬照套来得更有效果。

在软件领域,贴近用户的设计思想被归纳为“弱即是强”(Worse is Better)模式2。这个模式实际上包含了好几种不同的思想,所以至今人们还在争论它是否真的成立。但是, 其中有一点是正确的,那就是如果你正在设计某种新东西,就应该尽快拿出原型,听取用户的意见。

  • 来自微信读书评论: 刚做软件的时候,我也很赞同这种模式,原因是因为我认为如果你发布了一个很磕碜的产品恶心到了用户,用户一定不会在给你任何尝试的机会,所以应该一气呵成出一个完美的产品交给用户,让他们忠实。后来发现根本不可行,闭门造车,永远造不出用户喜欢的东西。但是如何避免磕碜的产品恶心到用户呢?那就是采用天使用户模式,每次迭代产品让这部分愿意参与尝试的天使用户进行尝鲜,根据他们的反馈来决定是否大量发布,既保证了快速迭代,又保证了用户体验

2 “弱即是强”指的是一种软件传播的模式,由Common Lisp专家理查德·加布里埃尔(Richard P. Gabriel)于1991年在“Lisp: Good News, Bad News, How to Win Big”一文中首先提出。它的含义非常广泛,涉及软件设计思想的各个方面,其中一个重要结论就是软件功能的增加并不必然带来质量的提高。有时候,更少的功能(弱)反而是更好的选择(强),因为这会使得软件的可用性提高。相比那些体积庞大、功能全面、较难上手的软件,一种功能有限但易于使用的软件可能对用户有更大的吸引力。加布里埃尔本人经常举Unix和C语言的例子,Unix和C在设计上考虑了实际环境,放弃了一些功能,但是保证了简单性,这使得它们最终在竞争中胜出,成为主流操作系统和编程语言。——译者注

与之对照,还有另一种软件设计思想,也许可以被称为“万福玛丽亚”模式。它不要求尽快拿出原型,然后再逐步优化,它的观点是你应该等到完整的成品出来以后再一下子隆重地推向市场,就像圣母玛丽亚降临一样,哪怕整个过程漫长得像橄榄球运动员长途奔袭、达阵得分也没有关系。在互联网泡沫时期,无数创业公司因为相信了这种模式而自毁前程。我还没听说过有人采用这种模式而获得成功。

  • 我的另一种想法: 一个app用于试错,最后开发另外一个app替换,前一个app用来导流,制造竞争关系

软件领域以外的人可能没听过“弱即是强”,所以意识不到这种模式在艺术领域普遍存在。以绘画为例,文艺复兴时期就有人发现了这一点。如今,绝大部分美术老师会告诉你准确画出一个东西的方法,不是沿着轮廓慢慢地一个部分一个部分地把它画出来,因为这样的话各个部分的错误会累积起来,最终导致整幅画失真。你真正应该采用的方法是快速地用几根线画出一个大致准确的轮廓,然后再逐步地加工草稿。

先做出原型,再逐步加工做出成品,这种方式有利于鼓舞士气,因为它使得你随时都可以看到工作的成效。在开发软件的时候,我有一条规则:任何时候,代码都必须能够运行。如果你正在写的代码一个小时之后就可以看到运行结果,这好比让你看到不远处就是唾手可得的奖励,你因此会受到激励和鼓舞。

跟你说实话吧,画家之间甚至流传着一句谚语:“画作永远没有完工的一天,你只是不再画下去而已。”

士气也可以解释为什么很难为低端用户设计出优秀产品,因为优秀设计的前提是你自己必须喜欢这种产品,否则你不可能对设计有兴趣,更不要说士气高昂了。

为了把产品设计好,你必须对自己说“哇,这个产品太棒了,我一定要设计好!”,而不是心想:“这种垃圾玩意,只有傻瓜才会喜欢,随便设计一下就行了。”

  • 现在写代码,对一些复杂的代码段,我喜欢针对做一下单元测试,这样可以快速看到效果,也可以避免后续整个流程时出现太多的bug
  • 来自微信读书评论
    • 学习编程语言也是这样,不要妄想着从书本上把所有东西都学精通,然后再开始接触实际的项目,没有实际的操作,不能对自己学到的东西加以巩固和思考,书上的东西始终是作者的
    • 先有整体概念,然后,再优化。先做一个框架,然后再丰富细节,一定要先想好,保证框架是对的,不然,重头再来的成本太高。
    • 如何能把事情做的更好:
      1、目标分解成小目标。2、在众多方案中采取能看到过程效果的方案。3、奖赏机制,如quick win。
<1…456…16>

153 日志
165 标签
RSS
© 2025 Kingson Wu
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4