我享受建筑的多样性已有20年了,我想分享自己的想法





首先,我想对文章“我在C#中遭受可怕的体系结构困扰十年……发表评论,但我意识到了两点:



  1. 有太多想法要分享。
  2. 对于这样的体积,注释格式对于书写或阅读都是不方便的。
  3. 我已经阅读Habr很久了,有时我发表评论,但是我从未写过文章。
  4. 我不擅长编号列表。


免责声明:我一般不会批评@ pnovikov或他的想法。文字质量高(我觉得自己是一位经验丰富的编辑),我分享一些想法。有很多体系结构,但是没关系(是的,听起来像韩国电影的标题)。 



但是,让我们按顺序进行。首先,我对影响体系结构的观点,然后是关于“修复体系结构”的文章中有争议的观点。我还将告诉您什么对我们有效-也许对某人有用。



当然,这里所说的一切都是基于我的经验和认知偏见的个人见解。



关于我的意见



我经常做出建筑决策。一旦大,一次小。有时我会从头开始提出架构。好吧,好像是从头开始-可以肯定的是,所有事物都是在我们面前发明的,但是我们对某些事情一无所知,因此我们必须进行发明。并不是出于对自行车制造的热爱(也就是说,不仅出于对它的热爱),而且因为对于某些任务,还没有适合所有参数的现成解决方案。



我为什么认为完全不同的体系结构有权存在?有人可能会认为编程是一门艺术,而不是工艺,但我不会。我的观点:曾经是艺术,曾经是手工艺。不是那个最主要的是任务是不同的。和人。要澄清的是,任务是业务需求。



如果有一天我的任务变得相同,我会写或要求某人写一个可以代替我的神经网络(或者脚本就足够了)。而且我会做些不那么惨淡的事情。直到我,而且我希望,您的个人启示还没有到来之前,让我们考虑一下任务和其他条件如何影响各种体系结构。TL&DR; 多变的



性能与可扩展性



这也许是更改体系结构的最正确的理由。当然,除非更容易使旧体系结构适应新要求。但是在这里很难简单地讲出有用的东西。



定时



假设术语(我两次确保用“ o”写过)非常严格。这样我们就没有时间选择,更不用说构架了-熟悉的工具进行挖掘。但是有一个细微差别-有时只有通过应用(也许是发明)根本上新的东西,复杂的项目才能按时完成。有人可能会说邀请顾客去澡堂是一种古老的技术,但是现在我在谈论建筑...



当时机合适时-这常常被证明是一种自相矛盾的情况-似乎您可以提出一些新的想法,但是为什么呢?的确,许多人成功地屈服于承担另一个更具挑战性的项目并将情况减少到以前的情况的诱惑。



在我的实践中,时间很少会导致建筑革命,但是它确实发生了。那太好了。



发展速度和质量



确实如此-团队(或管理层中的某人)注意到开发速度变慢,或者在迭代过程中运行了许多错误。通常,这归咎于“错误的体系结构”。有时-当之无愧。频率更高-就像最方便的被告一样(尤其是在团队没有她的“父母”的情况下)。



原则上,在某些情况下,这全都取决于时间因素。在其他方面-为了可维护性,稍后再讨论。



可维护性



模棱两可的话题。因为一切都是非常主观的,并且在很大程度上取决于什么。例如-来自团队,编程语言,公司中的流程以及针对不同客户的适应次数。让我们谈谈最后一个因素,在我看来,这是最有趣的。



现在,您已经创建了一个自定义项目。成功,按时,按预算,客户对一切都感到满意。我也有这个现在,您看看自己的使用和思考方式-这就是-金矿!我们现在正在使用所有这些开发,我们将快速创建一个B2B产品,并且……起初一切都很好。该产品被制造出来,卖了几次。雇用了更多的供应商和开发人员(“需要更多的黄金”)。客户满意,他们支付支持费用,发生新的销售...



然后,一位顾客用人类的声音说:“我会以完全不同的方式来做这件事-它要花多少钱?”好吧,只要想一想-如果用不同的代码(例如,没有时间拧入DI)插入一些代码,那会发生什么不好的事情?



第一次,真的没有什么不好的事情发生。在这种情况下,我什至不建议您采取一些特别措施。过早使体系结构复杂化类似于过早的优化。但是,当它第二次和第三次发生时,这就是记住诸如DI,“策略”模式,Feature Toggle以及其他类似内容之类的原因。而且,有一段时间,它会有所帮助。



然后是一天,当您查看特定测试台的项目设置(只有几百个选项)时,请记住如何计算组合数量并思考-您的母亲,如何进行测试?显然,在理想的世界中这很简单-毕竟,每个功能的设计和实现都不会影响其他功能,如果确实如此,那么所有这些功能都是提供的,并且一般而言,我们的开发人员从未犯过错误。



当然,我加粗了颜色-您可以突出显示实际客户使用的某些功能集,编写更多测试(如何和哪种测试是另一次对话的主题),并稍微简化任务。但是请考虑一下-每个主要版本都需要针对所有客户进行测试。让我提醒您,这不是B2C,您可以说“为5%的用户推出一项功能并收集反馈”-对于B2B,您可以开始从法院收集反馈...



解决方案?例如,将产品分为具有单独生命周期的模块(不要忘记测试它们的交互作用)。尽管这会使开发复杂化,但这将降低维护的复杂性。现在,我不是在谈论“独石vs.微服务”-在一个整体中,您也可以安排类似的服务(尽管更复杂,我认为)。



而且,从务实的角度,请注意,在每个阶段,我们都有一个良好的体系结构。



这是为了什么?



