跳到主要内容

Picturing Architecture

· 阅读需 27 分钟

除非你在山顶的山洞里工作,否则你可以与其他人谈论你的工作,否则你将无法真正有效的编程。而当你这样做时,就是说,看代码不会消减代码 代码太复杂了,整体解构还不够清晰

Picturing Architecture

交流 除非你在山顶的山洞里工作,否则你可以与其他人谈论你的工作,否则你将无法真正有效的编程。而当你这样做时,就是说,看代码不会消减代码 代码太复杂了,整体解构还不够清晰

1. designing in an agile world

2. Organizing Stories

stories and story cards

当设计到描绘架构时,让我们从设计过程的开始,即设计过程的开始开始。在本模块中,我将讨论故事以及组织故事并已图形方式故事以进行计划的方式。 不过,首先我需要谈一谈到底是什么故事。因为没有这样的背景,我以后再给你的描述就没有多大意义,而且很多人并没有真正理解一个故事。也就是说,故事的概念对于敏捷开发至关重要,因此我们最好把事情做好。因此,“故事”一词并非像我们在计算机科学中经常发下的那样构成对英语单词的反感。 例如,有几棵树的根在空中飘扬?首先,一个故事的确切含义就是它在字典中的叙述,即叙述。更准确地说,它是一种叙述,它使用户完成某些过程,从而产生对于该用户在现实世界中有价值的结果。换句话说,一个故事描述了一个过程。他没有描述事物

A narrative that takes a user through some process that results in a valuable outcome

这是动词,不是名词。因此,故事并不是表达功能请求的一种好方法。添加按钮不是故事。那里没有用户级别的叙述,而典型的用户可能会在乎我们的程序有多少个按钮

用户关心的是,他们在使用该程序时正在完成某些工作,而这正是故事所捕捉到的,他们正在完成的事情。

故事并非独立存在,而是存在于某些上下文中。而我们将上下文视为系统隐喻。可以将隐喻想象为故事发生的环境,如果可以的话,可以设置舞台 因此,在我们的博客系统上,我选择了一本杂志作为一个特别有用的隐喻,隐喻为我们提供了一堆可以在代码中建模的抽象,并且我们可以直观地理解这些抽象,或者如果它是一个很好的隐喻,我们可以 一本杂志上又出版商,读者,作家和文章,还有完全了解的许多其他内容。如果我们的代码结构具有这种隐喻模型,那么代码结构也将是直观且易于理解的。

这些片段将以连贯的方式组合在一起,因此,隐喻实际上使我们系统体系结构的一幅图,尽管这是一种心理上的构想。这是我们谈论的第一张价值图,他在你的内心深处,看不到 UML。现在已经确定了一个隐喻,我们的下一个任务是编造一些故事。代表故事的最佳方式是在索引卡上以实物形式呈现,现在这张卡片并没有包含所有细节,只是一两句话。在开始编码之前,可以将其视为与用户进行详细对话的占位符。 这是一个例子,现在这个特定的故事是以公式化的方式表示的,我将在第二秒钟中谈论它,而且这里有比我们在敏捷商店中常见的两周发布周期中更多的工作要做,所以这个特殊的故事被称为史诗,因为它是如此之大。换句话说,它不是占一个对话的占位符,而是占整个对话和整个故事的占位符。即使在史诗级,这里也有一件重要的事情要注意。阅读我们的句子,作家真的只是对表达意见感兴趣吗?我会说不,他们希望他们的意见能被听到并具有影响力。因此,让我们更改故事以反映该目标。现在,一项更改可能会对我们的代码产生巨大影响。如果我们正在考虑发挥影响力,那么我们也在考虑如何传播刚刚写的东西?换句话说,该程序现在必须具有以前没有的功能,与传播有关的功能,发送电子邮件(例如,当我们添加新博客时)或自动发布推文。因此,精心制作这些句子非常重要,并且在我们制作这些句子时牢记用户的真实目标更为重要。现在回到公式化部分,通常使用 mike cohn 的模板来表示故事。 基本形式是 x 我需要 y 来做 z。填写 x 是用户扮演的角色。换句话说,他是作为 x 角色的用户。不要讲这些角色与实际人员混淆 例如有时我会以作者的身份登录系统已撰写博客,有时我会以管理员的身份登录同一系统以执行某种管理任务。在两种情况下,我都是同一个人这一事实实际上并不重要。

