04-The-Depot-Application
我们这几天编写了一个粗糙的测试应用,但这并不能帮助我们实现目标。因此我们需要亲自啃这块硬骨头。让我们一起创建一个基于网络的购物车应用,并将它称为 Depot。
市场上还需要其他购物车应用吗?其实并不需要,但这并不能阻止数以千计的开发者再创建一个。其实我们也没有什么不同。
需要严肃说明的是,这个购物车应用能够帮助阐明许多 Rails 的开发特性。我们也会了解如何开发基本的维护界面,连接数据库表,操作 session 以及创建表单。其实,在接下来的十二章中,我们还会了解一些诸如单元测试,安全性和页面布局的话题。
增量开发
我们稍后就将开始开发这个应用。但我们不会试图在开发前详细列举每件事情。相反,我们会完成足够让我们开始的准备工作,并立即创建一些基础建设。我们也会尝试许多点子,然后获取反馈,并且持续最小设计和开发的循环。
这种编码风格并不总是适用。它需要与用户间的亲密合作,因为我们需要持续地获取反馈。我们可能会犯些错,或者客户发现自己只是想咨询点事情,而不是想让某些功能改变。这并不意味着我们可以更早发现自己的犯下的错,不过我们可以为修复过错付出更少的代价。总而言之,尽管使用这种开发风格,但持续的过程中我们也会有些许变动。
因为这些原因,我们需要一个工具集合,让我们在改变想法时不置于掉入巨大的陷阱。比如我们决定要向数据库表添加一个新的列时,或者修改界面间的导航时,我们可以顺利找到相应地方并且不需要操作大量代码或进行复杂的配置。如同你见识到的,Ruby on Rails 处理这种变化时熠熠生辉,它本身就是理想的敏捷开发环境。
开发过程中,我们将会建造维护一个测试集。这些测试将用来确认应用总是在按照我们的想法运行。不仅仅是依靠 Rails 就可以创建这些测试,但它确实地在定义一个新 controller 时就初始化了一组测试。
我们继续讲讲应用程序。
Depot 的功能是什么
让我们简单记录一下 Depot 的详设蓝图。我们会看到高等级的用例,也会看到界面流程的草拟图。我们也会尝试描绘应用需要的数据(需要承认的是,我们的初始猜测通常是错误的)。
用例
用例 是一种简洁的声明,它表示使用这个系统的一些实例。顾问通过虚拟场景的方式标识我们所知道的事情,即使平淡的词语更加有价值,但华丽的辞藻总是比平淡的词语更加有价值,这是对商务日常的曲解。
Depot 的用例是简洁的(有些人会说这挺悲剧的)。我们从两个识别到的角色或行动者开始,分别是 buyer(购买者) 和 seller(售货员)。
购买者使用 Depot 浏览我们售卖的商品,选择其中的一些购买,并提供必要的信息创建订单。
售货员通过 Depot 维护售卖商品的清单,还可以确定等待装运的订单和标记已经装运的订单(售货员当然也可以通过 Depot 赚一大笔钱然后退休后去一座热带岛屿,但这些是其他书中要介绍的知识了)。
现在,这些就是我们需要的所有细节了。我们可以更深入至细节中,比如维护商品是什么意思,怎样才能让订单准备装运,但没有必要关注这些细节。如果有不够明显的细节,我们会很快发现它们,因为我们向客户展示我们的持续迭代。
谈到获取反馈,让我们看看现在要怎么做,首先确认我们通过询问客户获得的初始用例是切题的。
假设用例都没有问题,接着就让我们制定应用程序将如何根据不同用户的愿景进行运作。
界面流程
我们总喜欢先就应用的主页面提出想法,并且以此为基础粗略地了解用户想在页面的导航上做些什么。这个步骤早于开发,虽然页面流程并不完备,但它们可以帮助我们专注于需要做的事情,以及了解一系列的动作如何运行。
一些人喜欢用 Photoshop,Word,或 HTML 模拟应用界面流程。我们更加愿意使用铅笔和纸。它更加快速,客户也可以一起参与,随时可以抓起铅笔并在纸上画出自己想要的东西。
第一张关于购买者的流程如下图所示。
流程比较传统。购买者查看分类界面,在这个界面中一次只能选中一款商品。每件被选中的商品都会添加至购物车,每次添加商品后都需要展示购物车界面。购买者也可以继续通过分类界面购物,或者检查并确认购买购物车中的商品。在检查期间,我们会获取联系人和支付详情,并且在收据界面展示。我们还不知道要怎样操作支付,所以这些细节在流程中是相当模糊的。
售货员流程如下图所示,也相当简洁。在登录后,售货员会看到一个菜单,这个菜单可以让她创建或查看一个商品,也可以装运已经存在的订单。如果进行商品查看,售货员可以选择性地编辑商品信息,也可以完全删除商品。
装运选项也很简洁。它展示每个还没有装运的订单,每个页面只显示一个订单。售货员可能会选择跳过下一步,也可以选择页面上适当的信息装运订单。
装运方法足够清晰但无法在真实情况下存在,但装运也是一个现实中比你想象的还要奇怪的领域。提前详细设计过多的东西只会让我们出更多错。现在界面流程就保持这样,我们确信在用户使用应用的过程中我们可以通过用户的经验修改它。
数据
最后我们需要考虑一下将会用到的数据。
需要注意,这里我们并没有使用诸如 schema 或 classes 这样的字眼。我们也没有谈论 databases,tables 和 keys 等种种。我们单纯想谈论数据。到了这个开发阶段,我们还不知道自己是否会使用到数据库。
基于用例和流程,看起来我们将使用到下图提及的数据。再一次说明,使用铅笔和纸会比其他有价值的工具更容易,但你用什么工具都可以。
通过上述数据图例浮现出一些问题。当用户购买商品条目时,我们需要将他们购买商品的列表存放何处,所以我们添加了购物车。但与购物车存放商品列表的透明地带意义相去甚远的是,购物车看起来像极了一个幽灵,我们并没有找到它将会存储任何有意义的东西。这也反应了不确定性,我们在购物车的图例中标注了一个问号。我们假设这些不确定性将在实现 Depot 的过程得到解决。
找到高层级数据的过程中也浮现了我们要将哪些信息放入订单中的问题。我们此时选择让它保持开放,我们会如同开始时说的那样通过向客户展示迭代将这些信息精炼,将问题解决。
最后,你也许已经注意到我们在排列项中重复地标注了价格项。这个地方我们打破了「开始时,保持简洁」的规则,但这是一个基于经验的犯规行为。如果一个商品的价格发生变化,它不应该引起已经开据的订单排列项价格变化,因此每个排列项都需要表示为订单生成时的商品价格。
常规建议
书中描述的每个东西都是经过测试验证的。如果你准确地跟随本书描述的场景,在相应操作系统中使用推荐的 Rails 和 SQLite3 版本,接下来的操作结果都会如同书籍描述的一样。不过,偏差也可能会出现。排版印刷的错误也是会出现在我们这里的,但这不止是产生负面影响,同样也会有积极作用。要注意这些错误可能将你引向奇怪的地方。但无须害怕,详情已经覆盖了通常问题容易出现的地方。下面还有一些小建议。
你应该只需要在为数不多的几个地方重启服务,这也是需要注意的。不过如果你真正地遇到了难题,重启服务也是值得一试。
有个魔法命令你需要知道,这个命令在第三部分会进行解释,它就是
rake db:migrate:redo
。它将会撤销和重新应用最后的迁移。如果你的服务器不能接收到一些表单输入,你可以在浏览器中刷新和再次提交表单。
需要再次强调的是,此时我们会和客户复核我们的工作是走在正轨上的。(当我们在画这三个图例时客户最好都已经坐在房间里)。
开始编码
因此,在与客户坐到一起,并进行了一些初步分析之后,我们已经准备好在电脑上开发了!我们将会根据最初的三个图例实现,但这个机会也千载难缝,我们会尽快将图例抛诸脑后,他们将会成为我们收集反馈后的过时产物。这也是我们不在上面花费过多时间的原因,如果你并没有花费大量时间创建它,那么抛弃他也不是什么问题。
在下面的章节中,我们将基于当前的理解开发应用程序。然而,在我们开始新篇章之前我们还需要再回答一个问题,我们首先要做什么?
我们愿意与客户一起工作,所以我们有权利参与到讨论中。在这个事例中,我们要知道,在我们系统地对产品有一些基本定义之前是很难开发任何东西的,所以我们建议花几个小时完成产品基础维护功能的初始版本并将其运行起来。当然,得先要征得客户同意。