我应该如何组织我的源代码树?


89

我是一个独立的开发人员,主要从事Web项目(W / LAMP),有时还从事平均规模的C / C ++(非GUI)项目。

我经常在构建源代码树时遇到困难。实际上,通常,我不完成整个项目就不会倾倒整个树并重新排列三到四次,这确实需要大量的精力,而且最终结果似乎是一个折衷方案。

有时,我最终会过度分类来源-文件夹和子文件夹的树很长。在其他时候,我只是根据所有文件的最终用途将所有文件集中在一个特定的文件夹中,从而导致源文件中的文件“混乱”。

我想问:

  • 是否有任何原则/逻辑/最佳实践可以帮助我更好地构建源代码树?
  • 是否有任何图形/图表技术(例如:在数据流情况下为DFD)可以帮助我基于项目分析预先可视化源代码树?
  • 采用什么策略来构造与项目关联的多媒体文件树?

关于赏金:我非常感谢会员分享自己的做法的现有答案,但是,我希望鼓励会员提供更一般性和指导性的答案(或资源),以及更多的答复。


8
我现在没有时间写论文,而是“以事物的名称命名”,“将事物放在它们所属于的地方”,“将相似的事物保持彼此靠近”,最后,“不要担心” ,您希望有一个IDE可以帮助您在代码段之间快速导航。”
约翰·桑德斯

@John,我对IDE不太满意,根据操作系统,我通常会拉出Notepad ++或vi。这使事情变得更加困难。其余各点很有帮助,但又归结为做出棘手的决定,例如更接近应用程序逻辑或DAL或缓存管理或视图管理器的日志(错误日志等)功能。错误几乎完全相同。
check123 2011年

3
也许一旦您提出了这样的问题,就该让一些工具为您完成一些工作了。日志记录显然是跨功能的问题,已被应用程序的所有部分所使用(如果您使用的是需要记录日志的代码)。另一句话是“将代码置于使用它的代码之上”,因此日志记录应该放在顶部,也许放在\ utilities中。
约翰·桑德斯

@约翰:非常感谢。也许我应该开始寻找IDE。Eclipse似乎很有希望。
check123 2011年

1
@ check123“ ...将零件重新排列三到四次...”常见做法:“因此,管理问题不是是否要建立试点系统并将其丢弃。你会做到的。唯一的问题是,是否要提前计划建立一个一次性,或承诺在一次性交付给客户“ -弗雷德里克·布鲁克斯小,人月神话:散文软件工程
shawnhcorey

Answers:


25

源代码树布局应反映架构。因此,结构良好的体系结构可以导致结构良好的源代码树布局。我建议阅读POSA1层模式,尝试将您的体系结构调整为分层结构,然后命名每个结果层,并将其用作源层次结构的基础。以常见的三层体系结构为基准:

  • Presentation / webService(向我们的业务逻辑展示一个Web服务接口)
  • 逻辑/ *(此处插入业务逻辑模块)
  • storage / sql(此处为后端存储API-使用SQL接口存储到数据库)
  • util / *(实用程序代码-可用于所有其他层,但未引用util之外,请转到此处)

请注意,这些层并不直接包含代码,而是严格用于组织模块。

在模块中,我使用以下布局:

  • <module> (直接到达模块的路径;定义模块化接口)
  • <module>/impl/<implName> (模块化接口的特定实现)
  • <module>/doc (使用模块的文档)
  • <module>/tb (模块的单元测试代码)

其中<module>根据它所属的层位于在存储库中。


5
+1:源代码树的布局应反映体系结构-这是我一直忽略的显而易见的事情。
check123 2011年

您如何管理安全文件-只有授权用户才能在登录后访问的文件?
check123 2011年

@ check123我不确定我是否理解这个问题。我专注于源模块的组织,而不是支持项目的文件,并且源代码通常旨在供所有人使用。(有例外,我在所有代码上方使用dist /目录,并使用非标准的使用/修改限制。)
Aidan Cully

