看我如何应对业务需求变化,“愚蠢”的应对?
作者:网络转载 发布时间:[ 2014/10/15 14:58:23 ] 推荐标签:软件测试管理
“愚蠢”的应对
我个人觉得这一节点内容非常重要,在领域驱动设计的过程中,也是很多人常掉进的“坑”,因为我们长期受“脚本模式”的影响,在业务需求变化后,应用程序需要做出调整,但是你会不自觉的“跑偏”,这偏离了领域驱动设计的思想,后使你的应用程序变得“不伦不类”。
当时为了很快的在应用程序中实现这种功能,我说的是技术上实现,完全没有用领域驱动的思想去考虑,我是怎么思考的呢?先从 UI 上考虑,主要是两个界面:
消息列表:收件箱、发件箱和未读消息列表。
消息详情:消息详情页。
消息列表实现
之前短消息不管发送,回复,还是转发,都是作为一个新短消息进行发送的,“消息的上下文”作为一个消息的附属体,放在新短息内容中,也是说,你把之前发送的消息删掉,在新回复的短消息内容中,是仍然看到之前发送内容的,这个在列表的显示是单独进行显示,但新的需求变化不能这样进行操作了,这个有点像两个人聊一个话题,里面都是我们针对这个话题进行讨论的内容,在列表显示的时候,首先,标题显示是这个话题的标题,像邮件回复一样,我们可以加上“消息标题(3)”,这个“3”,表示两个人回复了3次。
其实用话题这个逻辑是有些不准确的,毕竟我们是短消息项目,我们可以这样想,我给 netfocus 发了一个标题为:“打个招呼”,内容为:“hello netfocus”的消息,然后他给我进行了回复:“hello xishuai”,可能后面还有一些消息回复内容,但都是针对我发的第一条消息回复,也是说下面都是回复内容,那这个在消息列表显示的时候,标题显示为“打个招呼(3)”,后面时间为新回复时间,示意图:
上面是 netfocus 的收件箱示意图,收件箱列表显示的逻辑是以发件人和标题为一个标识,比如 Jesse Liu 也给 netfocus 发了一个“打个招呼”的消息,虽然标题一样,但发件人不一样,所以列表显示两条消息。
那代码怎么实现这个功能呢?贴出代码看看:
public async Task<IEnumerable<MessageListDTO>> GetInbox(Contact reader, PageQuery pageQuery)
{
var query = efContext.Context.Set<Message>()
.Where(new InboxSpecification(reader).GetExpression()).GroupBy(m => new { m.Sender.ID, m.Title }).Select(m => m.OrderByDescending(order => order.ID).FirstOrDefault());
int skip = (pageQuery.PageIndex - 1) * pageQuery.PageSize;
int take = pageQuery.PageSize;
return await query.SortByDescending(sp => sp.ID).Skip(skip).Take(take)
.Project().To<MessageListDTO>().ToListAsync();//MessageListDTO 为上一版本遗留问题(Select FileName),暂时没动。
}
GetInbox 是 MessageRepository 中的操作,其实原本收件箱的代码不是这样处理的,你会看到,现在的代码其实是 Linq 的代码拼接,我当时这样处理是为了可以方便查询,现在看确实像“一坨XX”,代码我不多说了,上面列表显示功能是可以实现的,除去回复数显示,其实你会看到,这个是对发件人和标题进行筛选,选取发送时间新的那一条消息。
虽然这段 Linq 代码看起来很“简单”,但是如果你跟踪一下生成的 SQL 代码,会发现它是非常的臃肿,没办法,为了实现功能,然后不得不去优化数据库,主要是对索引的优化,这个当时优化了好久,也没有找到合适的优化方案,后不得不重新思考这样做是不是不合理?这完全是技术驱动啊,后来,我发现,在领域驱动设计的道路上,我已经完全“跑偏”了。
消息详情页实现
业务需求的变化,其实主要是消息详情页的变化,从上面那张消息详情页示意图可以看出,刚才上面说了,收件箱列表显示是对标题和发件人的筛选,其实详情页是通过标题和发件人找出回复消息,然后通过发送时间降序排列。具体操作是,在收件箱中点击一条消息,然后通过这条消息和发件人去仓储中找这条消息的回复消息,示例代码:
public async Task<IEnumerable<Message>> GetMessages(Message message, Contact reader)
{
if (message.Recipient.ID == reader.ID)
{
return await GetAll(Specification<Message>.Eval(m => m.Title == message.Title
&& ((m.Sender.ID == message.Sender.ID && m.Recipient.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Inbox))
|| (m.Recipient.ID == message.Sender.ID && m.Sender.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Outbox)))),
sp => sp.ID, SortOrder.Ascending).ToListAsync();
}
else
{
return await GetAll(Specification<Message>.Eval(m => m.Title == message.Title
&& ((m.Sender.ID == message.Sender.ID && m.Recipient.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Outbox))
|| (m.Recipient.ID == message.Sender.ID && m.Sender.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Inbox)))),
sp => sp.ID, SortOrder.Ascending).ToListAsync();
}
}
不知道你是否能看懂,反正我现在看这段代码是需要思考一下的,呵呵。消息详情页基本上是这样实现的,还有一些是在应用层获取“点击消息”,UI 中消息显示判断等一些操作。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11