|
- M3 [' ]% u1 Q/ Q6 Q
我发布了第一个版本的SumatraPDF是在2006年。那是15年前的事了,这似乎是进行回顾的好时机。 4 }3 z- y0 n1 y& l& _
该应用程序 6 `$ l$ x' g( r
SumatraPDF是一个适用于Windows的多格式(PDF、ePub、Mobi、漫画书、DjVu、XPS、CHM)阅读器,目前看起来像这样:
3 K3 i- R6 E6 f; e9 {2 C
, [0 G8 P0 l! J, w 准则 - _% x( ?- m; P) k; W* y( p, |0 a
SumatraPDF是一个用于Windows的开源文档阅读器。它一开始是一个PDF阅读器,所以叫这个名字。随着时间的推移,我增加了电子书格式(epub、mobi)、漫画书(cbz、cbr)、DjVu、XPS、图像格式等。 ( k0 t% ?( u9 k. G4 H% f
这大约是12.7万行的C++(不包括其他人写的库)。 7 ?3 _; {8 o9 K X: ~
它是根据Win32 API编写的,没有使用Qt这样的GUI抽象库。这有助于使它尽可能地小而快。 8 |) F4 a: V( E6 ?% N. F0 B0 A1 I
几乎所有的内容都是由2个人写的,偶尔也有其他人的贡献。
* a+ v8 A% I4 Z& W$ P 编写的代码量实际上更高。这是长期运行的代码库的性质,代码被写入和重写。我们删除、增加、改变。
& G; b1 s% z" ?8 v9 s3 I 这是一个副业,在工作之余完成,不是全职工作。在一个应用程序上工作的日常磨练是怎样的? - N% r9 O3 a% c, c# J0 Q3 o
它看起来像这样: " J: y3 v) n N8 A' H
5 ~2 I, {8 v/ F; C0 g( G4 w0 g 你也可以偷看一下我的开发日志. 我一年前才开始写,所以只涵盖了15年中的1年。 ; z8 i$ `, |# ~4 e4 b* b5 p* k1 P
我为什么创建SumatraPDF
( |- W1 {" r! i+ C7 v( _4 w SumatraPDF是我称之为意外的成功。
% [% R! \; Y' ? `1 u$ p 我从未想过要为Windows写一个PDF阅读器。
# [' D3 _2 @" [2 {) h7 c# J 2006年,我在Palm工作,我的工作职责之一是为Foleo编写一个PDF阅读器。 Foleo,这是一款由ARM和Linux驱动的迷你笔记本电脑。你大概从未听说过Foleo,因为它在发布前几周就被取消了,原因我不清楚。 % \0 K: q5 O5 j' c6 o' {: o6 a: p
当时我不知道PDF很流行,但Palm管理层知道,这就是为什么他们决定PDF阅读器是一个必须的应用程序。我最终成为这个项目的(唯一的)开发者。
' m) n& M0 X2 Q6 F) T 编写一个PDF渲染库是一项多年的工作。我们没有几年的时间,所以我用开源的渲染库。 5 T; Q1 A1 [8 {! a) Q% u9 g E/ I+ S' v
我的工作是写一个基本的PDF浏览器,使用Poppler将PDF页面渲染成内存中的位图,并将这些位图显示在屏幕上。 0 L& g& f; `* L. G
PDF是一种复杂的格式,一些PDF的渲染速度很慢。我想提高速度,因为杰夫-贝佐斯告诉我,速度是客户永远关心的东西。 " C/ o+ `# y( [3 Z: u' ?
意外的应用程序
A8 t- t8 N7 _% L$ T3 _ 提高速度的方法是对代码进行剖析,看看结果。
+ j8 h* y' ?4 `6 Q; u5 L1 S# N1 c0 | 不幸的是,用于未发布的ARM硬件的工具链并不是很好。忘掉剖析器吧,孩子,庆幸你有一个C++编译器,不用像Steve Wozniak那样通过输入十六进制来输入汇编。 , Q* q6 K: j1 C9 [) r* |
Windows有体面的剖析器,所以我为Windows编译了Poppler。 / u. G$ k% L# P! G, U" Y* l7 ]
一旦我有了在Windows上工作的库,我就写了一个最简单的GUI应用程序,可以显示页面并允许在页面之间进行导航。
; S A4 g% H" ]9 ? 你知道什么?我有一个用于Windows的简单的PDF阅读器。
' y( L' G9 A9 K4 d4 v" r 我在我的网站上发布了它。它不能做什么,所以我把它标记为0.1版本。 ; w8 F" A) F- t. B: a5 h+ c
如果你不为你的应用程序感到尴尬,那么你已经等了很久才发布它。
9 q$ d& P+ j1 `3 I 这个智慧的小插曲不是我想出来的,但我同意它。
9 K. O9 T1 p7 j6 W5 U 获得早期用户,了解他们最想要的功能,这比辛苦几个月或几年,在你知道有人关心之前实现很多功能要好得多。 + \" i' x8 R; ^1 i+ O* @
剖析、性能优化和对开放源码的贡献 6 X( i7 g; r" s/ Q( Z. D4 J
回到剖析:我的计划成功了。
% x, {! ^, d% @( I1 i m1 N 我对渲染时间最长的文件进行了分析,并进行了一些简单得出奇的、有效得出奇的优化。
) v0 ]6 n) F( P) u 如果说内存服务器,2个优化的效果是最大的: 优化字符串类,使用所谓的 "小字符串优化",即在字符串类中添加一个小的缓冲区,以容纳内联的小字符串(而不是总是为字符串分配内存)。字符串被频繁使用,而且大多数是小字符串通过将其转换为批量读取的方式来修复逐个字节的i/o。在一些代码路径中,代码的结构方式是为每个字节做一个虚拟的C++调用和一个C read()函数调用。这些都是非常便宜的,但当你做500万次的时候就不一样了。
- S7 _7 V( ^# n' R8 {* D* U 作为一个好孩子,我确实向Poppler提交了我的修改。
" s' S3 \3 X; h5 b 就像我为开源项目做贡献的经验一样,这更像是一次失误而不是一次成功。
7 G3 Z3 z, |, i' k) g$ b# } 是的,我得到了13个提交,但这个项目并不活跃,维护者也不急于接受除小改动以外的东西。忘记任何重大的重构。
& o( O$ j" V. p5 t5 q, b( \ 我不是一个自愿用头撞墙的人,所以我不再尝试。 ) Q1 _8 ^: w: i5 ]! G
(如你所见,我是一个出色的团队成员)。 7 u6 C6 s' G5 m9 i* B- I) E
代码质量 0 n6 p( m8 ]3 i" [1 z4 {
我想要它,你也应该想要它。
( `2 R, C3 z) }* S 如何在大多数情况下独自工作,没有人做代码审查,没有专门的QA团队的情况下保持高的代码质量?
5 s- a) T1 R- K! R+ T 下面是方法: 自己测试代码。在调试器中浏览新添加的代码,验证新添加的功能是否符合预期,并在一般情况下经常使用该应用程序。自动崩溃报告。不幸的是,它的构建很麻烦,但这是你为提高软件质量所能做的最重要的事情。简而言之:设置异常处理程序来捕捉应用程序中的崩溃,在崩溃处理程序中从服务器上下载符号以获得可读的callstack,创建一个崩溃报告,包括所有线程、程序和操作系统信息的callstack,记录并提交给服务器。在服务器上,处理这些文件并生成网页以方便查看崩溃情况。就像我说的:建立它是一件很痛苦的事情。一旦你有了崩溃,就偶尔看看它们,并试图找出出错的地方并加以修复。assert()。断言是C++代码中公认的做法:只在调试构建中执行的额外代码,验证某些条件为真。如果不是,就说明出了问题,你应该进行调查。我写了我自己的类似断言的函数,在非调试的预发布版本中启用,这样我就能自动收到人们碰到这些条件时的错误报告。相信我:你自己做再多的测试,也无法与一千多人在使用该应用程序时做的所有不同事情相提并论。记录。在调查问题时,了解导致崩溃的事件序列是有帮助的。我的小型日志模块将日志记录到一个内存块中。这将与崩溃报告一起被发送。我也有一个选项,可以将日志记录到一个文件中,最近我还通过命名的管道将日志记录到一个单独的日志应用中。这很完美,因为大多数时候我并不关心日志,但当我关心时,我不想重启应用程序来启用日志。有了独立的日志应用,SumatraPDF一直在记录日志,当它检测到日志应用正在运行时,它也会向它记录。实施起来很简单:日志应用程序创建一个命名的管道,记录器打开这个管道(就像一个文件),如果打开成功,就意味着日志应用程序正在运行,它将读取我们写到管道中的日志。静态代码分析:C++编译器的最大警告级别,将警告变成错误,Visual Studio的`/analyze选项,cppcheck,clang-tidy,GitHub的CodeQL。偶尔运行这些,并修复错误和警告ASAN (地址消毒剂),是非常棒的。在Visual Studio 2019的某个点版本中被添加。以很小的性能代价,它可以检测你是否过度写入内存或试图读取未初始化的内存。我有一个启用了ASAN的配置。它的速度足够快,可以作为常规构建使用。压力测试。Sumatra的工作主要是渲染复杂的文件格式。由于格式的复杂性,在特定的文件中经常出现崩溃的情况。为了确保没有崩溃,我写了一个压力测试代码,读取并渲染一个目录中的所有文件。在发布之前,我通常会在我多年来积累的大量测试文件上运行它。单元测试。我没有太多的单元测试,它们主要用于测试低级功能的边缘情况,如字符串格式化。他们偶尔会发现错误。内存泄漏。令人惊讶的是,很难找到一个容易使用的内存泄漏检测工具。我正在开发一个非常简单的内置泄漏检测器。在此期间,我正在使用 Dr. Memory.它可以工作,但速度超慢。5 K7 o( ~" t' u( Q0 p ]
频繁发布 - m! B) {$ a3 j# F0 X& J
当你没有很多功能的时候,改进应用程序是快速而简单的。实现 "转到 "对话框(在0.2版中实现)并不费力。
5 l0 t9 [& o& z. b1 }# V3 x 一方面,我不想太频繁地发布,但我也确实希望用户能尽快获得新的功能。
5 f: e/ S# @+ F% K, z- v, L/ p* m 我对新版本的政策是:当至少有一个明显的、用户可见的改进时才发布。
2 E2 |# f" l2 ^2 ?( T 网络应用程序将其发挥到了极致(一些公司每天都会向生产部署多次)。
% x" D# l7 C ^8 R9 W/ r, a 在桌面软件中,这就有点复杂了,我必须建立一些功能来使它变得简单,即添加一个新版本的检查,编写一个可以更新程序的安装程序。
# K3 j- V) B( w BTW:我的意思是 "与编写的新代码的数量成比例的频繁"。SumatraPDF的发布在绝对意义上并不频繁,但如果你考虑到它是一个兼职的、下班后的项目,就会很频繁。
+ a8 J7 O* P0 o- \; \% z |! d0 q 像对待商业软件一样对待开源项目 2 O+ |9 I' I) H( @5 i* {0 p9 k: ]
大多数开源项目可能不属于这个类别,但如果你想让你的开源项目尽可能地成功,就像它是一个软件公司的商业产品那样行事。
% J7 x, _" w* T4 l7 q7 j2 _, I: X 它在实践中意味着什么?
5 \4 K {9 [% J, w( p 从第一天起,我就为这个应用程序创建了一个网站。它有屏幕截图,有文档,很容易下载和安装。当然,Reddit上的一个好心人称它是 "一个6岁孩子做的网站"。这里的教训是双重的: 无视仇恨者和混蛋一个由6岁儿童建立的网站总比没有网站好。它不一定要漂亮,但一定要有功能。
* @( |8 p( N! k 我做了基本的SEO。没有超出谷歌 "SEO 101 "文件的内容:只要注意URLs,放置正确的元数据,使用正确的关键词。 % M9 P0 f/ d5 R
我有一个论坛,供用户提出问题、提交功能请求,偶尔也会相互支持。
- ~! y4 U% K5 H4 X$ Z 我使安装过程尽可能地简单。
1 \9 Q4 V: J5 V0 K! C, p" g: d! p 凡是促进商业软件的好主意,对开源项目来说也是一个好主意。 3 g0 r( S+ g6 v3 c! C q6 ^
在汽车运行中切换发动机 % s; B& s' X* m, ~1 b8 ^
在某种程度上,我决定从Poppler切换到 mupdf因为mupdf更好,并且得到了积极的维护。
' [5 {/ D- d+ c. L3 Z 改变应用程序以使用完全不同的库,这不是一个下午就能做到的。 " p' X1 B9 k% z7 r$ }, j: u+ b; E
在甚至不能编译的代码上工作很长时间,这让人士气低落。
' `# W) s8 b4 P9 C2 B& E1 C 为了保持东西的编译,同时也为了支持替代的渲染引擎,我为渲染引擎开发了一个抽象。
& a5 Y5 C; Z; `% ] D/ I; Y) m 该引擎将提供用户界面所需的功能:获取文档中的页数、每页的尺寸(以计算布局)、将一个页面渲染成位图等。 2 ^* Y- x" {; k x2 C
我比大多数程序员(至少是那些喜欢在Hacker News上发表意见的人)更不热衷于抽象,但在这种情况下,它对我很有帮助。
* f% C# x; ^7 q; V; V1 w 我能够逐步将程序形式从使用Poppler API转换到通过引擎抽象使用Poppler,再到通过引擎抽象使用mupdf。 ) ~- u: V0 g- H. i3 {9 z& k
有一段时间,我同时支持这两个引擎,但最终我改成只支持mupdf,以保持应用程序的小型化。 & O' ]1 R# F; Y% D
这为通过相同的抽象来支持其他格式打开了大门。
4 I1 w6 R5 d; E: m% @9 F) ]& ?5 W0 s 简单性与可定制性
$ D. f3 _. l3 g2 \. W+ a 简洁性是卖点。 T( d% X6 f o0 v( C- Z
我从Mozilla Firefox的历史中学到了这一点。 * M1 t( F: }0 l0 o4 u6 r, R( \
在Firefox之前,有一个Netscape Navigator。它是一个集网络浏览器和电子邮件客户端于一身的应用程序的怪兽。 , N6 X8 j: R4 _, F1 z. w8 Y
网景公司无法控制自己,不断增加功能,导致了非常复杂的用户界面。 5 s. _# W9 D: f- w* y1 g
Mozilla内部的一小群叛徒分叉了代码,专注于简单的用户界面。 3 \ E2 } R" S9 | t# T6 R
简单的Firefox比复杂的Navigator更受欢迎,最终完全吃掉了它。
& V; ^) B5 f7 ~5 ^: Y2 e w) \6 Y 从一开始,我的目标就是要让SumatraPDF的用户界面尽可能的简单。一个80 ⁄20 应用程序:80%的功能和20%的用户界面。 ! b9 L o4 G0 c7 [' V4 ?( Z
这需要解决。我不断收到在工具栏上添加更多图标的请求,而我不得不不断地说 "不",因为为满足10%的用户而在工具栏上添加2个图标,会使100%的用户的应用程序变得更糟。 ! \# S" m+ e; q+ P. _4 t
另一个陷阱是额外设置的警笛声。有时人们建议,程序不应该做X,而应该做Y。他们不愿意删除X,而是建议添加一个新的用户界面设置"[ ]做Y而不是X"。 ) n p A9 s7 I$ |
设置对话框有100个设置,这不是一个好的解决方案。它使每个人的应用程序变得更糟,因为他们的选择太多,而且把重要的选项隐藏在非重要的选项的海洋中。 ) }9 N4 P8 _7 ]% i
更不用说每一个条件行为都需要更多的代码,更多潜在的错误和更多的测试。
! D7 ?2 j& u6 ?5 U$ h( w 话虽如此,我也相信可定制性是很重要的。我相信,Winamp之所以成为一个占主导地位的音乐播放器(在当时),很大原因是它有能力给整个用户界面换肤。 3 }, N/ V2 s, [' t4 i
一些高级功能可能只有20%的用户使用,但这些用户很可能是权力用户,他们会比其他80%的用户更多地宣传该应用。
/ n! E U+ L: M! \( t- d6 d 我对用户界面的简单性与可定制性的解决方案:高级设置文件。 5 o& n' J7 |1 R
我设计了一个简单的、人类可读(和人类可写)的文本格式,用于 高级设置.想象一下JSON,但要更好。 ; V- Z& q5 t$ J0 ]
我懒得写用户界面来改变这些高级设置。我只是用该文件启动notepad.exe。当用户改变设置并保存文件时,我重新加载并应用这些改变。 * W9 l: v) ]+ Z. {/ N2 v9 ^
水,我的朋友
! p4 \3 O0 a3 p/ N 变化是唯一不变的。我们必须适应世界的变化。 7 z1 P2 R# b* m* J" R1 C
我无法相信有多少流行的项目仍然使用蹩脚的Sourceforge作为源码库或邮件列表。
Y- {$ r" i: _9 d 实际上,我可以相信:改变事物需要努力,阻力最小的途径是什么都不做。 5 Q2 `& {: e4 p/ f3 t
我从Sourceforge开始,转到code.google.com,然后到github.com。
# o+ W& r8 f7 Y5 y 我换了三次论坛软件。
8 U% j% V! r' N& C0 G7 P 我已经添加了一个浏览器插件,然后在浏览器停止支持此类插件时将其删除。
; W1 Z: A, A3 y+ X0 L 我把存储偏好的格式从二进制改为人类可读的文本。
- y9 O5 X) A1 E& H/ m; A+ g3 S* S) e Windows XP从大多数用户使用的操作系统变成了不再被支持(在微软停止支持它很久之后)。 9 X0 y/ I B4 N. X- w" O
起初我只有32位的构建,现在我两者都有,但强调的是64位的构建。
8 N1 I4 Q" L. v" k. e2 D. Q 跳出框框思考
9 O' Y% f7 c: d% q% f 跳出盒子思考是很难的,因为盒子是看不见的。 # h0 |; D$ }& |' u/ ?
SumatraPDF并不是有史以来第一个PDF阅读器应用程序。
) V) i8 r2 o: v- V- y. A8 t4 [ 但大多数PDF阅读器并没有成为多格式的阅读器。 " g- t9 `7 ^ z2 G- }8 U: n! m# x
事后看来,支持尽可能多的文档格式是一个明显的想法,但我花了5年时间才意识到这一点。
- @( N+ I$ R3 V5 q$ E 大多数阅读器仍然是单一格式,我相信多格式有助于SumatraPDF的普及。
+ {1 v8 p* b% P- l( Z& T3 d' _/ t% F 我不能说这是完全独特的想法。在SumatraPDF之前,早就有多格式图像查看器,我可能是受到了它们的启发。 ' A! e C/ P) n# @, G0 P! N! R- k+ \
小而快--两者兼得 ( e) G% _9 O; w3 u3 f
按照现在的标准,SumatraPDF很小(安装程序小于10MB),而且可以立即启动。 2 W. |, e7 v& E5 a8 A. F
我相信个头小、看起来快是采用的一个重要原因。
9 S, \/ p+ x/ B% ~! e! Z! L8 q 这又回到了杰夫-贝佐斯的智慧:永远不会有用户想要臃肿和缓慢的应用程序的时候,所以小而快是一个永久的优势。 : y* c$ u/ n, Y0 a) T- K( C$ }
我如何保持SumatraPDF的小型化? . @ {1 D" j; ^. q P
我避免不必要的抽象。Window的控件系统在编程时是个巨大的麻烦。我可以使用Qt、WxWindows或Gtk等包装器。它们更容易使用,但会导致即时的、巨大的臃肿。 ) j( W" L8 [7 z+ }7 x
我并不害怕自己写东西的实现。我有自己的JSON、HTML/XML解析器,其大小仅相当于这些任务的流行库的一小部分。
* B6 z5 h6 Q3 o0 S$ {+ _7 j 我积极地利用Windows中包含的丰富功能。
3 Q, [- G( C" S 比方说,我需要做一个网络请求。我可以包括一个像curl这样的怪物库,或者我可以使用win32 APIs写300行代码。我写了300行代码。 z' K9 {/ ^" e1 _8 P( b. ~
没有臃肿是很难注意到的,因为它不在那里。
# o: R! X$ R/ q7 H. _7 B- I! P: t 我最讨厌的是过度使用XML来存储数据。 6 w' J3 m: U* W+ S- T
当我在Palm工作时,我参加了一个关于手机自动更新系统的设计会议。它的一部分是在图像中存储关于当前版本的信息,下载关于最新版本的信息并进行比较。 . r( Y5 z$ n* }% Z' ^& ]6 I
开发者决定使用XML来存储这些信息。对于存储版本号这样的简单信息来说,这似乎是一个很大的臃肿。仅仅是一个符合要求的XML解析器就是大量的代码。当然,一个简单的二进制格式会更容易实现,我建议说,但被忽略了。 5 O* s |7 `3 o8 y7 S6 H- i
如果你没有权力解雇某人,你的想法就会被忽视。 3 ?3 H: j k1 n5 H
(如你所见,我是一个伟大的团队成员)。 6 B6 k* \2 Z* k/ O
为了存储高级设置,我设计并实现了一种文件格式,它比XML小,人类可读可写,只需几百行代码就可以实现。它和JSON一样强大,甚至更具可读性。
; O( i' I- I& Z 它是如此简单,以至于在实现它之后,我有时间为C++对象实现一个序列化系统和一个Go代码生成器。要增加更多的设置,我不需要写更多的C++代码。我只需将数据定义添加到Go生成器中,重新运行它,就能自动生成数据驱动的C++解析。 6 g3 A4 {8 }+ s6 Z' f1 l
这是我的项目,我就像这样做。 4 M, d8 }7 g5 a9 n7 i& `& R
当有人付钱让你写代码时,你必须按照他们喜欢的方式来写。 ' \: @! Q6 x( x* H' @# o5 w7 t
从事没有报酬的代码工作的一大吸引力是,没有人可以告诉你该做什么或怎么做。
' w3 C; u) x) |( o 我的代码不会通过谷歌的代码审查,不是因为它不好,而是因为它经常是非正统的。在公认的教条之外。 3 D' u: a9 r. F" N: t
(如你所见,我是一个伟大的团队成员)。
, S9 ?6 P% Q5 ?5 x$ P 我总是把SumatraPDF作为我测试疯狂想法的游乐场。
8 |7 L6 }+ [: g. U# Q 通过不使用STL来最小化代码大小?这很疯狂,但我做到了。当然,在2006年,STL还不是很好。 ( k0 \2 M I% P/ ^8 S" T7 p
我了解到Plan 9的C代码有非传统的#include文件方案,他们不在每个.h文件中放#ifdef包装器,以允许多次包含,而且.h文件不包含其他.h文件。因此,.c文件必须以正确的顺序包含他们需要的每一个.h文件。这有点麻烦,据我所知,没有其他现代C++代码库保持这样的纪律。
+ e; i' t5 ~2 V1 A 但这是我的项目,所以我做了,而且一直在做。它可以防止.h文件之间的循环依赖,也不会因为不小心重复包含相同的文件而导致C++构建时间的增加。 ' U6 Y. `4 f4 g8 E& X+ x
我实现了一个受CSS启发的UI系统。不是很好,但却是我的。而且我打算用一个不同的来代替。
% Q: }" i& N2 R' ~ 因为我可以。
7 O5 _- u' L! n( t$ g 因为没有人可以告诉我不要这样做。 : |' H i/ P4 ?
跨平台被高估了 ' L, S4 M K" F4 w! W
SumatraPDF是一个毫不掩饰的 毫不掩饰地说,它是一个仅适用于Windows的应用程序。
' }& @7 `+ U% x* ? 支持其他平台(Linux、Mac、Android)是最频繁的要求之一。一个我不得不拒绝的请求。
2 u. g6 [' u) P+ g) [ 首先,有一个务实的原因:我只是没有足够的带宽为3个平台写代码。
0 K5 o/ ^* A; Q- Y( m 第二,我相信一个平台的优秀应用可以比3个平台的平庸应用更受欢迎。
! ^0 n4 u% C- [( u 回到第一个原因:我没有足够的带宽来编写三个优秀的应用程序。SumatraPDF之所以小,部分原因是我在用户界面上使用了win32 APIs。
! {! h ~0 a% ]" l7 f4 g0 L 一个人要想尝试跨平台的应用,唯一的办法就是使用Qt、WxWidgets或Gtk等UI抽象层。 - t% t: W! Y5 l
问题是,Gtk很丑,Qt极其臃肿,WxWidgets几乎不能用。
* u6 L3 U6 ]% s. F" f3 O9 |; d5 V 测试是没有必要的,代码审查也是如此 3 U5 a0 x) M' u. n
我不是说测试不好,也不是说你不应该写测试或做代码审查。 " F. s0 q6 n3 J5 z1 t
我是说,它们是没有必要的。 " m' y# r6 d5 k5 j: ], G1 U N& p
教条是强大的。在我的公司生活中,有时我觉得写测试只是在进行运动。也许我们应该花更多的时间来写代码,我想? 4 e( p- o! P4 \" {/ ]0 |. B* _
但是,如果你试图向你的同事们提出关于更多测试和更多代码的细微观点,你会被烧死在木桩上,你燃烧的尸体会被扔给野狗。村里的孩子会用你的头颅来踢足球。 8 a1 w& a$ x! z0 v) f
(如你所见,我是一个伟大的团队成员)。 " ?: v, C+ d0 d1 r* X/ I2 [
然而,我确实知道,你可以在没有测试的情况下写出复杂的、相对没有错误的代码,因为我做到了。 ; ]# i1 R9 x/ k2 z
我确实知道,你可以写出复杂的、相对没有错误的代码,而不需要任何人查看你的代码,因为我做到了。 5 [. Y: R6 R* ~# I( g: y
如果没有人使用你的应用程序,那么谁会在乎它是否崩溃。 - ]) M2 o- A. |# W, K
如果很多人使用你的应用程序,它崩溃了,他们会告诉你,然后你会修复它。
F3 l. V8 x2 s* ?+ J% j 一夜成功需要十年时间
n& X1 g3 L1 E6 w SumatraPDF是比较受欢迎的。不是Facebook的流行,也不是DOOM的流行,但比大多数应用程序更流行。这是一个可敬的流行水平。 6 `& h2 d8 t O" n2 Q( T* e
这一切都从0.1版和涓涓细流的下载开始。在很多很多个月里,它一直是涓涓细流。 1 l9 G7 v) h5 ~5 A
我不确定这里是否有一个教训。
, M! h% s; q: W& \: d+ C 成功往往需要很长的时间。
) ^0 W( q: K" ~2 v; D! u; d Q 不幸的是,在这个阶段,它与(最终的)失败是无法区分的,所以如果你正在进行一个尚未成功的项目,并在争论是否应该继续或放弃时,这种智慧并不能帮助你。
2 y5 y- y% [9 Q- v1 H 钱
& Q% `2 x9 w) r* O# T9 k 开源不是一个好的商业模式。
2 c& h! F) R: H 如果你想赚钱,可以做其他事情:尝试销售软件、做咨询、建立SAAS并按月收费、抢劫银行。 2 @6 N$ J5 K" _" H* {
我确实做过赚钱的实验,也赚了一些。
_( z5 U2 J( X: _$ J 曾经有一段时间,AdSense会支付体面的CPM,所以我把AdSense广告放在网站上,赚了一些钱。我不再这样做了,因为费率确实急剧下降,而且不值得去烦扰别人。我的灵魂是有价格的,AdSense再也负担不起了。 " p$ V" P* T+ u4 k, _* G
现在我正在尝试使用Patreon和Paypal的捐款。每个月能赚到100多美元,但不会超过这个数字。
- H ^, ~) B9 }& c' b! }8 g 就像我说的:不要带着赚钱的目的去启动开源项目。 $ _9 ^3 u8 D' D# L) u
你很少能同时拥有:做你想做的事的自由和高薪,所以要选择对你更重要的东西。开放源代码给你自由,但不给你钱。
- h, _1 S& e8 [# ? 走向未来
- Z9 \% d# R' ~6 V9 j8 ` 我需要继续像水一样。 9 N3 T, z0 V8 t2 f4 |1 E: G; k3 I6 z
多年来,我一直抵制增加编辑功能。"我说:"它只是一个阅读器。但为什么不增加编辑功能呢?如果人们需要它,就给他们吧。 ; x" m6 ^" L! l3 F/ R
所有软件的未来都是作为一个网络应用。为什么不把SumatraPDF的精神带到网络上呢? & ~( Q' A& i$ E' W! a: O
这些只是我今天的一些想法。 * t# R) y. y$ {( Q
像水一样意味着5年后我将会有其他的想法,并以当时的情况为依据。 2 \" d# X1 D, V! V( g
本文由闻数起舞翻译自 https://blog.kowalczyk.info/article/2f72237a4230410a888acbfce3dc0864/lessons-learned-from-15-years-of-sumatrapdf-an-open-source-windows-app.html
; _6 E) ?& n1 @0 A: p
8 K$ l4 q! q& k8 ^4 g( I1 U1 R/ ^( h
# N0 e& O& g Q' x
1 e* o k# U# k1 r% P |