48

我真的不能给您很多有关Web项目的建议,但是这是我在编程项目中构造树的方式(主要是从C / C ++的角度):

  • /
    • src —我自己编写的源文件
    • ext —包含第三方库
      • libname-1.2.8
        • 包括 —标头
        • lib —编译的lib文件
        • Donwload.txt-包含下载所使用版本的链接
    • ide —我在这里存储项目文件
      • vc10 —我根据IDE安排项目文件
    • bin-编译后的exe文件在这里
    • build —编译器的生成文件
    • doc —任何类型的文档
    • 自述文件
    • 安装
    • 影印

一些注意事项:

  1. 如果我正在编写一个库(并且正在使用C / C ++),我将首先在两个名为“ include”和“ src”的文件夹中组织源文件,然后按模块进行组织。如果是应用程序,那么我将仅按模块组织它们(标题和源将放在同一文件夹中)。

  2. 我上面用斜体列出的文件和目录不会添加到代码存储库中。


什么之间的区别IDE建设
M. Dudley

3
ide就是我自己存储项目文件的地方。build包含由编译器生成的目标文件。不同的IDE可能使用相同的编译器,因此这就是为什么我将IDE项目文件与由编译器生成的目标文件分开的原因。
保罗

因此,build == obj(许多其他系统使用的术语)
gbjbaanb

@gbjbaanb是的,我猜是。没关系,因为该目录不会被推送到存储库。:)我称它为“ build”,因为那是我使用att称呼它的IDE(Visual Studio)。
保罗

如果您的exe需要一些dll才能运行该怎么办?您是否将所有dll文件复制到与exe相同的目录中?是否使用了一些生成后事件?
Wakan Tanka'9

14

尽管Maven标准目录布局特定于Java,但它也可以作为其他类型项目的良好基础。

这是基本结构(您可以将'java'目录替换为'php','cpp'等):

src/main/java       Application/Library sources 
src/main/resources  Application/Library resources  
src/main/filters    Resource filter files 
src/main/assembly   Assembly descriptors 
src/main/config     Configuration files 
src/main/webapp     Web application sources 
src/test/java       Test sources 
src/test/resources  Test resources 
src/test/filters    Test resource filter files 
src/site            Site 
LICENSE.txt         Project's license 
NOTICE.txt          Notices and attributions required by libraries
README.txt          Project's readme

该结构基本上分为“ src / main”和“ src / test”,然后按类型分组。


5

我不太了解约定,但是我所有的主要项目都是使用Symfony Framework完成的,我已经习惯了如下所示的树形结构:

根/

  • 应用
  • app_name
    • config(应用程序特定的配置文件)
    • lib(应用专用的php文件)
    • 模块(功能的模块化分布)
      • module_name
        • 模板(html)
        • 动作(PHP代码)
  • confing(项目配置文件)
  • lib(可以在Hole项目中使用的php代码)
  • 模型(代表项目信息的类)
    • 基础
  • 表格(处理表格的php文件,如果没有symfony,这可能很难实现)
    • 基本(基本表单类)
  • 网路
  • 的CSS
    • 图片
    • file.css
  • js
  • 日志(可能生成的日志文件)
  • 数据(数据特定信息,例如sql修补程序或其他)
  • sql
  • 插件(使用的库可以与项目的任何应用合并)

如果您有兴趣,请阅读有关此问题的symfony文档,以进一步查询(MVC和Symfony上的代码组织)。


CSS文件夹集中了吗?我的意思是(整个项目中的)所有CSS都在同一目录中?
check123 2011年

不一定,您可以将其划分,但是由于我的大多数项目往往只有2个应用程序(前端和后端),因此没有太多的CSS文件(插件始终具有自己的Web文件夹用于抽象)
guiman 2011年

5

理想情况下,组织具有单个存储库,该存储库的结构旨在增加工程与业务之间的联系并促进重用。

...\products\
...\products\productName\
...\products\productName\doc\

