31

我认为我已经非常擅长编程的基础知识(适用于各种语言)。我可以写一行代码。我可以写一个很好的方法。我可以写一堂课。我可以写一组很好的类。我可以编写好的中小型应用程序。

然而,我不知道如何构建一个好的大型应用程序。特别是在涉及多种技术并且随着时间的推移可能会涉及更多技术的情况下。假设一个项目有一个大型 Web 前端,一个连接到其他集成后端的大型服务器后端,最后是一个庞大而复杂的数据库。哦,我已经参与了其中的一些应用程序,我确信我可以构建一个。但是,我不太确定它是否可以称为“好”。

因此,我的问题是参考一本书或其他好的阅读资源,在那里我可以学习如何为一般的大型项目分发和组织代码和数据。例如,我是想非常严格地分层,还是想将其封装成独立的单元?我是想尝试将大部分逻辑保留在同一个池中,还是应该在添加我要添加的任何功能时按照最合乎逻辑的方式进行分发?

我已经看过很多关于这些问题的一般原则(例如,没有意大利面条代码,肉丸代码......)并阅读了一些讨论这个问题的优秀文章,但我从未遇到过可以引导我获得具体实践知识的来源。我意识到这个问题的难度,所以我很高兴听到其他人发现有助于他们寻求此类知识的阅读材料。

一如既往,感谢您的回复。

****鉴于“好”代码的定义存在争议,在这种情况下,“好”这个词不会被定义(它意味着你认为它应该意味着什么)。

4

12 回答 12

31

作为程序员,我们喜欢相信自己是聪明人,所以很难承认某件事太大太复杂,甚至无法一次考虑。但对于大型软件项目来说确实如此,而且你越早承认自己的大脑能力有限并开始想出简化问题的方法,你就会变得更好。

要意识到的另一件主要事情是您将花费大部分时间来更改现有代码。构建初始代码库只是蜜月期——您需要在设计代码时牢记这样的想法,6 个月后,您将坐在它面前试图解决一些问题,却不知道这个特定模块是如何工作的,甚至虽然你自己写的。

所以,我们能做些什么?

最小化代码中不相关部分之间的耦合。随着时间的推移,代码会以你无法预料的方式发生变化——与不熟悉的产品集成时会出现惊人的问题、需求变化——而这些会导致变化的连锁反应。如果您已经建立了稳定的接口并对其进行了编码,则可以在实现中进行所需的任何更改,而这些更改不会影响使用该接口的代码。您需要花费时间和精力来开发经得起时间考验的界面——如果界面也需要更改,您就回到原点。

建立可用于回归测试的自动化测试。是的,前期工作量很大。但是,当您可以进行更改、运行测试并确定它仍然可以工作时,它会在未来得到回报,而无需担心如果您将最新的更改提交到源代码控制,是否一切都会失败。

放下棘手的事情。 我时不时地看到一些巧妙的 C++ 模板技巧并想,“哇!这正是我的代码所需要的!” 但事实是,代码可读性和易理解性的降低通常根本不值得增加通用性。如果你像我一样天生倾向于尝试以尽可能普遍的方式解决每个问题,那么你需要学会克制它,直到你真正遇到对通用解决方案的需求。如果出现这种需要,您可能必须重写一些代码——这没什么大不了的。

于 2009-01-23T19:47:04.993 回答
18

借自 tvanfosson:

从一个小应用程序开始,每次有人想要添加新功能时说“是”。

于 2009-01-23T17:41:46.977 回答
11

这是我们用来指导我们的编码标准和方法的一本书:

替代文字 大规模 C++ 软件设计

我正在开发的这个程序自从第一次在众所周知的餐巾纸上拟定以来,已经开发了将近 10 年。该项目今天仍然很强劲。它并不完美,循环依赖仍然存在问题,一些类接口不是很干净,但大多数类都不是这样,程序可以正常工作,我们的用户很满意。

