在《悲伤的阶段》的精神下,这些是新软件开发技术的《采纳阶段》
更新:希望这不会太像Gartner的“炒作周期”。
- 阶段1,狂欢: “闪亮的新玩具”阶段,我们首次发现一个新想法,并意识到它的强大。随着我们变得更加自信,我们开始尝试将其用于/一切/。
- 阶段2,失望: 不可避免地,当我们开始尝试将这种新方法应用于更多更复杂和隐晦的问题时,我们开始遇到它不太适合的情况 - 这可能是因为想法的表达(当前实现)还不够成熟和完善,或者是因为我们在兴奋中简单地误用了它。
- 阶段3,洞察: 闪亮的玩具现在只是我们工具箱中的另一个小玩意。我们终于有了经验,知道何时以及何时不应使用它。我们不仅理解了想法的限制,还理解了/为什么/这些限制存在。
Seam的最早版本发布已经过去一年了,现在我认为Seam是Java中增长最快的框架(每天下载500次,并且还在增加)。但Seam中的想法 - 上下文组件、状态管理、会话、BPM - 对于大多数人来说仍然很新,Seam社区仍在理解如何以及何时应用这些想法。这实际上是一个像Seam这样的项目最令人兴奋的阶段。我喜欢Hibernate的早期日子,当时社区仍在开发模式(以及描述这些模式的语言),这些模式现在已经成为书籍和示例,并且为大多数企业Java开发者所熟知。
今天我收到了一封来自一个刚进入第二阶段,失望阶段的用户的电子邮件。他问:
- 在faces-config.xml中,是使用页面流程好,还是普通的JSF导航足够好?有没有一句话可以解释如何使用@Begin和@End?
- 我认为我的大多数问题都是由于对会话的误解和不正确的使用造成的。
在一年前真正坐下来编写我第一个Seam示例应用之前,我花了超过一年的时间来思考会话和乐观事务,并设计Seam的会话模型。即便如此,两次都搞错了!实际上,我在我们心爱的预订演示的第一版中成功地搞砸了会话模型。我那毫无说服力的借口是我试图说明会话的/概念/,同时保持实际的会话模型非常简单。但当然,展示一个想法力量的最糟糕方式就是错误地应用它。我深感愧疚。
一年后,我认为我们终于到了可以开始正式制定一套关于在哪里使用会话、在哪里不使用会话、在哪里开始会话、在哪里结束会话的直观规则的时候。我们现在有了关于这一想法及其实现的来之不易的实践经验。
没有与用户的交互,很难定义一个正确的状态管理模式。我们首先需要理解用户希望应用如何工作:哪些任务应该是可多任务的,哪些页面需要可书签或通过电子邮件交换,何时工作应该变得持久,等等。
我对《何时开始会话?》的第一个尝试如下
如果您在页面X,则开始一个新的会话,
- 用户预计将想要使用《在新标签页打开》或《在新窗口打开》导航到页面Y,
- 并且您希望一些在渲染Y时检索到的状态在服务器上保持内存中的状态,但仅限于标签页或窗口。
我们需要补充以下附加规则
- 如果页面X已经有一个会话,而页面Y需要访问X的会话中持有的状态,那么它应该是一个嵌套会话。否则,它应该是一个全新的顶层会话。
好吧,这些规则实际上只是对《会话》和《嵌套会话》的定义的重复。它们并没有真正告诉你什么你已经不知道的(尽管这可能是一种更友好的表述)。我们真正需要的是对X和Y可以是什么类型的描述。因此,当我在开发框架时,我真正需要考虑以下典型情况
- 搜索/列表屏幕:这些允许用户找到并导航到他们感兴趣的实体实例。搜索屏幕通常支持排序。
- 项目详情页面:这些允许用户查看不仅是一个实例,还有相关的对象。有时这些页面可以是复杂的由树视图控件驱动的视图,可能需要通过AJAX进行延迟加载数据。
- 编辑/关联管理页面:这些页面实现了简单的乐观事务,允许用户原子性地查看和更新实体实例,并可能更改其实体与其他实体的关联。现在我将创建和删除功能归入此类,尽管这些功能应该严格有自己的类别。
- 向导:我不仅仅是在想简单的线性流程,而是在想任何引导用户通过一系列步骤形成单一工作单元的交互。事实上,《向导》甚至可以是像树视图控件这样复杂的东西,用户可以从中编辑顶层对象及其跨越多个不同页面的子对象的数据,通过AJAX进行延迟加载数据并在服务器上缓存编辑,然后在最后的单一原子《保存》操作中使所有更改持久化。
对我的失望用户的第一问题的答案是简单的:/仅对向导使用jBPM页面流/。无状态导航模型更适合我们其他典型情况。
但我还没有满足他对于何时使用对话的 一句话解释
的要求。相反,我将尝试概述一组步骤,用于设计一个用于应用的纪律性状态管理模型。
步骤 1: 首先要考虑的是搜索或列表屏幕。这些非常重要,因为它们是所有应用程序功能的入口点。我们需要决定在哪里 放置
搜索结果列表。备选方案包括
- 在对话中保持结果列表 - 这通常有点过度
- 在会话上下文中保持结果 - 如果用户需要能够同时运行多个搜索,则不是很好
- 无状态(使用带有请求参数的重定向并拉取 MVC)- 优点是可以将结果添加到书签;缺点是我们无法轻松缓存搜索结果,这可能会在用户被允许对结果列表进行排序和重新排序时减慢性能
- 在页面上下文中放置结果(这会序列化到客户端)- 这可能意味着相当多的序列化开销
总的来说,我大多数情况下更倾向于无状态,但这取决于用户的需求。会话范围可能是他们更喜欢的(这是我们Booking演示中使用的方法)。通常在这里不会有对话的位置。
步骤 2: 当我们从搜索屏幕导航到项目详情页面时,存在一个类似的选择空间
- 在新的对话中保持项目
- 保持无状态(请求参数和拉取 MVC)
- 使用页面上下文
现在平衡倾向于使用对话,特别是如果我们有一些复杂对象并且需要树视图风格的导航。(在这种情况下,对话为您提供透明的延迟关联加载以及所有这些好的东西。)但如果可书签性是必需的,无状态又是最佳选择。
步骤 3: 现在,我们开始到达编辑页面、关联管理页面、创建/删除等。我们处于乐观事务的世界,因此对话是王道。主要决策围绕对话传播:嵌套对话?新对话?保留在现有对话中?这取决于用户想要使用多少 在新标签页中打开
!
步骤 4: 最后,向导应始终在对话中运行。实际上,你很可能会想要使用 原子对话
模式,其中更改在服务器端暂时保存在内存中,直到对话结束。一些向导应该使用页面流程。(请记住,我对 向导
的定义非常广泛。)
希望这次讨论能帮助您从失望走向领悟,而不会吓跑那些尚未体验过狂欢的人们。