...\systems\
...\systems\systemName\
...\systems\systemName\doc\
...\systems\systemName\res\
...\systems\systemName\build\
...\systems\systemName\test\

...\library\
...\library\libraryName\
...\library\libraryName\doc\
...\library\libraryName\build\
...\library\libraryName\test\

...\devops\

产品展示

每个产品一个文件夹;帮助传达软件如何支持业务。

理想情况下,每个“产品”仅是一个配置文件,该文件指示要调用的系统以及如何配置它们。doc子文件夹可以包含顶级摘要\规格和任何促销材料等。

通过分离产品和系统,我们将重用潜力传达给了面向客户的业务部门,并打破了每个产品的孤岛。(这与针对相同问题的“产品线”方法形成对比)

系统

每个系统一个文件夹;帮助传达存储库内容的主要功能和机会/价值。

  1. 指定配置和部署环境的“配置管理”文件。
  2. 系统级测试配置(数量可能很大)。
  3. 顶级逻辑和功能;最繁重的工作是由库函数完成的。

图书馆

由各种系统调用的可重用组件。大多数开发活动都是围绕库的生产而不是系统来组织的,因此重用被“植入”开发过程中。

op

构建,持续集成和其他开发自动化功能。

结论

源代码树是文档的关键部分,它通过其专有技术来塑造企业关系的方法,结构和心理。

我对此问题的回答中更深入地介绍了此方法的驱动程序:https : //softwareengineering.stackexchange.com/questions/43733/who-organizes-your-matlab-code/59637#59637


注意:以与INCOSE系统工程手册中讨论的产品层次结构兼容的方式命名文件夹可能会很有用。
威廉·佩恩

3

我要为每个项目执行的操作类似于:

  • src-源文件,每个命名空间/包的文件夹,可轻松检索文件(甚至是C / C ++的头文件)
  • ext-对于外部/第三方库,添加外部(例如SVN存储库)很简单。在内部,每个库的文件夹(二进制文件和包含文件)
  • bin-对于内置的二进制文件,可以快速导出以进行发布
    • inc-用于C / C ++头文件(由IDE / makefile / etc复制)
  • 出来 -所有临时生成的文件(的.class,.OBJ等等),它可以(通过SVN例如)被忽略
  • doc-适用于任何文档,通常由Doxygen生成
  • res-通过在此处放置资源,可以分离文本源文件和程序使用的二进制资源。我内部确实没有特定的层次结构。
    • config-一些配置文件
    • 可绘制 -用于某些图片或图标

如果仅使用其中之一,则所有IDE的文件或makefile都直接保存在根目录中。


2

我做这样的事情。对于我在业余时间从事的跨平台游戏来说效果很好。不幸的是,在工作中,事情没有那么组织。

Output                      <-- Build outputs
Docs
External
   <libname>
      Include
      Lib
Data
<ProjectName>.xcodeproj
<ProjectName>VS2010
Source
Temp                        <-- Intermediate stuff from builds and other tools
Tools

2

对于我的团队,我们尝试在项目之间强制执行标准结构,以便在团队切换上下文时易于查找内容,并避免每次都要重新学习。并非所有项目都需要所有系统,因此我们从最小的集合开始。

/来源/组件/语言

/来源/组件/第三方/

/文档/要求

/文档/设计

/测试/自动化/单位

/测试/自动/工具名称

/测试/手册

这会导致某些重复,特别是在第3方代码和库下,但是至少我们永远不会忘记诸如“使用RogueWave编辑器是什么?”之类的答案。


1
大写的路径组件对我来说真的很愚蠢,毫无意义。为什么全部全部小写?对于人类来说,键入起来非常容易(尽管工具并不在乎,包括WIMP文件管理器),而且由于路径分隔符,其读取效果也同样好。最终赢得了我。
ulidtko 2015年

2

