首页 / 资讯中心 / 文章详情

功能点估算实战:ILF/EIF计数与VAF调整到48.72

功能点估算实战:ILF/EIF计数与VAF调整到48.72 ★ FEATURED ARTICLE
简介这份文档面向软件项目管理、需求分析与软件度量方向的学习者也适合需要为项目做规模估算的开发者围绕功能点估算法给出一个可对照复盘的完整算例。案例以员工管理系统为主线从用例图与基本信息表出发逐项识别内部逻辑文件ILF、外部接口文件EIF以及外部输入、输出与查询EI、EO、EQ并说明如何依据DET、RET、FTR判定低、中、高复杂度。压缩包内仅1个docx文件约102KB篇幅集中、结构完整。正文含用例图说明、ILF/EIF与EI/EO/EQ功能点表、通用系统特性评分表以及ILF/EIF、EI、EO/EQ三类复杂度矩阵与未调整功能点对照表。作者还点出主从表合并计一个逻辑文件、标签字段不计入DET、报表标题与页码不计DET等易错细节按系统特性合计19分得出0.84的调整因子最终算得48.72个功能点。已有232人学习适合需要掌握完整估算流程与计算细节的读者按步骤演练。1. 立项评审被追问规模时拍脑袋的回答撑不过三分钟投标或立项评审的现场最容易被问住的一句是「这个系统到底多大」。回一句「大概两三个月能做完」对面通常不买账换成「48.72 个功能点」对方立刻会追问这个数是怎么来的。功能点估算解决的正是这件事把需求拆成可数的 ILF、EIF、EI、EO、EQ按 DET 和 RET 落到复杂度矩阵再乘调整因子得到一个能被第三方复核的规模数字。这套方案拿员工管理系统做完整例子从系统边界一路算到最终的 48.72把每一步的判定口径摊开讲。适合要交软件工程课设或毕设、要出一份项目管理方案或者第一次接触功能点分析想照着走一遍的人。下面按识别、计数、调整、验收的顺序往下推。2. 系统边界与 ILF/EIF 识别先分清谁存数据、谁供数据功能点估算翻车十有八九不是算错矩阵而是第一步边界就没画对。同一个工资字段放在员工管理系统里算内部逻辑文件放在财务系统里就变成外部接口文件两种算法差出好几个点。所以在数 DET 之前得先把系统边界、数据归属和纸质表单的对应关系摆清楚。这一章先用员工管理系统把边界定下来再把 ILF 和 EIF 逐个识别出来最后用一段 C# 代码把复杂度矩阵固化成可复用的查表函数后面所有计数都调它。2.1 系统边界画在员工管理与财务系统的接缝上员工管理系统的用例图里核心参与者是人事专员主用例是维护员工资料和维护部门信息。员工的一般信息、教育情况、工作经历、家属信息都在本系统内录入和保存这部分构成系统内部的数据主体。工资不由本系统产生而是由另一个财务系统提供本系统只读取工资表来做展示或统计。这条「谁产生、谁保存」的线就是系统边界员工信息和部门信息在边界内工资表在边界外。边界一旦确定后面所有判定都有了依据。员工的所属部门 ID 和部门名称虽然出现在员工表单上但部门数据本身由本系统的部门维护功能管理所以部门信息是 ILF不是 EIF。工资表则相反本系统没有维护工资的入口只能引用所以它是典型的 EIF。判断一个数据组是 ILF 还是 EIF问自己一句「本系统有没有独立的增删改入口」就够了有就是 ILF只能读就是 EIF。边界画错的代价很直接。把工资表当成 ILF会多算一个内部逻辑文件把部门信息当成 EIF会少算一个 ILF 又多算一个 EIF最终调整前的功能点总数就偏了。项目经理在评审时被质疑规模很多时候不是矩阵用错而是这一层归属没说清楚。2.2 ILF 判定员工信息为什么算 4 个 RET先看员工信息。假设员工表单上出现的字段是员工 ID、员工名称、性别、生日、婚否、所属部门 ID、所属部门名称、受教育的时间、学校名称、所学专业、工作时间、工作单位、工作部门、工作职务、家属的姓名、家属之间关系、家属年龄、家属工作单位一共 18 个数据项。从纸质档案的角度看这就是一张员工登记表表上的每个字段都是一个 DET。关键在于 RET 怎么数。员工信息不是一个平表它内部包含四组相对独立的数据员工基本信息、受教育情况、工作经历、亲属信息。每一组在数据库里通常是独立的从表但按照功能点估算的口径主表和从表只要围绕同一个业务实体、在同一个维护界面上录入就合并视为一个 ILF四个从表算四个 RET。这就是很多人第一次算会踩的坑把四张表当成四个 ILF功能点直接翻几倍。按矩阵查DET 18 个落在 1~19 区间RET 4 个落在 2~5 区间交叉得到「低」复杂度ILF 低对应 7 个未调整功能点。部门信息更简单只有部门 ID 和部门名称两个 DET、一个 RET同样落在低复杂度7 个功能点。两项 ILF 合计 14 个点。2.3 EIF 判定工资表凭什么只算 5 个点工资表来自财务系统本系统只读。它的数据项是员工 ID、员工姓名、金额、单位一共 4 个 DET内部按员工基本信息和工资信息两组来看RET 为 2。查 EIF 矩阵4 个 DET 落在 1~19、2 个 RET 落在 2~5复杂度为低EIF 低对应 5 个未调整功能点。这里有个容易起争议的点工资表里的员工 ID 和员工姓名在员工信息 ILF 里已经出现过算不算重复在功能点口径里EIF 统计的是这个外部文件自身携带的数据项跨文件重复不影响 DET 计数。真正需要去重的是 EI 里的 DET因为那涉及用户实际输入这一点在第 3 章会展开。把三项合起来员工信息 7 点、部门信息 7 点、工资表 5 点调整前 ILF 与 EIF 合计 19 个功能点。这个 19 是后面总算式的第一项先记下来。类型文件RETDET复杂度未调整 FPILF员工信息418低7ILF部门信息12低7EIF工资表24低5合计192.4 用 C# 把复杂度矩阵固化成查表函数手查矩阵在案例里只有几行真到几十个功能点的项目靠眼睛对表必然出错。通常的做法是把三张矩阵写成 C# 的查表方法输入类型、DET、RET或 FTR返回复杂度等级和对应的未调整功能点。这样每次计数都是同一套规则评审时也能直接把代码跑给对方看。public enum FpType { ILF, EIF, EI, EO, EQ } public enum Complexity { Low, Average, High } public static class FpMatrix { // 按 IFPUG 口径把 DET/RET(或 FTR) 映射到复杂度 public static Complexity GetComplexity(FpType type, int det, int retOrFtr) { switch (type) { case FpType.ILF: case FpType.EIF: // ILF/EIF: RET 1 / 2~5 / 6DET 1~19 / 20~50 / 51 if (retOrFtr 1) return det 19 ? Complexity.Low : (det 50 ? Complexity.Low : Complexity.Average); if (retOrFtr 5) return det 19 ? Complexity.Low : (det 50 ? Complexity.Average : Complexity.High); return det 19 ? Complexity.Average : Complexity.High; case FpType.EI: // EI: FTR 0~1 / 2 / 2DET 1~4 / 5~15 / 16 if (retOrFtr 1) return det 4 ? Complexity.Low : (det 15 ? Complexity.Low : Complexity.Average); if (retOrFtr 2) return det 4 ? Complexity.Low : (det 15 ? Complexity.Average : Complexity.High); return det 4 ? Complexity.Average : Complexity.High; default: // EO / EQ: FTR 0~1 / 2~3 / 4DET 1~5 / 6~19 / 20 if (retOrFtr 1) return det 5 ? Complexity.Low : (det 19 ? Complexity.Low : Complexity.Average); if (retOrFtr 3) return det 5 ? Complexity.Low : (det 19 ? Complexity.Average : Complexity.High); return det 5 ? Complexity.Average : Complexity.High; } } // 复杂度 类型 映射到未调整功能点 public static int GetUnadjustedFp(FpType type, Complexity c) { int[,] table { // Low, Average, High { 7, 10, 15 }, // ILF { 5, 7, 10 }, // EIF { 3, 4, 6 }, // EI { 4, 5, 7 }, // EO { 3, 4, 6 } // EQ }; return table[(int)type, (int)c]; } }这段代码有两个用途。一是把三张矩阵的边界条件写死避免手查时把「1~19 个 DET」和「20~50 个 DET」的分界记混二是把 ILF 与 EIF 的 RET 分档、EI 与 EO/EQ 的 FTR 分档统一在一个方法里调用方只需要传类型和两个计数。参数retOrFtr在 ILF/EIF 场景下传 RET在 EI/EO/EQ 场景下传 FTR虽然共用一个参数名但语义由FpType决定调用时注释清楚即可。矩阵数值直接来自 IFPUG 的未调整功能点对照表改口径时只改这一处不用满项目找硬编码。3. EI/EO/EQ 计算DET 和 FTR 的口径决定最终点数ILF 和 EIF 只回答了「系统存了多少数据」真正的工作量大头在事务功能上。员工管理系统里增删改查加起来贡献了 25 个 EI、9 个 EQ、5 个 EO占调整前总数的三分之二。这一章逐个拆开 EI、EQ、EO 的 DET 怎么数、FTR 怎么定重点讲清楚「用户直接输入才算 DET」这条规则最后用一张对账表把所有事务点汇总。3.1 EI 的 DET 只算用户手输的部分先看添加员工信息。员工表单上虽然有 18 个数据项但不是每个都算 EI 的 DET。员工 ID 通常是系统自动生成的员工名称旁的两个标签控件内容不由用户输入这几项要扣掉员工部分实际手输 16 个 DET。部门信息里的部门名称虽然出现在界面上但它和员工信息中的所属部门字段重复按「同一数据项在一次事务里只算一次」的规则部门部分一个 DET 都不计。工资表引用的员工 ID 和姓名同样与员工信息重复只剩金额和单位两项算数。合起来 16 2 18 个 DET。FTR 方面这次事务触及员工信息、部门信息、工资表三个文件FTR 记为 3。查 EI 矩阵18 个 DET 已经超过 16 的上限无论 FTR 落在哪一档都是高复杂度对应 6 个未调整功能点。修改员工信息的口径与添加一致同样 18 个 DET、高复杂度、6 个点。删除员工信息只涉及员工 ID 一个 DET中等复杂度4 个点。部门的三个事务都很轻添加部门只有部门名称一个有效 DET低复杂度 3 点修改部门同理 3 点删除部门只有部门 ID 一个 DET低复杂度 3 点。六项 EI 合计 6 6 4 3 3 3 25 个功能点。事务FTRDET复杂度未调整 FP添加员工信息318高6修改员工信息318高6删除员工信息31中4添加部门信息11低3修改部门信息11低3删除部门信息11低3合计253.2 EQ 和 EO 的分界是有没有经过计算查询类功能容易混因为界面上都是「点一下出一张表」。区分标准只有一条输出结果有没有经过数学公式或计算加工。没有加工、原样带出数据的是 EQ经过汇总、统计、公式推导的是 EO。查询员工信息带出员工、部门、工资三张表的内容DET 约 20 个高复杂度EQ 高对应 6 个点。查询部门信息只有部门 ID 和部门名称两个 DET低复杂度3 个点。两项 EQ 合计 9 个功能点。统计员工年薪归 EO因为它对工资做了年度汇总计算。参与的数据项是员工 ID、员工名称、年份、年薪、单位共 5 个 DET低复杂度EO 低对应 4 个点。这里要特别注意报表的标题、页码、打印时间不能算 DET它们不是业务数据只是排版信息。很多人在这一步把页眉页脚都数进去DET 虚高复杂度直接从低跳到中。事务类型FTRDET复杂度未调整 FP查询员工信息EQ320高6查询部门信息EQ12低3统计员工年薪EO25低4合计133.3 FTR 的口径由被引用的 ILF 和 EIF 个数决定FTR 是很多人算不准的第二个点。它的定义是「一次事务里被引用或被维护的内部逻辑文件与外部接口文件个数」不是数据表个数也不是字段个数。添加员工信息触及员工信息、部门信息、工资表即使员工信息内部有四个从表也只算一个 ILF所以 FTR 是 3不是 6。删除员工信息的 FTR 看起来也应该触及三个文件但实际业务里删除员工往往只校验员工 ID 是否存在部门信息和工资表只是级联展示或约束检查按严格口径可以只记 1 个 FTR。案例里统一按 3 处理是因为删除操作确实要检查工资表里有没有未结清的记录。这种判定没有绝对标准关键是同一个项目里前后一致评审时能自圆其说。3.4 用一段 C# 代码把事务点累计起来事务数量一多逐条手加容易漏。我一般会把每条事务写成一条记录用 C# 做一次汇总顺带把复杂度校验一遍输出和手工表对照。public class Transaction { public string Name; public FpType Type; public int Det; public int Ftr; } public static int SumTransactions(IEnumerableTransaction list) { int total 0; foreach (var t in list) { // 复用第 2 章的矩阵函数保证口径一致 var c FpMatrix.GetComplexity(t.Type, t.Det, t.Ftr); int fp FpMatrix.GetUnadjustedFp(t.Type, c); Console.WriteLine(${t.Name}\t{t.Type}\tDET{t.Det}\tFTR{t.Ftr}\t{c}\t{fp}); total fp; } return total; }调用时把六条 EI、两条 EQ、一条 EO 依次塞进列表输出结果应该正好是 25 9 5 39。参数Det传的是扣掉自动生成项和重复项之后的净 DETFtr传的是被引用的文件数。如果跑出来的数和手工表对不上先查 DET 有没有把标签控件算进去再查 FTR 有没有把从表当独立文件重复计数这两个是最高频的差异来源。4. 调整因子与规模收口19 分怎么变成 0.84前面算出来的 19 25 9 5 58 是未调整功能点它只反映功能数量不反映技术复杂度。同样是 58 个点一个纯内网的单机录入工具和一个要跟外部系统对接、要求高在线响应的系统工作量差得远。调整因子就是用来补这个差的。这一章把 14 项系统特性逐项打分推出 0.84 的调整系数再落到最终的 48.72并说明这个数字怎么转成工期和报价。4.1 14 项系统特性逐项打分调整因子由 14 项通用系统特性加权得出每项按 0~5 分评估影响程度。员工管理系统的打分是数据通讯 3 分因为要和财务系统做数据交换分布式数据处理 2 分部门数据可能分布在不同的库性能 0 分内部人事系统并发很低高强度配置 0 分没有特殊的硬件或部署要求交易速度 0 分不做高频交易在线数据输入 5 分这是全系统最重的特性大量表单录入最终用户效率 2 分界面要照顾非技术用户在线更新 3 分员工资料需要实时更新复杂处理 0 分没有复杂算法可复用性 3 分员工、部门模块要被其他系统调用易安装性 0 分部署环境固定易操作性 0 分已包含在最终用户效率里多场地 0 分单点部署支持变更 1 分需求相对稳定但仍有少量调整。这 14 项加起来是 3 2 0 0 0 5 2 3 0 3 0 0 0 1 19 分记为 TDI总影响度。打分时最容易虚高的是「性能」和「复杂处理」很多人一看系统里有查询就顺手打 3 分结果调整因子被抬到 0.9 以上规模凭空多出一成。打分要拿实际非功能需求做依据没有明确指标就老老实实打 0。系统特性分数判定依据数据通讯3与财务系统交换工资数据分布式数据处理2部门数据分库性能0内网低并发高强度配置0无特殊部署要求交易速度0无高频交易在线数据输入5大量表单录入最终用户效率2面向非技术用户在线更新3资料实时更新复杂处理0无复杂算法可复用性3模块被外部调用易安装性0环境固定易操作性0已计入用户效率多场地0单点部署支持变更1需求少量调整TDI 合计194.2 VAF 公式和 0.84 的来历调整因子的标准公式是 VAF 0.65 0.01 × TDI。0.65 是基准值0.01 是每分影响的权重14 项特性就算全打 5 分TDI 最高 70VAF 上限 1.35下限 0.65这个区间保证了调整不会失控。代入 TDI 19VAF 0.65 0.19 0.84。这个 0.84 意味着什么它表示该系统的技术复杂度略低于平均水平规模要往下调 16%。如果各项特性都打 0VAF 就是 0.65等于砍掉三分之一这显然不合理所以实操里很少出现全 0。反过来如果一个系统在线数据输入、性能、复杂处理都打满分VAF 到 1.1 以上也很正常。调整因子的作用是让不同技术背景的项目可比不是给规模注水。注意VAF 的 14 项特性打分要有需求文档或非功能指标做支撑评审时每一项都可能被追问依据凭印象打分是答辩翻车的重灾区。4.3 最终 48.72 和它怎么用把未调整功能点乘调整因子(19 25 9 5) × 0.84 58 × 0.84 48.72。这个数就是员工管理系统的调整后功能点规模。算出来只是第一步真正要用它做决策还得转成工作量和成本。通常的做法是取组织的历史生产率比如过往项目平均每人月完成 8~12 个功能点48.72 除以 10 大约是 4.9 人月再叠加 15%~20% 的风险缓冲落到 5.5~6 人月。如果没有历史数据可以先用行业参考值做初版项目结束后反向校准下一次估算就有自己的基线了。用 C# 做汇总和换算很直接double uafp 19 25 9 5; // 未调整功能点 double tdi 19; // 总影响度 double vaf 0.65 0.01 * tdi; // 调整因子 0.84 double afp uafp * vaf; // 调整后功能点 48.72 double productivity 10.0; // 人月/功能点取自组织历史数据 double effort afp / productivity; // 基础工作量 double buffered effort * 1.2; // 加 20% 风险缓冲 Console.WriteLine($AFP{afp:F2}, 基础工作量{effort:F2}人月, 含缓冲{buffered:F2}人月);productivity这个参数是整个换算里最需要谨慎的它必须来自本组织或同类项目的实际数据不能拍脑袋填。填高了工期压不住填低了报价没竞争力。第一次做没有基线可以在项目复盘中记录实际人月和功能点两三个项目之后这个参数就稳了。5. 避坑与排查功能点估算最容易翻车的五个点功能点方法论本身不复杂难的是执行时每个判定都有人为空间不同人算同一个系统能差出 30%。下面五条是实际项目里出现频率最高的偏差每条按现象、原因、解决三步拆开对着排查基本能把误差压到可接受范围。第一条主从表被拆成多个 ILF。现象是员工信息算出了 28 个点甚至更多ILF 数量明显偏多。原因在于把员工基本信息、教育、工作经历、家属四张从表各当成一个独立文件。解决方法是回到纸质表单视角一次录入界面覆盖的数据组算一个 ILF从表只贡献 RET 不贡献文件数。员工信息的 RET 是 4ILF 仍然是 1 个。第二条DET 里主外键重复计数。现象是 DET 数虚高复杂度从中跳到高。原因是员工 ID 既在主表出现又在从表出现被数了两次。解决方法是主键和外键在同一个 ILF 内只算一个 DET跨 ILF 不算重复。EI 里的 DET 去重规则更严同一数据项在一次事务里只计一次。第三条EI 把自动带出的字段算成用户输入。现象是添加员工算出 20 多个 DET。原因是把系统自动生成的员工 ID、根据生日算出的年龄、根据部门 ID 带出的部门名称都算进了 DET。解决方法是只数用户在界面上手工填写的字段自动计算、自动转换、标签展示的一律不计。案例里 18 个 DET 就是扣掉这些之后的净数。第四条EO 和 EQ 来回摇摆。现象是同类查询有时算 EO 有时算 EQ总数对不上。原因是没有统一的判定标准凭感觉区分。解决方法是固定一条规则输出经过汇总、统计、公式加工的算 EO原样带出数据的算 EQ。统计年薪因为做了年度汇总归 EO查询员工信息只是带出明细归 EQ。规则定下来后写进估算说明全项目统一执行。第五条调整因子凭印象打分。现象是 VAF 算出 0.95 甚至 1.0规模比实际高出一两成。原因是 14 项特性里性能、复杂处理、在线更新被顺手打了高分没有需求依据。解决方法是每项打分必须对应一条可追溯的非功能需求没有明确指标就打 0打分表附在估算文档后面备查。员工管理系统里性能和高强度配置都打 0就是因为没有对应的量化指标。提示估算完成后做一次交叉校验找另一个人独立算一遍两人结果差异超过 10% 就逐项对口径差异点往往就藏在这五条里。6. 验收与答辩三张底稿让 48.72 站得住功能点估算的交付物不是那个数字而是能支撑数字的推导过程。答辩或评审时评委不会质疑矩阵本身只会挑你的判定口径。我一般会准备三张底稿按顺序摆出来基本能覆盖八成提问。第一张是系统边界与用例图标清楚哪些数据在本系统内维护、哪些来自外部系统。这张图决定了 ILF 和 EIF 的划分边界一错后面全错所以放在最前面讲。第二张是逐项计数表把每个 ILF、EIF、EI、EO、EQ 的 DET、RET/FTR、复杂度、未调整功能点列成一张长表每一行的 DET 来源都能指回具体的表单字段。第三张是调整因子打分表14 项特性逐项给分并附判定依据。三张表加起来就是完整的推导链任何一个数字被追问都能往下追两层。答辩时最常被问的三个问题提前准备好答案。一是「为什么员工信息是 1 个 ILF 不是 4 个」答主从表合并规则从表只贡献 RET。二是「为什么添加员工是 18 个 DET 不是 20 多个」答只算用户手输、自动生成和重复字段扣除。三是「0.84 怎么来的」答 TDI 19 分逐项列出公式 0.65 0.01 × 19。这三个问题答顺了剩下的基本是细节确认。底稿内容对应答辩问题边界与用例图系统范围、外部系统接口为什么工资表是 EIF逐项计数表DET/RET/FTR、复杂度、FPDET 为什么是这个数调整因子表14 项特性打分与依据VAF 0.84 怎么算的有个血泪经验第一次做功能点答辩我只带了最终数字和一张汇总表被问到「删除员工为什么 FTR 是 3」时答不上来因为当时是照抄案例没想清楚。从那以后我每次做估算都强制把每个事务的 FTR 判定理由写进备注列哪怕只是一句「删除时需检查工资表未结清记录」。这个习惯让后面的复盘和交叉校验省了大量扯皮也让估算文档从一张纸变成能传下去的东西。希望这套结构能帮到你照着三张底稿走一遍48.72 这个数字就站得住了。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站