博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
敏捷开发“松结对编程”系列之十:L型代码结构(技术篇之一)
阅读量:2398 次
发布时间:2019-05-10

本文共 5085 字,大约阅读时间需要 16 分钟。

本文是“松结对编程”系列的第十篇。(

主题:如何用更少的代码写相同的功能,怎样的团队结构可以推进这一点。

如果你也希望只用国际先进水平的1/4代码量,就实现相同的功能,欢迎阅读本文。

本文会多次切换技术和管理两个平行线,所以结构会复杂一些。

前言

一直对代码有效性比较感兴趣,所以今天早上重新排布了功能树后,仔细计数了功能点和代码行,大致如下:

代码9883行,来自VS的统计数据(只计算CS文件),加上cshtml中的1420个分号计数(此方法低于VS的统计方法约10%),大约是11200行;

功能点740个,包含33个ILF和127操作(没有区分EI/EO/EQ,每个统一按4FP计算,会略低于标准数值)(关于功能点的计算,请参考 及其下面的4篇文章,火星人产品中未来有这个功能)。

也就是说每个功能点,需要花费15行C#代码。在QSM的网站上,C#的这个数字大约是60(),考虑到能提供这些数据(尤其是基于功能点的数据)的企业都不是等闲之辈,所以15这个数值还是很惊人的(培训课上我曾经提到过大致是19~23,但那时候没仔细整理,是个粗略值)。

代码行/功能点,也就是平均多少行代码可以实现一个功能点,是国际通行的评价编程效率有效性的方法。在MS推出C#的时候,为了证明C#的效率更高,用C#编写了Java的一个例程PetShop(也称PetStore),结果是只使用了Java代码的1/4。Java后来又予以反击,以大致相当的代码效率重写了PetShop()。

当然,后面还会提到更少的代码到底好还是不好的问题。

先解决一个基本问题:如何把代码编得更少呢?

技术手段

技术手段不是我们今天说的重点。因为技术手段受限于开发者的水平,极难一下子就提升多少;而且所从事的业务本身也会限制技术手段的发挥。

不过还是大致说几点(另外一些以后再分享):

1. 限制每个函数的规模

火星人中包含2125个Public关键字,姑且将函数的数量大致估算为2000个左右,所以每个函数内的代码,平均低于5行。

小函数有些显而易见的好处:

a. 更容易抽出可复用的部分

先看看火星人手册中提到过的这三个界面:

产生这三个界面(以及另外大约10多个类似的界面),都是下面这段代码:

private void PrepareIndexData(int rootID, string whats, string whattypes)        {            ViewBag.ItemTreeViewModel = new ItemTreeViewModel(                "查看用户故事树",                rootID, whats ?? SystemItemWhat.Story, whattypes, Product.ProductsAccessibleToUserIDs(User.Identity.Name),                showPopupOperationMenu: true,                showMoveLeftRight: true,                showMoveUpDown: true,                 enableInternalDrop: true,                subItemsTreeColumnWidth: 290);        }        [UrlLog]        public ActionResult Index(int rootID, string whats, string whattypes)        {            PrepareIndexData(rootID, whats, whattypes);            //ViewTester.IsViewTesting = true;            return View(ItemTree.ViewPath);        }        [HttpPost, UrlLog]        public ActionResult Index(int rootID, string whats, string whattypes, FormCollection collection)        {            try            {                Item.OnItemDropped(collection[MFCUI.DragHistories]);            }            catch (Exception e)            {                ModelState.ReportException(e);            }            PrepareIndexData(rootID, whats, whattypes);            return View(ItemTree.ViewPath);        }
当whattypes变化时,产生了上面的三个不同界面。

若PrepareXXXData中产生的ViewModel不同,则会产生另外10多个界面。

图中有一个不起眼的小函数叫做Item.OnItemDropped,能处理故事树(包含上面提到的多种子树)/部门树/自定义字段树/故事板/向导……等的所有拖拽,每次都是这一行代码。

b. 更易读,易维护

有时候经常会听到一种说法:“更少的代码,有时候反而很不易于理解”。

不知道大家感觉如何,反正我觉得上面这些代码,比散装的500行代码要容易读一些。如果有一天让人来维护,也更容易。

当然下一个问题:如果要动底层,会不会很难?怎么办?

其实,如果打开这几个函数,会发现他们也是一层一层形成的,并不需要真的面对500行代码;而且到了某一层,找到了要维护的地方,就无需深入下去了。这样一层一层找下去,每次维护可能只需要看50行代码(要10层调用,才会用到50行)不到,而不是把500行代码整个翻一遍。

2. 信息隐匿,暴露其用法,而隐藏其实现方法

这个好处包括:

a. 函数可以自解释

经常听到有人说:不应该写注释,应该写自解释的代码。

不过有个问题,代码要解释什么?解释自己在做什么,还是解释自己是怎么做的?如果只能选择一个,我一定会选择前者。

比如这四行代码:

try            {                Item.OnItemDropped(collection[MFCUI.DragHistories]);            }            catch (Exception e)            {                ModelState.ReportException(e);            }            PrepareIndexData(rootID, whats, whattypes);            return View(ItemTree.ViewPath);
看上去应该是说:处理拖拽行为,如果发现异常则报告,根据链接参数准备好数据,重新生成页面。

如果每个函数都是这么干干净净写的,即使我们不知道他里边怎么实现的,发生了问题,也很容易追查进去,找到具体的地方再慢慢读。

b. 更容易让新手上手

如果这个产品中,突然又要一个类似的界面,也要树形结构,也要拖拽,甚至加上Ajax操作……如果是500行代码,确定能让新手上手吗?估计很难。

但现在容易多了。一位之前从来没有编过程序的技术支持人员,在跟我学编程不到一年后(有效工时折算成5×8的模式,可能只有3~4个人月),就直接照葫芦画瓢做了2个类似界面,并帮我维护了很多其他细节问题,因为这些工作看上去更像是搭积木的活动,而不是真的要对软件、编程了如指掌。

下面就是一段他搭建的“积木代码”:

public ActionResult LinkProduct2Team(int focusedProductID = 0)        {            ViewBag.ItemTreeViewModel = new ItemTreeViewModel(                "产品-团队映射", Department.DepartmentRootID, SystemItemWhat.DEAPRTMENT, ItemWhattype.DeaprtmentDepartment + "_" + ItemWhattype.DeaprtmentTeam);             focusedProductID = focusedProductID == 0? ProductLine.ProductRootID : focusedProductID;            ViewBag.LinkItem2ItemsViewModel = new LinkItem2ItemsViewModel(                Department.DepartmentRootID, SystemItemWhat.DEAPRTMENT, ProductLine.ProductRootID,                 SystemItemWhat.Product, focusedProductID, whatTypes: ItemWhattype.DeaprtmentDepartment + "_" + ItemWhattype.DeaprtmentTeam,                 leftPadWhatTypes: ItemWhattype.ProductProductline + "_" + ItemWhattype.ProductProduct + "_" + ItemWhattype.ProductEdition);            return View(ItemTree.ViewPath);        }
为了生成树状结构,只需要第一行代码,剩下的代码,是处理树状结构的树枝行为的。

在这个界面上如果树枝被点击,将会发生一次Ajax调用,并刷新树枝的样式。我没有时间在3~4个人月教会一个从未编程的人C# + Ajax,不过他也不需要学,而只需要写下:

var ajaxLink = "/MFC/LinkItem2Items/AjaxNode?currentItemID=" + Model.ID + "&leftPadFocusedItemID=" + leftPadFocusedItemID + "&leftPadRootID=" + leftPadViewModel.LeftPadRootID + "&leftPadWhat=" + leftPadViewModel.LeftPadWhat + "&leftPadWhatTypes=" + leftPadViewModel.LeftPadWhatTypes;    MvcHtmlString link = Model.Link(outerLink: ajaxLink, updateTargetId: Model.ID.ToString(), onSuccess: "refreshAll(); ");        
@link
Ajax操作、刷新所需的js脚本会被Model.Link自动生成,而所调用的函数AjaxNode里边也只有9行代码。

所以,不需要担心新手看不懂、不会用的问题,短小而高度封装的代码,反而更容易看懂和使用。

反过来说,我们总不能因为新手看不懂,而让高手都用ABC级别的垃圾代码来编写吧?毕竟应该改变的是新手,而非高手。

其实自己看看,限制函数规模和信息隐匿是一回事情,前者导致了后来。

前面说的技术方法都不太难,但问题是为什么很多团队做不到呢?下一个问题来了:

高手可以这样写代码,新手呢?总不能要求他们也都这样吧?这个,是下篇(管理篇之一)的内容。

转载地址:http://ftbob.baihongyu.com/

你可能感兴趣的文章
XNA是一统游戏开发环境的标准?(转)
查看>>
掌上游戏机开发指南GBA探索日记(8)(转)
查看>>
CCNA的SimulatorLab命令总结(转)
查看>>
CCNA专业英文词汇红宝书---F、G、H篇(转)
查看>>
MUD是永远不会结束的,因为它就是人生(转)
查看>>
顶尖游戏关卡设计专家的秘籍宝典(转)
查看>>
DirectX图形接口指南的介绍(转)
查看>>
在D3D中实现第一人称视角控制(转)
查看>>
代码展示之----最简单的Windows程序(转)
查看>>
为什么Postfix提示“biff_notify:Connectionrefused”(转)
查看>>
md5sum(转)
查看>>
Oracle入门基本知识一点通(转)
查看>>
itpub上的ORACLE之常用FAQ V1.0(转)
查看>>
Fedora 1/ rh as 3 安装oracle 9.2.0, 并升级到9.2.0.4详细过程(转)
查看>>
SQL*Plus的简单使用之一(转)
查看>>
硬盘分区表详解(转)
查看>>
两机之间不用密码传输文件(转)
查看>>
八种防火墙产品评测(企业级防火墙)(转)
查看>>
win2k pro下可以象win98一样通过输入密码才能打开共享目录吗(转)
查看>>
文本的四种编码方式(转)
查看>>