这是松结对编程的第22篇(专栏目录)。

接前文

业务代码

比较长,基本上就是看被注释隔开的三大段,先显示状态群筛选链接,然后是单个状态筛选,然后是显示下拉框的当前选中项,最后显示下拉框。
        public static MvcHtmlString StatusFiltersDropdownList(WebViewPage page)
{
var allStatuses = Status.AllStatuses().ToList();
const string key = "statusIds";
var currentStatusIds = page.ParameterOf(key); //Status groups filters on the top.
var linksLeft = new Dictionary<string, IEnumerable<Status>>
{
{"所有状态", allStatuses},
{"所有正常", allStatuses.Where(i => i.IsNormal)},
{"所有开放", allStatuses.Where(i => !i.IsClosed)},
{"所有故事板", allStatuses.Where(i => i.IsDisplayedOnKanban)},
};
var linksListLeft = AddToList(page, key, currentStatusIds, linksLeft); var linksRight1 = new Dictionary<string, IEnumerable<Status>>
{
{"0", null},
{"所有已放弃或推迟", allStatuses.Where(i => !i.IsNormal)},
{"所有关闭", allStatuses.Where(i => i.IsClosed)},
{"所有非故事板", allStatuses.Where(i => !i.IsDisplayedOnKanban)}
};
var linksListRight1 = AddToList(page, key, currentStatusIds, linksRight1); //Single status filters on the bottom.
linksListLeft.Add(new MvcHtmlString("<hr/>"));
linksListLeft.AddRange(allStatuses.Where(i => i.Value >= 0)
.Select(status => status.Link(outerLink: page.MergeParameter(key, "_" + status.ID + "_"), title: status.Value.ToString(),
displayAsBoldText: "_" + status.ID + "_" == currentStatusIds)));
linksListLeft.Add(new MvcHtmlString("<hr/>"));
linksListLeft.AddRange(allStatuses.Where(i => i.Value < 0)
.Select(status => status.Link(outerLink: page.MergeParameter(key, "_" + status.ID + "_"), title: status.Value.ToString(),
displayAsBoldText: "_" + status.ID + "_" == currentStatusIds))); //Current value text
var currentValueText = "";
MvcHtmlString currentValue = null;
currentValueText = linksLeft.SingleOrDefault(i => i.Value != null && currentStatusIds == i.Value.Aggregate<Status, string>(null, (current, status) => current + "_" + status.ID + "_"))
.Key ?? currentValueText;
currentValueText = linksRight1.SingleOrDefault(i => i.Value != null && currentStatusIds == i.Value.Aggregate<Status, string>(null, (current, status) => current + "_" + status.ID + "_"))
.Key ?? currentValueText;
if (!string.IsNullOrEmpty(currentValueText))
{
currentValue = new MvcHtmlString("<b>" + currentValueText + "</b>");
}
else
{
var status = allStatuses.SingleOrDefault(i => currentStatusIds == "_" + i.ID + "_");
currentValue = status != null
? MFCUI.Image(status.Title, "/MFC/Items/STAT/STAT16.png", showText: true, cssClassOfText: "bold", textColor: status.Color)
: new MvcHtmlString("<b style=\"color: #169; \">请选择</b>");
} var ddl = MFCUI.DropdownListHtml(page, currentValue, linksListLeft, linksListRight1, null, "200px");
return new MvcHtmlString("状态:" + ddl);
}

有一个被调用的函数在这里:

基于上篇文章中提到的“业务代码设计原则”,有几个相关的点(和上篇中的顺序有差异):
1. 所有无关业务的东西都不在这里实现
比如MFCUI.ImageLink/Link, page.ParameterOf()/MergeParameter(从URL中取出或放入某个参数的数值),MFCUI.DropdownListhtml(显示下拉框)等,都与业务无关,只调用,不散开写。
这些函数都是公共使用的函数,应该早就写好,或这次写好留待后用。
2. 不写重复代码
某些函数入AddToList()是只在这个函数中调用的,没人会复用,但在这里本身被调用多次是重复代码,则写一个Private的函数放下面就可以了:
        private static List<MvcHtmlString> AddToList(WebViewPage page, string key, string currentStatusIds, Dictionary<string, IEnumerable<Status>> linkList)
{
var linksList = new List<MvcHtmlString>();
foreach (var link in linkList)
{
var statusIds = link.Value == null ? "" : link.Value.Aggregate<Status, string>(null, (current, status) => current + "_" + status.ID + "_");
linksList.Add(link.Value == null
? null
: MFCUI.Link(link.Key, page.MergeParameter(key, statusIds), displayAsBoldText: statusIds == currentStatusIds));
}
return linksList;
}