我喜欢此页面www.javapractices.com/topic/TopicAction.do?Id=205上提出的想法。基本上,建议将项目组织成功能(或模块,组件)。除了那里介绍的原因:

  1. 考虑到您正在使用的代码范围时,可以减少认知负荷,因为您可以保证正在使用的功能中的任何代码都是“功能私有”的。
  2. 当确保您仅修改给定功能的代码时,就会增加安全性。例如,除了正在使用的功能之外,您不会破坏其他任何功能。同样,这是由于“功能-私有”。
  3. 较少的认知负荷简单,因为对于给定的软件包,您可以看到的文件较少。我敢肯定,每个人都看过一个包含15个以上文件的软件包。

请注意,这是针对Java包(即名称空间)的。对于大型项目,出于相同的原因,我建议将项目分为代表业务功能的多个项目(如在多个Maven项目中)。对于Maven项目,我建议阅读

到目前为止,我所参与的项目并未遵循这些。原因有很多,但有几个原因:

  1. 对Java默认访问修饰符的误解(根据本书,大多数误解了访问修饰符)
  2. “ Argumentum ad populum”:流行的逐层打包文化(可能由原因1引起)

我认为,如果在项目开始时就没有认真对待项目源组织,那么就有错了机会来防止复杂性,正如建筑师亚历山大说的:

“正如任何设计师都会告诉您的那样,最重要的是设计过程的第一步。创建表单的前几个笔触就在其中承载着其余的命运。” -克里斯托弗·亚历山大

根据项目的规模和复杂性,错失的削减成本或投资回报的机会确实很大。(我有兴趣查看一项研究以了解确切数字)


2

我的建议是下载各种框架或引擎,并查看庞大的开发团队如何处理其文件夹布局。

组织文件的方式太多了,最好选择一个文件,并在任何给定的项目中坚持使用。遵守特定的约定,直到完成或改版,以避免错误和不必要的时间。

您可以为网络项目下载Laravel,Symphony或Codeigniter框架,以使即时文件夹布局有效。

因此,我将尝试传达任何开发通用的文件夹布局:

MVC(模型视图控制器)提供了良好的组织范例。

根源代码可以是src(C ++)或应用程序(Web开发)

如果文件结构对它所分组的类没有明确的目标,则肯定会引起混乱。它不仅可以组织代码,还可以支持自动加载器,类工厂,包装本地存储,远程存储和命名空间。

该文件夹结构是从Laravel Framework派生并简化的。我对这篇文章的偏好是复数命名,但是我在项目中使用单数词。


src / storage(模型/文件存储/ api / mysql / sql-lite / memcached / redis实现)

src / repositories(“存储实现”的包装,带有一些存储逻辑,一个公共接口和返回结果约定。)

src /服务| 逻辑| 实体 (应用程序业务逻辑)

src / controllers(用于Web开发以将服务器请求路由到您的服务)

src /模块| 系统(扩展框架常规功能的模块化系统。服务可以使用模块,反之则不能)

src / helpers(Helper或wrapper类,例如字符串操作。很多时候,第三方可能在libs | vendor上)

src / types(命名枚举)

公共| 建立 输出(Web或C ++)

config(安装文件。YAML在跨平台配置文件中变得越来越流行)

快取

日志

lang(en / es / ru / ...)

引导程序(启动框架和应用程序)

docs(以markdown格式.md编写的文档)

测试(单元测试)

数据库/迁移 (从头开始创建数据库结构)

数据库/种子(用虚拟数据填充数据库以进行测试)

库| 供应商(所有第三方软件。C++上的“ libs”,通常在php上的“ vendor”)

资产| 资源(图像/声音/脚本/ json /任何媒体)


1

使用面向对象的语言,您可以构建名称空间。用于分离应用程序各部分以避免耦合的逻辑故障是逻辑文件位置故障的主要来源。使用耦合作为打破名称空间的原因是开始http://en.wikipedia.org/wiki/Software_package_metrics的好地方。

其他人谈到建立与构建相关的项目,但是一旦您进入源代码本身,便是有意义的-只是使用您如何以逻辑方式将代码分解。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.