<audio id="audio" title="12丨组织好代码文件，要有“用户思维”" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/43/75/43a29ce4d9aac7453a1feb6c1397e275.mp3"></audio>

上一讲中，我们讲了如何组织代码段，今天我来讲下，如何组织代码文件。

最开始接触一个项目代码时，我们最渴望的，就是快速揭开项目的面纱。这个项目是干什么的？是怎么做的？该怎么使用？

有很多这样的问题，排着队等我们处理。我们需要从一个点开始，先撕破一点点皮，然后，像剥洋葱一样，一层一层地阅读，一层一层地了解。

刚拿到一个项目的代码时，你最想找哪一个文件？面对大量的文件，该从哪里入手？创建一个项目时，各式各样的文件该怎么规整？

如果一个项目很小，只有三五个文件，我们不用担心上述的问题。

但事实上，一个典型的软件项目，拥有上百个文件是寻常的事情。如果这些文件组织混乱，就会让整个项目乱糟糟的，我们很难入手去查找、阅读和测试。

其实文件的组织是一个简单的事情，但这些简单的事情如果不能做得清晰、明了，就会变成一个效率的黑洞。

文件的组织要层次分明、易于检索、一目了然。要做到这一点，我们可以从用户思考问题的逻辑入手。

## 逻辑之一：软件是干什么的？

无论我们开始一个软件项目，还是阅读一个软件的代码，第一个遇到的问题就是，这个软件是干什么的？

可以回答这个问题的文件叫做README，它的命名全部使用大写字母。需要被放在一个软件工程的根目录里，方便人或者机器第一时间找到，从而轻而易举地找到并进行阅读。

“软件要用来干什么？”是一个软件工程的启动问题。

一个软件项目开始时，这个问题的答案可以不是很丰满，但是，最基本的思想一定要有。随着软件的研发进程，它的描述可以越来越清晰。软件成型之前，这个问题必须干脆地解决掉，得到明确的答案。

这个问题的描述，要记录在代码的工程里。可以让代码的阅读者轻而易举地找到并阅读。

由于机器的参与，尤其是在线代码管理服务（比如GitHub、Maven）的广泛使用，README的名字和位置也就慢慢地形成了共识。

## 逻辑之二：软件可以拿来用吗？

如果我们看到了README，想使用这个软件，那么紧接着的问题就是，这个软件我们可以使用吗？

所有的软件，都有归属，都受版权的保护。谁拥有这个软件的版权？这是我们需要关注的一个问题。

有时候，一个软件包含很多贡献者，不同的贡献者有不同的版权诉求。软件的不同部分，就有不同的版权。

这种情况下，**版权描述一般放在每一个源文件的头部**。不同的源文件可以有不同的版权，同一个源文件也可以有一个以上的版权所有者。

如果版权来源只有一个，而且源文件头部没有版权描述，我们就需要把版权描述放到最显眼的地方。**这个地方就是软件工程的根目录，命名为COPYRIGHT，全部使用大写字母**。

没有版权描述的软件，并不是没有版权保护。如果一个软件没有版权描述或者版权描述不清晰，使用起来有很多法律风险。如果这个软件依赖外部的版权，那么问题就会变得更为复杂。

有了版权保护，不代表我们就不能使用这个软件了。我们能不能使用、怎么使用，是由软件的许可证确定的。

许可证文件是LICENSE，全部使用大写字母，放在软件工程项目的根目录下。

当使用软件的时候，不能超越许可证约定的范围。 一个没有许可证的软件，我们是不能使用的，因为不知道许可的范围，也不知道应承担的义务。同样，如果一个软件的许可证不清晰，或者我们不了解，那么使用起来也会有很多法律问题。

## 逻辑之三：软件是怎么实现的？

作为程序员，代码是我们看软件世界的语言。我们关心的下一个问题就是，这个软件是怎么实现的？

代码的位置在现在的软件工程里有了一定的共识。通常来说，源代码存放在根目录下的src目录下。

当看到src目录的时候，我们就可以确认，这里面是源代码文件。当我们要查找源代码的时候，也是在软件工程文件里查找src目录。我不建议在这里搞创新，不要使用其他的名字或者位置。

但源代码并不能一股脑地堆在src这一个目录里。src目录下面可以有很多子目录。一般来说，稍具规模、相对正规的软件，都需要有命名空间的区隔。使用命名空间的区隔至少有三个好处：

<li>
可以把一个组织的代码和另外一个组织的代码区隔开；
</li>
<li>
可以把一个项目的代码和另外一个项目的代码区隔开；
</li>
<li>
可以把一个模块的代码和另外一个模块的代码区隔开。
</li>

每一个命名空间的节点，都要对应一个文件目录。比如，我们常用的java.lang这个命名空间，就要相应地使用“java/lang”这两级目录。