这样封装的代码没有复用价值,但可以减少维护时的阅读量。

3. 业务代码中只描述做什么,不描述怎么做。
乍一看这一大段代码,肯定不可能看懂“是怎么实现的”,其实,这就对了。
因为这样反而分离了要做什么和怎么做两块,党只关心要做什么(比如业务发生变更)时,就只看做什么的代码;想知道怎么做的时候再说。
下篇会通过一次“业务变更”来展示如何从代码分离中受益。

关于注释

读者可能注意到代码中注释很少,培训中也经常有人问到“注释应该占多大比例”的问题,这个问题要回答好还比较复杂。
注释的多少以能看懂代码能维护为准。要看懂代码,除了注释之外,命名、布局、函数封装等都有利于读懂代码,而在L型代码结构中,代码的使用次数是另外一个帮助复用、阅读、维护代码的方法。
火星人现在基本版的文件数只有622个(cs + cshtml),代码只有7500行(仅计算C#,由VS2012自带功能统计),而上面提到的MFCUI.ImageLink/Link一共被使用过280次/220次,parameterOf/MergeParameter 79次/62次,DropdownListHtml()33次。
在这种情况下,任何新手/新人想使用它们前,第一个想到的绝不是阅读注释或文档,而是先在界面上找一个自己想要的实例做示例,然后拷贝粘贴修改参数就可以了。最初的示例是由师傅写出来的(可复用的代码也是他写的),而之后大家不断参考使用,一点点就学会了。因此这些函数不但使用时很少有注释,函数接口定义处也几乎没有注释。
但是,若L型代码结构被复用的范围超出了示例代码的范围,情况就不同了。这时候就需要写点注释了。(所以说“多少注释才好”这个问题有答案,但比较复杂)
无论如何,更有参考价值的无疑是示例而非注释。

业务逻辑代码

刚才说的全是界面上的东西,底层怎么实现筛选的呢?
其实statusIds原封不动地传递了大约5层后到达这里:
            subItems = statusIds == null
? ItemsUnder(repository, rootID, includeHidden: includeHidden)
: ItemsUnder(repository, rootID, includeHidden: includeHidden).Where(i => i.Status != null && statusIds.Contains("_" + i.Status.ID + "_"));

这是它唯一被真正使用的地方。尽管我们会对很多东西进行筛选,但都不需要写任何一行代码了,因为这行代码位于“很多东西”的底层。日后如果技术上有什么变动,就修改它就可以了。

实现业务变更

现在我们需要实现“晚于某个状态的所有工作项”筛选器(比如自动集成时,只运行“所有晚于故事板上已完成的故事,以及部署中、部署完毕的故事”的测试用例,这个是我们自己的实际需求,写本博客时还没做),下篇文章将通过增加这个新业务,来展示L型代码 结构如何使得只通过业务代码而无需阅读技术代码就进行维护变为可能的。
(写下篇文章前需要写一些代码,会晚0.5~1小时左右发布)

待续

敏捷开发松结对编程系列:L型代码结构案例StatusFiltersDropdownList(中)的更多相关文章

  1. L型代码结构案例:Link访问权限(上)

    这是松结对编程的第20篇(专栏目录). 本文探讨Link访问权限的最佳实现方法,力求外观干净且封装良好. 这些代码将位于L型代码结构(参见松结对编程系列中的定义)的下层,调用者无需理解其原理. 顺便说 ...

  2. shell编程系列26--大型脚本工具开发实战

    shell编程系列26--大型脚本工具开发实战 大型脚本工具开发实战 拆分脚本功能,抽象函数 .function get_all_group 返回进程组列表字符串 .function get_all_ ...

  3. shell编程系列21--文本处理三剑客之awk中数组的用法及模拟生产环境数据统计

    shell编程系列21--文本处理三剑客之awk中数组的用法及模拟生产环境数据统计 shell中的数组的用法: shell数组中的下标是从0开始的 array=("Allen" & ...

  4. shell编程系列19--文本处理三剑客之awk中的字符串函数

    shell编程系列19--文本处理三剑客之awk中的字符串函数 字符串函数对照表(上) 函数名 解释 函数返回值 length(str) 计算字符串长度 整数长度值 index(str1,str2) ...

  5. 《Windows核心编程系列》十三谈谈在应用程序中使用虚拟内存

    在应用程序中使用虚拟内存 Windows提供了以下三种机制对内存进行操控: 一:虚拟内存.最适合来管理大型对象数据或大型结构数组. 二:内存映射文件.最适合用来管理大型数据流,以及在同一机 器上运行的 ...

  6. 安卓APP开发简单实例 结对编程心得

    开始说起搞APP开发,自己和小伙伴的编程水平真的很低,无从下手,只有在网上找点案列,学习着怎样开发,结对编程还是面临着许多问题的,大家的水平有所差异和编程风格不同,我们用eclipse做了一个仿微信登 ...

  7. 敏捷开发与XP实践

    北京电子科技学院(BESTI) 实  验  报  告 课程: Java        班级:1352          姓名:黄伟业         学号:20135215 成绩:           ...

  8. 实验三 敏捷开发与XP实践

    实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验 ...

  9. 20145215实验三 敏捷开发与XP实践

    20145215实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 相关工具 实验步骤 (一)敏捷开发与XP 软件工程是把系统的.有序的.可量化的方法应用到软件的开发.运营和维护上的过程.软 ...

随机推荐

  1. Analyze 静态分析工具中显示 大量的CF类型指针 内存leak 问题, Core Foundation 类型指针内存泄漏

    Analyze 静态分析工具中显示 大量的CF类型指针 内存leak 问题   今天使用Analyze 看了下项目,   解决办法,项目中使用了ARC,OC的指针类型我们完全不考虑release的问题 ...

  2. 过滤HTML

    过滤HTML public static string NoHTML(string html){ string[] strArray2 = new string[] { "font" ...

  3. Dreamweaver安装jQuery插件jQuery_API.mxp

    要让Dreamweaver支持jQuery自动提示代码功能,方法很简单,下载一个插件—jQuery_API.mxp[点击下载]. 在Dreamweaver里依次选择“命令” -> “扩展管理” ...

  4. 11-17的学习总结(DOMfirstday)

    HTML: 超文本标记语言,专门定义网页内容的语言 XHTML: 严格的HTML标准 DHTML: 所有实现网页动态效果技术的统称 XML: 可扩展的标记语言,标签都是自定义的 XML语法和HTML语 ...

  5. wpf数据自动树结构

    在项目中,时常会遇到存在上下级关系的数据.在呈现方面,按照传统方法,不得不组装TreeNode之后添加到TreeView 中,已实现树形数据的显示.如果项目中需要多处使用树,毫无疑问这将存在巨大的代码 ...

  6. git+Coding.netの小试牛刀

    一.将本地项目推送到Coding中 1.在Coding中新建项目,填写项目名称和项目描述,设置属性,勾选初始化仓库

  7. 代理服务器基本知识普及代理IP使用方法!

    本文并未从专业角度进行详细讲解,而是从应用的角度出发来普及一些代理服务器的基本知识.文章明显是搜集多方资料的拼凑,而且比较老了,但往往越老的东西越接近事物的本质,更容易窥探到原理,对于刚接触的人来说, ...

  8. 【POJ2478】Farey Seque

    题意: 就是求2~n的所有欧拉函数值的和,这里就用到了快速求欧拉函数的方法.(不能暴力求了,不然必定TLE啊) 说说欧拉筛法,感觉十分机智啊~~ 对于上述代码的几个问题: 1.问:为什么i%prime ...

  9. 李洪强iOS开发之-环信02_iOS SDK 介绍及导入

    李洪强iOS开发之-环信02_iOS SDK 介绍及导入 iOS SDK 介绍及导入 iOS SDK 介绍 环信 SDK 为用户开发 IM 相关的应用提供的一套完善的开发框架.包括以下几个部分: SD ...

  10. Java_xml_Dom解析方式

    本博文为子墨原创,转载请注明出处! http://blog.csdn.net/zimo2013/article/details/12094775 1.Node准备 Node接口是整个文档对象模型的主要 ...