正如许多其他人之前所做的那样,我还推荐Steve McConnell 的Code CompleteSoftware Estimation。我特别喜欢他关于“增长”软件而不是构建或构建的比喻。这种查看软件的方式更适合具有较长生命周期的东西。

于 2009-01-23T17:43:00.050 回答
5

正如我在其他地方提到的,大型应用程序不仅更大,而且不同。如此之多,以至于我们谈到了小型大型编程。当您进行大型编程时,问题的性质及其解决方案会发生重大的质变。这条线非常模糊,有许多具体问题会迫使你越过这条线。

其中一些问题包括:

  • 大小(例如一个根本不适合单个硬盘驱动器的数据库)
  • 复杂性(从多合一应用程序到多个子系统)
  • 并发(从零到数千/百万同时用户)
  • 可用性(从 9% 的正常运行时间到 99.999% 的正常运行时间)
  • 可靠性(从日常故障到几年的 MTBF)
  • 速度(从几小时到几毫秒的响应时间)
  • 产品化(从您的宠物项目到可销售的商品)
  • 等等

如何处理这一切?尽可能地学习和使用每一种有价值的技术,并学会评估哪些是真正有价值的——这需要一段时间,而且没有快速的答案。

但是,有一种简单、明显且一刀切的技术:分而治之。隔离每个主要功能、每个子系统、每个外部依赖项,以便您的主系统仅在其外部边缘接触它们。当你可以在很短的时间内通过简单地调整一个精简的界面来改变每一个,那么你已经完成了一些事情。这将带你走很长的路。

最良好的祝愿。

于 2009-01-23T19:50:17.297 回答
4
  1. 决定哪些特征是最重要的;忘记其余的
  2. 决定其中哪些功能最重要,而忘记其余的
  3. 实施它们(应该需要几个星期,否则重复步骤 1 和 2)
  4. 发射
  5. 查看哪些功能有效,哪些无效,哪些缺失
  6. 返回步骤 1
于 2009-01-23T17:43:19.190 回答
4

大型应用程序不是一夜之间创建的。企业应用程序从小块开始,然后将它们组合在一起。如果您设计的应用程序是一种可以扩展的方式,那么与所有周边因素(如数据库、第三方工具等)集成会更容易。如果您访问infoq.com,您会发现很多很棒的案例有关扩展和架构的研究和材料,例如 Myspace、Amazon 和许多其他公司。除了经验之外,没有什么可以引导您开发出色的大型应用程序。

于 2009-01-23T17:49:54.370 回答
4

渐进式地使用测试驱动设计

于 2009-01-23T18:10:55.093 回答
3

使用设计模式使其可扩展,这意味着您无需更改所有内容即可插入新功能。

决定你需要什么来构建和构建它。

将其分解为分别执行任务的模块。

计划计划计划计划,在开始之前知道您正在构建什么,然后构建它而不是其他任何东西。

只写你需要的功能,不要添加你认为可能有用的东西,但是......让它足够灵活,以便能够添加你可能需要添加的东西。

于 2009-01-23T17:48:37.727 回答
3

注意到有多少评论说盲迭代是唯一的方法,这真的很有趣。

迭代很关键(我是一个超级粉丝),但也有人可以计划出大型项目——只是我们中很少有人遇到过这样的项目。

把它想象成我们所有人都在我们的车道上打篮球。我们很好,我们可以得到大多数篮子,实际上在公园里玩得很开心。

然而,仅仅因为我们从未见过职业球员,并不意味着他们不存在,也不能整天在球场上踢我们的每一个屁股。

唯一的问题是没有专业的编程游戏——如果有的话,我们可能会多看到一些。

于 2009-01-23T20:42:54.397 回答
0

好吧,你可以看看理性统一的过程。检查基本部分,选择一些您认为需要的工件。列出您需要的所有功能并将它们组织在需求列表中。还要仔细规划您的软件架构,这样您以后就不必更改它。使用其中的一些技巧,开发大型应用程序会相对容易一些。

于 2009-01-23T17:49:25.060 回答
0

