触摸屏左右屏幕外向内滑动
没有前端时,没有理由拥有后端。 当没有人使用API时,没有理由使用它。 没有其他类(或框架)可以使用时,没有理由拥有一个类。 没有人调用时,没有理由拥有一种方法。
仅应满足用户,外部系统或另一段代码的外部需求来编写代码。
由内而外的发展
许多开发人员在定义领域模型在定义外部世界将如何使用之前都专注于实现领域模型。 用户(通过用户界面)或其他系统(通过API,消息等)与系统进行交互的方式被视为较少关注的问题。 二十年前,我在大学里学到了做业务分析和首先专注于领域建模的知识。 这也是我在职业生涯的前半年与前辈们学到的东西。 由于相信前端的更改比业务规则更改的频率更高,因此我们选择首先创建一个完全解耦且健壮的后端系统,而将UI留到后期。 我称这种方法为由内而外的开发 。
优点
让我们看一下由内而外开发的一些最重要的优点:
及早确认业务需求
与业务需求有关的一些问题只有在我们开始编写代码时才会出现。 从域模型开始编码使我们能够直接专注于业务规则,从而使我们有机会发现业务不一致性,更详细地阐明需求并验证假设。 快速获得有关系统重要区域的反馈是一种缓解风险的策略。
风险缓解
调查和预防工作,使我们能够在编写任何脚手架代码之前发现可能会大大改变我们对项目范围和成本的理解的问题。 在构建过多的代码之前识别和缓解风险可以最大程度地减少返工,并有助于保持项目的健康。
最有价值的东西
开发人员应该首先处理最有价值的任务,并且普遍认为领域模型可以说是最有价值的软件。 与此相反的说法是,如果任何人都不使用该软件,则该软件没有商业价值。 从这个角度来看,领域模型仅在实现并在生产中使用完整功能时才有价值。
易变的用户界面从左到右
众所周知,用户界面(UI)易变,而一旦定义,业务规则的变化往往会少得多。 从业务规则开始,后端开发人员可以在前端开发人员迭代UI设计的同时取得一些进步。
缺点
让我们看一下这种方法的一些缺点:
浪费精力
如果没有外界的明确定义和具体需求(作为用户界面或API交付机制)的指导,我们就可以轻松构建不需要的东西。 当我们最终定义了交付机制并尝试将其插入时,我们很快意识到后端并不能完全满足交付机制的所有需求。 在这一点上,我们需要编写一些连接双方的管道代码,或者更改后端,或者更糟的是,破坏交付机制定义的可用性,以便我们可以按原样在后端中重用代码。
投机发展
当在定义系统使用方式之前,先关注系统内部时,我们的想像力会大打折扣。 我们开始考虑所有不同的可能性以及我们的代码应该做的事情。 我们试图使我们的领域模型尽可能健壮和通用。 我们推测得越多,偶然的复杂性就越多。
反馈延迟
使用我们的API的用户或外部系统不在乎我们的后端。 如果我们可以提供一些东西供他们使用或访问,我们只能从他们那里获得反馈。 不管我们在后端做什么。 如果用户旅程(通过用户界面)或API不适合,则我们的后端没有价值。 如果前端或API是在域模型(后端)之后完成的,则只有在完成整个功能之后,我们才会获得反馈,这已经太迟了。
粗粒度开发
增量交付软件的一种好方法是将我们的功能切成垂直的薄片。 当我们从领域模型开始时,这变得非常困难,因为我们没有编写代码来满足特定的外部需求。 在构建领域模型时,我们还没有外部需求来指导垂直切片。
在找不到合适的垂直薄切片的情况下,我们需要等待整个功能完成才能获得反馈并进行部署。 当将交付机制视为事后思考时(仅在实现域模型之后才决定),也很难预测何时完成某项功能。
送达机制
首先关注后端的另一个危险是,在完成后端后,开发人员通常没有时间或不太热衷于在前端工作。 他们最终急于实现前端实现,从而导致两个主要问题:a)糟糕的用户体验,b)与后端相比质量标准较低,从而导致交付机制混乱且难以维护。
协作受损
未定义API时,移动,前端和后端团队不应并行工作。 对于跨职能团队,移动,前端和后端开发人员在同一团队中也是如此。 1一旦移动和前端开发人员尝试集成他们的代码,让后端开发人员定义API会引起很多麻烦和返工。
更深入地了解由内而外的优势
让我们更深入地研究由内而外开发的优势,并检查它们是否是真正的优势,以及其中的一些优势如何也可以应用于由外而内的开发。
风险缓解
由内而外开发的最大优势之一是首先解决了系统的核心问题,并希望发现未知的问题-这被称为缓解风险。 但是,减轻风险是我们仅在由内而外开发中应该做的事情吗? 减轻风险和探索工作的所有类型是否都处于同一水平?
通常,我们不确定给定业务需求的解决方案应该是什么样,业务需求应如何设计和编码,我们应该使用哪些工具,或者某些框架如何工作。 需要一些探索性的工作。 2现在,让我们看一下一些探索性工作:
- 技术的:与框架,库,数据库或工具有关。
- 体系结构:与系统如何相互通信,逻辑如何在系统之间分布,API,系统之间的消息,生产环境,日志记录,监视等相关。
- 宏设计:与我们如何在更高层次上组织代码有关:层,六边形,有界上下文等。
- 微型设计:与业务领域规则,类协作,算法,功能组成等相关。
尽早发现未知内容与实际提供功能之间存在差异。 它们不应属于同一任务。 每当我们不确定需要做什么或应该如何工作时,都应该创建峰值 (或任何其他带时间限制的活动)来调查问题。 一旦获得更多信息,我们便可以致力于构建功能。
不要将探索性工作与功能开发混在一起。
在上述四个类别中,我发现有必要为技术,体系结构和宏设计调查创建单独的峰值,而对于微设计则没有价值。 这是我的代码的一部分,它是通过Outside-In TDD自然出现的。
用户界面的变化和影响
从域模型(Inside-Out)开始开发的另一个论点是用户界面(UI)易变,并且应在域模型完成后完成其实现。 好吧,确实是用户界面(UI)的更改比业务规则更频繁地更改,但是所有UI更改是否真的会影响后端? 让我们看一下最常见的UI更改类型及其对后端代码的影响:
审美的
审美变化与UI的外观有关,通常由Web设计师,前端开发人员和用户体验专家完成,而对后端没有任何影响。 审美变化通常是UI中最常见的变化类型。
行为的
行为更改与用户与系统交互的方式有关。 它们会影响用户的旅程 -用户需要执行以达到期望结果的步骤。
行为变化可以细分为两个主要特征: 导航性和可操作性 。
导航导航更改与用户如何浏览应用程序或特定用户旅程中的导航有关。 在Web应用程序中,UI中的导航更改可能会触发后端的更改,也可能不会触发后端的更改。 这完全取决于所使用的前端技术的类型以及视图和控制器层(MVC)的结构。 如果Controller层位于浏览器中(通常使用AngularJS和React这样的框架时就是这种情况),则后端没有任何变化。 如果我们有一个更传统的Web应用程序,其中Controller驻留在后端,则每次添加,删除或更改链接(或按钮)时,都需要更改后端。 有关更多详细信息,请查看我以前关于MVC,交付机制和域模型的文章 。
可行可行的更改与用户可以在系统中执行的操作有关。 它们是为用户和公司提供商业价值的工具。 例如购买产品,阅读餐厅评论,订票等。 通常,用户界面中的更改很小-添加按钮,更改URL参数或HTTP方法或返回代码。 最大的更改通常在后端,通常会创建或更改现有的API及其触发的流程。
数据
数据更改与显示给用户或用户需要的数据有关。 这些更改通常涉及现有API接收或返回的数据更改。 对后端的影响根据数据以及返回或存储数据的复杂性而有所不同。
UI更改实际上对域模型有多少影响?
正如前面所讨论的 ,我们决定的方式来构建我们的交付机制和领域模型将会使我们的后端或多或少容易受到用户界面的变化。 在结构良好的Web应用程序中,如果交付机制完全负责系统的导航,而域模型仅公开业务流和管理数据,则后端的更改可以大大减少。 尽管设计域模型是为了满足用户的需求,但它应该不知道如何将这些业务流程呈现给用户。
用户交互代表用户需求
用户与用户界面的每次交互都代表用户需求。 每次用户提出要求时,满足用户需求是系统的工作。 如果用户只想从网站的一部分导航到另一部分,则该逻辑属于交付机制,而不是域模型。 但是,如果用户要存储或检索信息,则逻辑属于域模型。 从用户的角度来看,我们应该开始设计域模型。
外向内发展的案例
为了就如何设计软件达成一致,我们首先应该同意一些基本原则。 在本文的其余部分,我假设我们都同意以下几点:
- 仅当系统投入生产且用户或外部系统满意地使用价值时,才交付价值。
- 我们应该努力并尽快地创造价值。
- 在构建任何东西之前,我们应该进行适当的尽职调查。
- 我们应该尽快获得反馈。
- 我们应该始终以少量有价值的增量工作。
- 我们应该使事情尽可能简单,但不要简单。
- 我们只应该构建真正需要构建的内容,仅此而已。
- 如果技术任务没有商业价值,则我们不应从事这些任务。
- 调查工作应有时间限制,并应单独完成。
由内而外的发展
由外而内的开发是一种专注于构建足够的代码来满足外部需求的方法,通过消除推测性编码来降低意外复杂性。
仅应满足用户,外部系统或另一段代码的外部需求来编写代码。
注意:在本文的其余部分中,我将假定人们正在跨职能团队工作。 3
增量发展
我们只应该构建真正需要构建的内容,仅此而已。
没有限制,我们的想象力疯狂地奔跑。 在构建软件时,重要的是要限制(或专注于)满足业务需求所需的最低限度的工作。
在“由外而内”的开发中,与其先处理域模型,然后再处理持久性和UI,仅当完成全部功能后才发布到生产环境,我们更喜欢以较小的增量进行工作,从而从UI驱动开发。
图纸样机
首先要做的是使用Balsamiq之类的工具快速绘制一些模型。 Balsamiq的优点是我们可以快速创建可执行的模型,这意味着我们可以播放模型,单击链接,移动到其他页面等。此活动通常与用户和/或合作进行产品负责人。 在绘制模型时,我们将重点更多地放在用户的旅程和每页上的信息上,而不会浪费时间在页面的实际外观上。 由于我们需要在视觉组件(标签,表单,按钮,链接等)中添加名称,因此我们从这些模型中自然产生了领域语言(或普遍存在的语言)。 从实体模型中,我们可以提取出所有构成领域模型中使用的词汇的名词和动词。
当协作完成模型时,整个团队不仅对要完成的事情有清晰的认识,而且对买进也有清晰的认识。 模拟可以使整个团队更好地了解系统的使用方式以及功能之间的相互连接。 而且,模型成为讨论用户故事并开始将功能切成小的可交付成果的良好起点,而不会失去整体外观。
这种方法的一个危险是过分地处理了模型,试图使它们看起来像真实的UI或为太多的功能创建模型。 我们也永远不要使用模型工具生成代码。 建立实体模型的目的是就用户旅程和用户在每次旅程中将与之交互的数据达成一致。
将特征分成较小的增量
启动新功能时,首先要做的是为该功能构建UI。 这听起来很违反直觉,通常会使后端开发人员摇头。 “哦,不,不,不。 这真的是错误的。” 好吧 构建UI将为我们提供来自用户或产品所有者的快速反馈。 如果他们不喜欢该系统的使用方式或所使用的语言,我们可以轻松地对其进行更改,而不会产生任何后端影响-尚无后端。 一旦我们都同意UI,我们将知道后端将需要提供的确切行为,并且将具有更加明确和稳定的域语言。 如果用户界面具有行为,则可以独立测试整个用户界面,从而模拟对后端的调用。 这也将有助于稳定UI所需的API。
一旦完成UI,我们就可以按垂直增量将后端工作分片。 每个垂直增量都应从用户交互开始,并包含满足该用户交互所需的所有逻辑(持久性,与外部系统的通信等)。 完成此增量后,系统将添加新的行为。
这种有条不紊的方法可以小幅地分割我们的特征,并始终从外部(UI)开始进行开发,这使我们可以轻松定义验收测试的边界,并使用它们来指导我们的开发。
一旦完成一次增量,演示并接受该增量,我们就可以将其部署到生产环境或任何其他环境中。 4现在我们准备开始一个新的增量。
由外而内的API设计
API的设计应始终满足消费者的需求。 但是在深入探讨之前,让我们首先考虑一下提供API的不同上下文:
- 公司专用API:仅由API提供者控制的系统使用(内部)。
- 公用API:供不受API提供程序控制的系统使用(外部)。
- 混合API:供内部和外部系统使用。
公司专用API
API的唯一目的是满足其客户的需求,它们是多种交付机制或其他模块(服务)。 前端,移动和后端开发人员应在API设计中进行协作。 当一个团队需要使用另一团队正在开发的API时,也应该进行这种协作。 API设计应由API客户端的需求驱动,而不应由后端开发人员认为API客户端将需要的驱动。
我在许多公司中都看到过,后端开发人员设计API并将其强加给移动和前端开发人员。 移动和前端开发人员经常需要调整其用户体验或增加很多不必要的复杂性,因为API并非旨在为他们提供服务。 这种工作方式变得如此普遍,以至于许多移动和前端开发人员现在都认为API设计不是他们的工作,他们也不愿参与其中。
API提供者(后端开发人员)应尽其所能减少API客户端所做的工作。 由后端开发人员创建的API如果没有清楚地了解交付机制的需求及其各自的流程,则会导致复杂的交付机制和团队之间的摩擦。 跨职能团队可以大大减少这些问题,在跨职能团队中,开发人员不仅需要使用API,还需要使用其客户端。
如果一个API只有一个客户端,则该API应该专用于该客户端。 随着我们添加更多的客户端和不同的外部需求,API逐渐变得越来越通用。
公开API
很难预测使用公共API的所有可能方式。 但是,即使是公共API,也应在设计时考虑外部工作流程,从客户在使用我们的API时应具有的最常见工作流程开始。 根据所公开的API的类型,我们应该从参考实现开始,并从其需求中得出API设计。 参考实现使我们能够验证流程和API粒度是否有意义。 如果我们无法为它们提供一个很好的用例,我们应该重新考虑公开API的决定。
混合API
混合API维护起来非常复杂,因为它们承受着来自不同方面的发展压力。 与公司专用和公共API相似,它们也应根据客户的需求进行设计。
摘要
降低风险是任何软件项目中极为重要的活动。 但是,我们不应将探索性工作与功能开发混为一谈。
仅应满足用户,外部系统或另一段代码的外部需求来编写代码。 我们只应该构建真正需要构建的内容,仅此而已。
根据外部需求指导我们的设计和代码,有助于我们始终专注于手头的任务并避免投机性开发。
为了实现连续的交付和部署,重要的工作是小幅增加。 在小的垂直切片中切片功能是确保每个增量都具有商业价值的好方法。
由内而外的开发是一种结构化,增量式的软件交付方式,着重于交付足以满足外部需求的行为。
注意:在下一篇博客文章中,我们将深入研究由外而内的开发。
- 跨职能团队并不意味着跨职能人员。
- 为了简洁起见,我仅指技术探索性工作,不包括可用性测试,业务影响等内容。
- 团队中的成员拥有所需的全部技能,可以构建要求的内容。 例如:前端,移动,后端,操作等。
- 有时我们可能想在部署到生产之前先批量增量。 另外,我们可以连续部署它们并使用功能切换。
翻译自: https://www.javacodegeeks.com/2017/10/case-outside-development.html
触摸屏左右屏幕外向内滑动