我不想通过列出架构更改的其他原因而使您(和我自己)感到厌倦。现在让我们同意,架构会随着时间而变化,这取决于许多因素。这意味着:解决“好,所有问题”理想架构不存在。



如果我还没有说服您,请查看各种编程语言和框架(只是不在前端-不要打开这个主题)。如果有人说这很不好,我建议进行一个思想实验-想象一个有一种特定编程语言的世界。有一个重要条件-您不喜欢它。例如,因为您从未使用过它,并且也从未打算这样做。



而且,我承认,还有另一个很好的理由-想出一些新东西,优化一些参数,妥协一些-真是太好了。现在我们所有人(对吗?)同意建筑的多样性还可以...



关于“修复体系结构”的文章的讨论



IoC呢?



关于IoC,我同意在军队中占有一席之地,而模块是通用的。但是剩下的就是这些……



当然,如果您听一些辩护者的“干净代码”,那么您就可以编写大量的服务代码,每个服务将平均有一个半方法,而在该方法中将有两个半行。但为什么?老实说,您绝对希望遵循能够帮助您在遥远的将来应对不大可能出现的问题的原则,但是在数十个文件中抹上甚至是简单的逻辑呢?还是足以让您现在编写体面的代码? 



顺便说一下,现在我正在开发一个肯定会在不同产品中使用的模块,并且很可能会积极地“调整”。所以我尽量不要“浅”。不还清。尽管在其中我比平常更频繁地使用接口的唯一实现。



因此,如果我们有模块而又不是“小资”,那么IoC性能问题或不受支持的“ IoC配置脚印”来自何处?我还没碰到。 



但是,我将澄清我们的工作条件:



  • 我们的模块不是“几乎任何IoC框架都提供的”模块,而是“直接模块”-通过API相互进行远程通信(有时,出于性能原因,您可以将它们置于一个过程中,但是工作方案不会改变)。

  • IoC的使用尽可能简单,并且尽可能简单-依赖关系被卡在构造函数的参数中。

  • 是的,我们现在有了微服务架构,但是在这里我们尽量不要太小。 



提示:接口可以与类保存在同一文件中-方便(当然,如果您使用的是普通IDE,而不是记事本)。接口(或对它们的注释)增长时,我会设置例外。当然,这就是所有的味道。



ORM怎么了?为什么要直接访问数据库? 



是的,我本人会说出什么问题了-其中许多与SQL相距太远。但不是所有的。因此,与其“忍受O / RM删除3000个对象”或想出另一个对象,不如找到一个适合您的对象。



提示:尝试LINQ to DB平衡良好,有多行更新/删除方法。请小心-会上瘾。是的,没有EF功能,但概念稍有不同,但我更喜欢EF。



顺便说一句,这是我们同胞的发展,这很高兴。伊戈尔·特卡切夫(Igor Tkachev)-尊敬(我在哈布雷(Habré)上找不到)。



UPD: RouR注释中指出,EF Core有一个扩展,允许批量操作。无论如何我都不会放弃LINQ,因为它很好



数据库测试出了什么问题?



是的,它们将比内存中的数据慢。致命吗?不,当然不。如何解决这个问题呢?这是两个最好同时使用的食谱。



配方编号1。您选择了一个乐于助人的开发人员,喜欢做各种有趣的事情,并与他讨论如何漂亮地解决此问题。我很幸运,因为解决问题的速度比出现的速度快(我什至不记得我们是否在讨论它)。怎么样?为ORM(一天之内)建立了一个测试工厂,该工厂将访问的主要子集替换为访问数组。



非常适合简单的单元测试。另一种选择是使用SQLite或类似的东西代替“大型”数据库。

评论者 : . -, , ORM, , SQL . -, , , , , .. . .



配方编号2。我更喜欢在真实数据库上测试业务场景。并且,如果该项目宣布能够支持多个DBMS,则将对多个DBMS进行测试。为什么?这很简单。the,在声明“我不想测试数据库服务器”中,有一些概念可以替代。您知道,我不是在测试连接是否有效或排序依据。



我正在测试使用DB的代码。而且,即使知道同一DBMS的不同版本也可以在同一查询(证明上产生不同的结果,所以我想检查该代码将与之一起使用的那些数据库上的主要脚本。



通常对我来说,这样的测试如下:



  • 对于一组测试(Fixture),它是根据数据库元数据从头开始生成的。如有必要,请填写必要的参考书。

  • 每个脚本在通过过程中都会自己添加必要的数据(用户也要这样做)。在性能测试中并非如此,但这是一个完全不同的故事...

  • 每次测试后,多余的数据(参考书除外)将被删除。



建议:如果长时间客观地为您执行了这样的测试(不是因为现在是时候优化对数据库的查询),请构建一个可以减少运行频率的构建(测试类别或一个单独的项目可以帮助您)。否则,开发人员将不希望自己运行其余部分-快速测试。



交易和电子邮件



我将添加一个故事“由于某种原因,数据库中的事务失败,并且电子邮件消失了”。当事务等待不可用的邮件服务器时,由于某些通知,然后用户将其发送到购物篮而没有阅读的通知,整个系统将变得很有趣。



没错,我一直相信,只有六月在野外发送信件在没有审查的情况下。在我们的团队中,他们为这场大战打败了(到目前为止是虚拟的)。



结果



总的来说,如果@pnovikov没有计划借助唯一真正建筑意识形态征服世界,那么他没有发现任何其他值得一提的差异。当然,对于某些任务,他所说的原则是合适的。我很高兴阅读以下文章和评论,也许我会为自己找到一些有用的想法。



我几乎不会使用建议的框架。原因很简单-我们已经有一个理想的体系结构。...



PS如果您希望讨论评论中的某些内容,我将很高兴参加。



All Articles