在代码和设计级别上重要的是人员在登录时所扮演的角色。下一块是我需要做的部分。这是给定角色的某人将执行的一组活动,已实现某种有价值的结果。 换句话说,本节描述了一组域级别的活动,没有描述使用计算机程序的用户 我们将把所有内容都保留在我们的系统隐喻中,因此这里描述中,因此这里描述的所有活动都是在发行杂志的过程中应该进行的事情,你没有在故事卡上放置任何有关如何使用计算机程序的内容。 如果程序不存在,你将看到用户将要执行的操作。模板中的第三字句向我们展示了我们试图实现的结果。同样,这必须对我们的用户有价值 例如登录不是故事,因为那里没有有价值的结果,你不是为了登录儿登录,现在,在一家敏捷商店中,我们的工作单元就是整个故事

换句话说,我们讲一次处理一个故事,构建从 ui 一直到数据库的所有内容。如果故事足够小,我们将在一两个星期内完成所有工作,届时我们将拥有可以发布的内容。 我们将有一段工作代码,因此以敏捷方式工作的优点之一是该程序可以运行。现在他起初并没有做很多事情,但实际上他可以正常运行 随着我们继续构建该程序,我们将从头到尾实施更多故事,随着时间的推移,该程序将逐渐变得越来越有用。 不过这里的要点是,我们可以随时停止工作,并且我们将拥有一个功能能齐全的程序。我们永远都不会在程序的某个角落工作六个月,而在那个时候程序仍然无法工作。现在有最后一个思维差别

当我编写故事时,我个人希望对规范形式进行重新排序,已将结果放在第一位,这主要是因为他是我专注于我要完成的工作。这毕竟是故事中最重要部分

story Maps

现在一旦我们有了少量的故事,我们就需要一种图形化的方式来表示他们的全部集合,以便我们能够弄清楚首先处理的内容 我们的目标是始终致力于最重要的事情,既对用户最有价值的事情,我所知道的最好的工具不是图片,而是所谓的故事地图,他是一块板子或一面带有一堆卡片或便利贴的墙

故事地图是由 jeff patton 开发的,他在他的《用户故事地图》一书中对其进行来描述,我强烈建议你阅读它,这是一本很棒的树