如果软件项目把所有的源代码文件不加分别地放在同一个目录下，说明软件的开发人员并没有厘清代码之间的逻辑关系。纠缠在一起的代码越多，代码越难以维护，代码的安全越难以保证。

## 逻辑之四：软件该怎么测试？

如果要使用或者发布一个软件，最值得关注的还有软件的质量。软件的质量，首先要通过软件测试这一关。那么软件该如何测试呢？ 这是我们要面对的另一个问题。

有很多传统的软件项目，测试代码和功能代码是放在同一个目录下的。如果一个项目比较小，那么这样做也许没什么大问题。一旦软件工程变得复杂，这样做就会让项目变得难以管理，尤其是在测试人员和开发人员分离的情况下。

让测试人员看着实现代码写测试，会误导测试的用例选择和测试效果；让开发人员看着测试代码改实现，也会影响开发的质量和效率。

既然要分工，不同的代码就要区隔开来。

如果开发和测试是一个人，或者是同一个小组成员，是不是就可以混在一起了呢？ 当然不是，因为看代码的人依然可能是分工的。区隔实现和测试，可以尽可能照顾到每个工程师，方便他们工作。

幸运的是，现在的很多软件项目，大都采用了分离的组织方式。通常来说，源代码要存放在根目录下的test目录下。

仅仅放置在对应的目录下还不够，测试文件本身还有一个需要注意的地方，一个测试文件，最好执行一个独立的任务。如果测试出错误，我们就能够快速定位错误。这也要求测试的目标要小，测试的结果要清晰，测试的组织要照应功能代码的组织。

比如说，对java.io测试的文件，要放在java/io测试目录下；对java.util测试的文件，要放在java/util目录下。这种互相照应的组织方式，从目录名就可以看出测试的范围。这样既可以快速从功能代码找到测试代码，也可以快速地从测试代码找到功能代码。

## 软件该怎么使用？

使用软件工程项目文件的，不仅仅只有程序员，还有软件的用户。

要是只能通过阅读软件代码来揣测软件该怎么使用，这样既没有效率，也容易犯错，更偏离了软件设计者的初衷。

一个好的软件，要尽可能降低使用门槛。编写使用指南和代码示例是两个常用的办法。一份好的用户文档，应该让软件的用户快速入门，然后再逐步深入地了解整个软件的使用细节，以及潜在的问题。

软件的文档，需要随着软件的变更不断升级维护。有很多项目会把文档和代码分开管理。

但实际上，这样做有一些缺陷，它会让文档变得难以维护。

我们经常看到很多文档和软件脱节的软件，很大一部分是由于项目组织和管理方面的问题导致的。如果代码的变更，也需要相应地变更文档，那么文档和代码统一管理，是一个更高效的组织方式。

如果你留意，就会注意到现在的很多项目，在根目录下，有一个名字为docs或者doc的目录。 这个目录就是存放软件文档的。

作为程序员，我们不仅要熟悉源代码，还要熟悉文档。当需要更直观的用户指南或者代码示例时，就要写作这样的软件文档。对于每一行的代码变更，我们都要问，需不需要文档变更？如果代码和文档一致的话，就会节省我们大量的维护时间和维护成本。

下面的例子，是一个常见的软件组织形式，也是我们对上述讨论的小结。

```
Project directory layout:
   src/
      java/
          lang/
          io/
      javax/
          net/
              ssl/
   test/
      javax/
          net/
              ssl/
   doc/
   make/
   README
   COPYRIGHT
   LICENSE  

```

## 小结

我们的日常软件开发工作，有很多都依赖于集成开发环境（IDE）。主流的IDE有缺省的文件组织形式。一般情况下，我们可以使用缺省的组织形式，然后添加进缺失的内容。

也有很多软件开发，不依赖于IDE。这就需要我们自己规划好文件的组织原则和基本形式。不同的语言，不同的项目，文件的组织方式差别可能很大。

如果你需要自己制定组织形式，我建议参考一些成功项目的组织方式。比如，如果你要做一个中间件，为客户提供类库，就可以参考OpenJDK的文件组织方式。

如果没有什么现成的项目可以参考借鉴的，请记住以下两点：

<li>
文件的组织要一目了然，越直观，越有效率；
</li>
<li>
可维护性要优先考虑。这要求文件组织要层次分明，合理区隔、照应、使用不同的空间。
</li>

## 一起来动手

由于项目的多样性，项目文件组织的具体形式有很多差异。借这个机会，我也想学习一下大家的项目文件组织经验。你做的项目，是怎么组织文件的？为什么选择这种组织的形式？你最欣赏的这种形式的哪几点？你阅读一个项目代码时，是怎么一步一步深入进去的？欢迎你把你的经验公布在讨论区，我们一起来学习，一起进步。

欢迎你把这篇文章分享给你的朋友或者同事，一起来探讨吧！