作为负责大型应用程序的人,我会说

  • 使用非侵入性框架,例如 Spring
  • 减少耦合
  • 尽可能创建不可变对象——它们是线程友好的
  • 接受您的应用程序可能需要拆分为单独的进程以更好地扩展并为此进行计划。
  • 构建一个可靠的工具集并学习这些工具。

不要恐慌

于 2009-01-23T23:44:25.233 回答
-1

关于产品和供应商锁定的一些想法:

  • 尝试尽可能独立于供应商和平台。这将防止您必须使用新产品/平台/框架等从头开始重新实现所有内容。
  • 这实际上意味着使用 Java SE + Java EE + 和开源 RDBMS,如由 Java EE 的 JPA 封装的 PostgreSQL。不要使用额外的库、框架(spring、hibernate、...)等。这样您可以随时切换产品和供应商。
  • 我认为您只能使用 Java 获得这种级别的产品和平台独立性。即使你使用了 OSS 库和框架,如果你发现实现不适合你的需求,你必须重做所有事情,你会后悔使用它们。
  • 您可以使用Java Application Verification Kit检查代码的产品独立性。
  • 事先花一些时间在架构上,但也要在整个实施过程中重新设计架构。一本好书(不幸的是只有德语)是 Adam Bien 的“Java EE 5 Architekturen”。

@j_random_hacker:实际上,不——我仍然认为我的第一点是在大型应用程序中使用 java 的论点,而不是反对它。每种语言都是一种语言。因此,当然,您总是必须对一门语言做出承诺。

  • 但是 Java SE & EE 包括语言、编译器、虚拟机以及所有必要的库/框架。但是整个 Java SE/EE 平台有不同的实现:来自 Sun、Apache、IBM、HP、Oracle、BEA 的 Java SE (JDK)。Sun、Apache、Red Hat、IBM、Oracle 和其他公司的 Java EE(应用服务器)。带有 C# 的 .Net 只有一个实现(来自 Microsoft 和一个称为 Mono 的有点相似的语言/平台的实现)。
  • 我认为 PHP 也只有一种实现。有很多不同的 C++ 编译器。但是它们都实现了稍微不同的 C++ 语言,并且它们没有与共享相同 API 的库捆绑在一起。选择 Java,我知道我可以在六种 Java SE 实现和六种 Java EE 应用服务器之间进行选择来运行该软件,而这些软件又可以在 Linux、Solaris、FreeBSD、HP-UX、IBM z/OS、Windows 上运行, Mac OS X 和各种各样的硬件平台。所以我不必担心,如果我在开发后期甚至生产中发现一个非常糟糕的实施问题 - 我会离开 Sun 并且永远不会回头。(这就是我推荐 Java Application Verification Kit 的原因。通过检查您的源代码,您可以确定 Sun、IBM、甲骨文或任何其他邪恶公司并没有将他们的任何专有东西作为依赖项偷偷带入您的源代码中,这可能会将您绑定到该公司。你像鸟一样自由。)
  • 你不能用 PHP 或 Ruby 做到这一点。使用这些语言,如果没有其他人这样做,您将不得不自己修补实现问题,因为在 PHP 或 Ruby 中花费数月的错误修补时间仍然比重写完整的应用程序要少。
  • Sun 已开源:Java SE(完整的 JDK)和 Java EE(Glassfish 应用服务器)。唯一不是“开源”的就是有一个绑定语言规范,由 sun 主导,并得到其他人的大量贡献。这就是为什么您可以从 sun 获取 Java 实现、修改 Java 语言并重新分发该源代码和二进制文件,但如果这不符合语言规范(Sun 保护 Java 商标仅实际应用于事物java)。起初这可能听起来“邪恶”,但它实际上确保存在“Java”之类的东西:您可以编写一个 java 应用程序并在任何 java 实现上运行它。
  • 如果您无法忍受任何 Sun 微系统,但想要一个开源 Java,那么您可以只使用Apache Harmony (Java SE) 和Apache Geronimo (Java EE)。
于 2009-01-26T11:41:48.270 回答