我将暂时查看地图的结构,但是 jeff 的书中包含了所有细节,因此我将在本节课中没有事件讨论。现在故事地图是一个网格,我们在上面放置了所有故事卡 通常当我制作地图时,我会遇到一些并非地图真正组成部分的桩,左边一堆故事是我的渗漏故事 换句话说,这些是我认为我们将在某个时候进行的工作,但是我现在真的不想考虑他们,因为我可能没有足够的信息。换句话说,对于我不想忘记的事情来说,这是一堆烂泥 我喜欢保持可见,以便偶尔考虑 换句话说,我喜欢讲故事地图放置在我经常走的某个大型公共场所,每当我走在地图上时,我的视线都会被渗流堆中的其中一张卡片吸引住,而我会在考虑一下,也许将其适当的移到地图上。 右边的故事也不是地图的一部分,那只是我完成的一堆事情,这让我很高兴看到我完成了一些事情。如果你是管理人员,那么你真的会对故事从地图移到成品桩的速度感兴趣 因此从管理的角度来看,实际上在哪里堆满了成品实际上可以为我们提供一些有用的信息。现在转到地图本身,列标题使我们环境中隐喻中的广泛活动类型 通常,为了拥有一个完成可行的系统,你必须至少在这些活动的每一项中实现了一些功能,如果该活动是一项大型活动,则可以按照我在此处所做的将其细分为子活动 然后下一步是获取故事卡,并将其放在地图的右列中。当然,现在故事不一定要完成放在一列或另一列中,因此我们将其放在看起来最有意义的一列中 故事按优先级和价值来组织。因此,你离顶端越近,这个故事就越有价值。 一旦我将所有卡片都放在地图中,最上面的一行就是你拥有一套完全有用的系统所需要做的最少工作。你可以将其视为概念验证系统。 换句话说,我们将在每一行中从左到右执行故事。因此我们将从左到右,从上到下。这样,我们总是接近拥有一个完整的系统 我们总是首先做最有价值的事情,并且我们总是一起实施具有相同价值水平的所有内容以形式发布,而且我们离发布仅剩几个故事 或者换句话说,在任何时候,我们都可以保证我们已经建立了我们可以在可用时间内构建的最有价值的程序 因此,六个月内将不会进行任何这项工作,也没有任何东西可显示。我们总是可以提供一个工作系统。继续前进,在完成每一行之后,你可能不希望发布到更大的用户社区 泥浆向某人释放,但不会向所有人释放,因此我们必须决定的事情之一就是何时进行正式发布,而在故事地图上指示正式发布的方式只是在合理的位置在地图上画一条水平线 当然,真是的地图比我在这里给你展示的地图要大得多,但它们并没有太大。在任何给定的时刻。一张大地图上可以都有三十个故事。那是一张相当不错的地图。

你不希望超过 30 个左右的原因是,这些故事将在将来实现,因此立即将其故事化的可能性为 0

因此,如果你认为要做的事情比摆在你面前的三十件事要多得多,那就把它放在渗流堆中,最后请注意,此地图是动态的,这是使用物理索引卡或便利贴比绘制图形更好的原因之一 通常会出现新的故事,通常是因为用户正在使用代码并意识到他们忘记了一些东西 现有的那些将消失,因为我们意识到它们并不像我们认为的那样有价值,优先级发生变化,开发四处移动。 现在,当组合一个故事图时,问题之一是找出订购卡片的最佳方法,换句话说,实际优先事项是什么?

Story (Use Case)Diagram

因此,实际上有一张真实的图纸对此很有帮助,我称之为故事图,UML 称它们为用例图 这是一幅相同的图,用例和故事非常相似,尽管概念不尽相同,但是由于我是一个敏捷的人,因此我在这里以故事而不是用例的方式思考,因此我将其称为故事图。 你可以在图中用带圆圈的名称表示故事,也可以使用简笔图表示该故事中涉及的角色 UML 称这些为角色参与者。但角色实际上是一种更正确的看待方式,因此我们称其为角色。在这里,由主持人角色创建的杂志 以故事卡的形式,我会说类似的话,作为主持人,我需要创建一本杂志来做某事或其他。现在让我们添加第二个故事 作为作者,我需要创建一篇文章,或者也许我应该说我需要写一篇文章。一种或另一种方式,我们有第二个故事。现在这两个故事之间存在依赖关系 除非有杂质要刊载,否则你无法创建文章。这不一定意味着我们必须在创建故事之前先创建杂志,但是如果我们不创建杂志,则必须以不同的方式来创建故事 例如必须有残存对象,如果我们以相反的方式进行操作,这些对象将是真实对象。我将用一条线和一个箭头来表示该依赖关系,改线和剪头指向必须首先完成的事情,将其视为依赖关系。如果 A 依赖于 B,则箭头指向 B。现在我讲添加另一个故事 作为读者,我想评论一篇文章,然后设置依赖项。评论依赖于创建故事,因为对不存在的故事进行评论完成没有意义 现在,当我想到设计时,我的想法是,注释将在编写后立即添加到注释线程中,但它是不可见的 如果评论呗某位主持人批准,那么我将使其可见,如果未被批准,则将其从线程中删除,在这里,我指定了两个可能的参与者,换句话说,作者或主持人都可以批准评论 现在,让我们添加另一个故事,这实际上是最后一个变体。这是一种批准,但我希望能够通过电子邮件批准 换句话说,我正在想象系统将向主持人发送一封电子邮件,如果主持人响应该电子邮件,那么该故事将被批准。现在,你可以标记依赖项行,以使这里的事情更加清楚 你可以使用 UML 成为构造型的东西,一个简短的注释字符串,那些类似于小括号的标点符号来完成此操作 顺便说一下,请注意这些是实际的标点符号,他们不是两个小于号和两个大于号 这里的 require 构造型实际上只是一行的默认含义,因此显示的添加它实际上只是噪音。但是,扩展刻板印象告诉我们一些有趣的事情。 在这里,我说的是电子邮件故事是更基本的批准故事的延伸 或换一种说话,当我们完成批准故事时,我们可能已经完成了电子邮件故事的大部分工作,因此电子邮件故事应该相对较短 现在,一旦我们有了所有的故事,我们就会有很多圈子和很多依赖关系。那些箭头最多的故事是最先发生的事情的良好候选者。换句话说,很多事情都取决于这些故事,因此如果我们先做了这些事情,那么就可以轻松地进行其他事情 另请注意,史诗确实是一种故事,只是一个很大的故事,我们也可以将其放在图片上,我已经在这里完成了,但是我使用 UML 中的上下颠倒的三叉戟符号来表明这是史诗般的。因此这是我在工作时代表故事的两种图形方式。

在下一模块中,我讲进一步深入研究,并向你展示如何弄清楚为实现这个故事我们必须要做的事情,我将使用另一种 UML 图(活动图)来完成此操作

3 Activity Diagrams

活动图的重点是向我们展示所有的活动,为了让我们通过这个故事,有人必须做的所有事情,这里有比你在故事卡上有的更多细节 我们得到细节的方式,当然是通过与我们的用户交谈所以活动图特别有帮助,当以和一群用户坐在一起,视图弄清楚他们必须经济什么步骤时 为了达到他们有价值的结果,这是这张图的主要值之一,事实上不涉及编码,因此你的用户是否可以读取代码并不重要,现在你必须经历的一系列步骤可能很简单,他可能只是一个线性列表,如果是这样的话,绝对没有理由拍这样的照片只需制作一个项目符号列表并编码大多数故事都比那复杂,这就是图表为什么很方便,顺便说一句,这是所有这些图表的一般规则 如果你能用代码,我们这里不做大的前期设计工作,我们的目的是编码,如果我们能直接进入代码,现在回到我们的照片就更好了了 活动图会勾勒出一个特定故事的所有步骤,事实上,活动图通常会勾勒出几个故事的步骤,事实上,我要在这里采取这种方法,我将创建一个单独的活动图,显示与两个评论相关的所有活动 我们在上一个模块中看到的批准故事,现在所有的活动都必须从某个地方开始。我们在图表中用一个大黑点指出,那是我们开始的地方 然后我将添加某人创建评论所需的第一个活动 然后下一个需要有人在仪表板上添加注释 现在请注意,我捕捉到的所有以下是活动本身,我说总得有人 我真的不在乎谁在做这个活动,当我把这张图放在一起的时候 那是我以后要做的决定 当我开始接近这里的实现时,我关心的是什么,换句话说就是正在发生的事情 是谁在做这件事 接下来我需要做的是把评论添加到评论中 当我将注释添加到仪表板时 UML 让我们用一种叫做叉子的东西来表示这种情况 这里的分叉是顶部的的粗黑线和底部的连接是底部的大黑线 其基本思想是,fork 和 join 之间的操作可以任何顺序进行 无论如何