当前位置: 首页 > news >正文

如何在一个地方建设网站营销型定制网站

如何在一个地方建设网站,营销型定制网站,拖鞋设计网站推荐,百度网站流量查询1. 导读 你们是否也有过下面的想法#xff1f; 重构一个项目还不如新开发一个项目…这代码是谁写的#xff0c;我真想… 你们的项目中是否也存在下面的问题#xff1f; 单个项目也越来越庞大#xff0c;团队成员代码风格不一致#xff0c;无法对整体的代码质量做全面的…1. 导读 你们是否也有过下面的想法 重构一个项目还不如新开发一个项目…这代码是谁写的我真想… 你们的项目中是否也存在下面的问题 单个项目也越来越庞大团队成员代码风格不一致无法对整体的代码质量做全面的掌控没有一个准确的标准去衡量代码结构复杂的程度无法量化一个项目的代码质量重构代码后无法立即量化重构后代码质量是否提升 针对上面的问题本文的主角 圈复杂度 重磅登场本文将从圈复杂度原理出发介绍圈复杂度的计算方法、如何降低代码的圈复杂度如何获取圈复杂度以及圈复杂度在公司项目的实践应用。 2. 圈复杂度 2.1 定义 圈复杂度 (Cyclomatic complexity) 是一种代码复杂度的衡量标准也称为条件复杂度或循环复杂度它可以用来衡量一个模块判定结构的复杂程度数量上表现为独立现行路径条数也可理解为覆盖所有的可能情况最少使用的测试用例数。简称 CC 。其符号为 VG 或是 M 。 圈复杂度 在 1976 年由 Thomas J. McCabe, Sr. 提出。 圈复杂度大说明程序代码的判断逻辑复杂可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。 2.2 衡量标准 代码复杂度低代码不一定好但代码复杂度高代码一定不好。 圈复杂度代码状况可测性维护成本1 - 10清晰、结构化高低10 - 20复杂中中20 - 30非常复杂低高30不可读不可测非常高 3. 计算方法 3.1 控制流程图 控制流程图是一个过程或程序的抽象表现是用在编译器中的一个抽象数据结构由编译器在内部维护代表了一个程序执行过程中会遍历到的所有路径。它用图的形式表示一个过程内所有基本块执行的可能流向, 也能反映一个过程的实时执行过程。 下面是一些常见的控制流程 3.2 节点判定法 有一个简单的计算方法圈复杂度实际上就是等于判定节点的数量再加上1。向上面提到的if else 、switch case 、 for循环、三元运算符等等都属于一个判定节点例如下面的代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21function testComplexity(*param*) {let result 1;if (param 0) {result--;}for (let i 0; i 10; i) {result Math.random();}switch (parseInt(result)) {case 1:result 20;break;case 2:result 30;break;default:result 10;break;}return result 20 ? result : result; }上面的代码中一共有1个if语句一个for循环两个case语句一个三元运算符,所以代码复杂度为 121116。另外需要注意的是 || 和  语句也会被算作一个判定节点例如下面代码的代码复杂为3 1 2 3 4 5 6 7function testComplexity(*param*) {let result 1;if (param 0 param 10) {result--;}return result; }3.3 点边计算法 1M E − N 2PE控制流图中边的数量N控制流图中的节点数量P独立组件的数目 前两个边和节点都是数据结构图中最基本的概念 P代表图中独立组件的数目独立组件是什么意思呢来看看下面两个图左侧为连通图右侧为非连通图 连通图对于图中任意两个顶点都是连通的一个连通图即为图中的一个独立组件所以左侧图中独立组件的数目为1右侧则有两个独立组件。 对于我们的代码转化而来的控制流程图正常情况下所有节点都应该是连通的除非你在某些节点之前执行了 return显然这样的代码是错误的。所以每个程序流程图的独立组件的数目都为1所以上面的公式还可以简化为 M E − N 2 。 4. 降低代码的圈复杂度 我们可以通过一些代码重构手段来降低代码的圈复杂度。 重构需谨慎示例代码仅仅代表一种思想实际代码要远远比示例代码复杂的多。 4.1 抽象配置 通过抽象配置将复杂的逻辑判断进行简化。例如下面的代码根据用户的选择项执行相应的操作重构后降低了代码复杂度并且如果之后有新的选项直接加入配置即可而不需要再去深入代码逻辑中进行改动 4.2 单一职责 - 提炼函数 单一职责原则SRP每个类都应该有一个单一的功能一个类应该只有一个发生变化的原因。 在 JavaScript 中需要用到的类的场景并不太多单一职责原则则是更多地运用在对象或者方法级别上面。 函数应该做一件事做好这件事只做这一件事。 — 代码整洁之道 关键是如何定义这 “一件事” 如何将代码中的逻辑进行抽象有效的提炼函数有利于降低代码复杂度和降低维护成本。 4.3 使用 break 和 return 代替控制标记 我们经常会使用一个控制标记来标示当前程序运行到某一状态很多场景下使用 break 和 return 可以代替这些标记并降低代码复杂度。 4.4 用函数取代参数 setField 和 getField 函数就是典型的函数取代参数如果么有 setField、getField 函数我们可能需要一个很复杂的 setValue、getValue 来完成属性赋值操作 4.5 简化条件判断 - 逆向条件 某些复杂的条件判断可能逆向思考后会变的更简单。 4.6 简化条件判断 -合并条件 将复杂冗余的条件判断进行合并。 4.7 简化条件判断 - 提取条件 将复杂难懂的条件进行语义化提取。 5. 圈复杂度检测方法 5.1 eslint规则 eslint提供了检测代码圈复杂度的rules: 我们将开启 rules 中的 complexity 规则并将圈复杂度大于 0 的代码的 rule severity 设置为 warn 或 error 。 1 2 3 4 5 6rules: {complexity: [warn,{ max: 0 }] }这样 eslint 就会自动检测出所有函数的代码复杂度并输出一个类似下面的 message。 1 2 3 4Method testFunc has a complexity of 12. Maximum allowed is 0 Async function has a complexity of 6. Maximum allowed is 0. ... 5.2 CLIEngine 我们可以借助 eslint 的 CLIEngine 在本地使用自定义的 eslint 规则扫描代码并获取扫描结果输出。 初始化 CLIEngine  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15const eslint require(eslint);const { CLIEngine } eslint;const cli new CLIEngine({parserOptions: {ecmaVersion: 2018,},rules: {complexity: [error,{ max: 0 }]} });使用 executeOnFiles 对指定文件进行扫描并获取结果过滤出所有 complexity 的 message 信息。 1 2 3 4 5 6 7 8 9 10 11const reports cli.executeOnFiles([.]).results;for (let i 0; i reports.length; i) {const { messages } reports[i];for (let j 0; j messages.length; j) {const { message, ruleId } messages[j];if (ruleId complexity) {console.log(message);}} }5.3 提取message 通过 eslint 的检测结果将有用的信息提取出来先测试几个不同类型的函数看看 eslint 的检测结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17function func1() {console.log(1); }const func2 () {console.log(2); };class TestClass {func3() {console.log(3);} }async function func4() {console.log(1); }执行结果 1 2 3 4Function func1 has a complexity of 1. Maximum allowed is 0. Arrow function has a complexity of 1. Maximum allowed is 0. Method func3 has a complexity of 1. Maximum allowed is 0. Async function func4 has a complexity of 1. Maximum allowed is 0.可以发现除了前面的函数类型以及后面的复杂度其他都是相同的。 函数类型 Function 普通函数Arrow function  箭头函数Method  类方法Async function  异步函数 截取方法类型 1 2 3 4 5 6const REG_FUNC_TYPE /^(Method |Async function |Arrow function |Function )/g;function getFunctionType(message) {let hasFuncType REG_FUNC_TYPE.test(message);return hasFuncType RegExp.$1; }将有用的部分提取出来 1 2 3 4 5 6 7const MESSAGE_PREFIX Maximum allowed is 1.; const MESSAGE_SUFFIX has a complexity of ;function getMain(message) {return message.replace(MESSAGE_PREFIX, ).replace(MESSAGE_SUFFIX, ); } 提取方法名称 1 2 3 4 5function getFunctionName(message) {const main getMain(message);let test /([a-zA-Z0-9_$])/g.test(main);return test ? RegExp.$1 : *; }截取代码复杂度 1 2 3 4 5function getComplexity(message) {const main getMain(message);(/(\d)\./g).test(main);return RegExp.$1; }除了 message 还有其他的有用信息 函数位置获取 messages 中的 line 、column 即函数的行、列位置当前文件名称reports 结果中可以获取当前扫描文件的绝对路径 filePath 通过下面的操作获取真实文件名1filePath.replace(process.cwd(), ).trim()复杂度等级根据函数的复杂度等级给出重构建议 圈复杂度代码状况可测性维护成本1 - 10清晰、结构化高低10 - 20复杂中中20 - 30非常复杂低高30不可读不可测非常高 圈复杂度代码状况1 - 10无需重构11 - 15建议重构15强烈建议重构 6.架构设计 将代码复杂度检测封装成基础包根据自定义配置输出检测数据供其他应用调用。 上面的展示了使用 eslint 获取代码复杂度的思路下面我们要把它封装为一个通用的工具考虑到工具可能在不同场景下使用例如网页版的分析报告、cli版的命令行工具我们把通用的能力抽象出来以 npm包 的形式供其他应用使用。 在计算项目代码复杂度之前我们首先要具备一项基础能力代码扫描即我们要知道我们要对项目里的哪些文件做分析首先 eslint 是具备这样的能力的我们也可以直接用 glob 来遍历文件。但是他们都有一个缺点就是 ignore 规则是不同的这对于用户来讲是有一定学习成本的因此我这里把手动封装代码扫描使用通用的 npm ignore 规则这样代码扫描就可以直接使用 .gitignore这样的配置文件。另外代码扫描作为代码分析的基础能力其他代码分析也是可以公用的。 基础能力 代码扫描能力复杂度检测能力…应用 命令行工具代码分析报告…7. 基础能力 - 代码扫描 本文涉及的 npm 包和 cli命令源码均可在我的开源项目 awesome-cli中查看。 awesome-cli 是我新建的一个开源项目有趣又实用的命令行工具后面会持续维护敬请关注欢迎 star。 代码扫描c-scan源码awesome-cli/conard at master · ConardLi/awesome-cli · GitHub 代码扫描是代码分析的底层能力它主要帮助我们拿到我们想要的文件路径应该满足我们以下两个需求 我要得到什么类型的文件我不想要哪些文件 7.1 使用 1 2 3 4 5 6 7 8 9 10npm i c-scan --saveconst scan require(c-scan); scan({extensions:**/*.js,rootPath:src,defalutIgnore:true,ignoreRules:[],ignoreFileName:.gitignore });7.2 返回值 符合规则的文件路径数组 7.3 参数 extensions 扫描文件扩展名默认值**/*.js rootPath 扫描文件路径默认值. defalutIgnore 是否开启默认忽略glob规则glob ignore规则为内部使用为了统一ignore规则自定义规则使用gitignore规则默认值true默认开启的 glob ignore 规则1 2 3 4 5 6 7const DEFAULT_IGNORE_PATTERNS [node_modules/**,build/**,dist/**,output/**,common_build/** ];ignoreRules 自定义忽略规则gitignore规则默认值[] ignoreFileName 自定义忽略规则配置文件路径gitignore规则默认值.gitignore指定为null则不启用ignore配置文件 7.4 核心实现 基于 glob 自定义 ignore 规则进行二次封装。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49/*** 获取glob扫描的文件列表* param {*} rootPath 跟路径* param {*} extensions 扩展* param {*} defalutIgnore 是否开启默认忽略*/ function getGlobScan(rootPath, extensions, defalutIgnore) {return new Promise(resolve {glob(${rootPath}${extensions},{ dot: true, ignore: defalutIgnore ? DEFAULT_IGNORE_PATTERNS : [] },(err, files) {if (err) {console.log(err);process.exit(1);}resolve(files);});}); }/*** 加载ignore配置文件并处理成数组* param {*} ignoreFileName */ async function loadIgnorePatterns(ignoreFileName) {const ignorePath path.resolve(process.cwd(), ignoreFileName);try {const ignores fs.readFileSync(ignorePath, utf8);return ignores.split(/[\n\r]|\n\r/).filter(pattern Boolean(pattern));} catch (e) {return [];} }/*** 根据ignore配置过滤文件列表* param {*} files * param {*} ignorePatterns * param {*} cwd */ function filterFilesByIgnore(files, ignorePatterns, ignoreRules, cwd process.cwd()) {const ig ignore().add([...ignorePatterns, ...ignoreRules]);const filtered files.map(raw (path.isAbsolute(raw) ? raw : path.resolve(cwd, raw))).map(raw path.relative(cwd, raw)).filter(filePath !ig.ignores(filePath)).map(raw path.resolve(cwd, raw));return filtered; }8. 基础能力 - 代码复杂度检测 代码复杂度检测c-complexity源码awesome-cli/code-complexity at master · ConardLi/awesome-cli · GitHub 代码检测基础包应该具备以下几个能力 自定义扫描文件夹和类型支持忽略文件定义最小提醒代码复杂度 8.1 使用 1 2 3 4npm i c-complexity --saveconst cc require(c-complexity); cc({},10);8.2 返回值 fileCount文件数量funcCount函数数量result详细结果 funcType函数类型funcName函数名称position详细位置行列号fileName文件相对路径complexity代码复杂度advice重构建议8.3 参数 scanParam 继承自上面代码扫描的参数min 最小提醒代码复杂度默认为1 9. 应用 - 代码复杂度检测工具 代码复杂度检测conard cc源码awesome-cli/conard at master · ConardLi/awesome-cli · GitHub 9.1 指定最小提醒复杂度 可以触发提醒的最小复杂度。 默认为 10通过命令 conard cc --min5 自定义 9.2 指定扫描参数 自定义扫描规则 扫描参数继承自上面的 scan param例如 conard cc --defalutIgnorefalse 10. 应用 - 代码复杂度报告 部分截图来源于我们内部的项目质量监控平台圈复杂度作为一项重要的指标对于衡量项目代码质量起着至关重要的作用。 代码复杂复杂度变化趋势 定时任务爬取代码每日的代码复杂度、代码行数、函数个数通过每日数据绘制代码复杂度和代码行数变化趋势折线图。 通过 [ 复杂度 / 代码行数 ] 或 [ 复杂度 / 函数个数 ] 的变化趋势判断项目发展是否健康。 比值若一直在上涨说明你的代码在变得越来越难以理解。这不仅使我们面临意外的功能交互和缺陷的风险由于我们在具有或多或少相关功能的模块中所面临的过多认知负担也很难重用代码并进行修改和测试。下图1 若比值在某个阶段发生突变说明这段期间迭代质量很差。下图2 复杂度曲线图可以很快的帮你更早的发现上面这两个问题发现它们后你可能需要重构代码。复杂性趋势对于跟踪你的代码重构也很有用。复杂性趋势的下降趋势是一个好兆头。这要么意味着您的代码变得更简单例如把 if-else 被重构为多态解决方案要么代码更少将不相关的部分提取到了其他模块中。下图3 代码重构后你还需要继续探索复杂度变化趋势。经常发生的事情是我们花费大量的时间和精力来重构无法解决根本原因很快复杂度又滑回了原处。下图4你可能觉得这是个例但是有研究标明在分析了数百个代码库后发现出现这种情况的频率很高。因此时刻观察代码复杂度变化趋势是有必要的。 代码复杂度文件分布 统计各复杂度分布的函数数量。 代码复杂度文件详情 计算每个函数的代码复杂度从高到低依次列出高复杂度的文件分布并给出重构建议。 实际开发中并不一定所有的代码都需要被分析例如打包产物、静态资源文件等等这些文件往往会误导我们的分析结果现在分析工具会默认忽略一些规则例如.gitignore文件、static目录等等实际这些规则还需要根据实际项目的情况去不断完善使分析结果变得更准确。 参考 加推研发质量与规范实战codescene圈复杂度那些事儿-前端代码质量系列文章二代码质量管控 – 复杂度检测详解圈复杂度
http://www.w-s-a.com/news/646821/

相关文章:

  • 保定网站建设方案维护动易网站中添加邮箱
  • 简易网站的html代码wordpress音乐html
  • 四川住房和城乡建设厅网站打不开海山网站建设
  • 深圳设计功能网站如何用html制作网站
  • 网络优化软件下载竞价排名和seo的区别
  • 龙华新区做网站中高端网站建设
  • 网站开发小图标大全手机网站设计开发
  • 网页设计设计一个网站口碑营销的优点
  • 枣庄建网站的公司唐山企业网络推广培训
  • 张家界建设企业网站学校资源网站建设方案
  • 网站制作教程书籍业务管理系统
  • 上传网站空间的建站程序怎么删除c 网站开发案例详解下载
  • 企业网站维护兼职丹阳网站优化
  • 秦皇岛网站开发公司怎么注册自己的公司
  • 写作网站哪个能得稿费绿色环保企业网站模板
  • 牡丹江网站建设定制开发安徽建设工程信息网官网入口
  • 有什么好的网站建设的书适合在家做的网站工作
  • wordpress情侣源码西安网站快速优化
  • 昆明网站建设高端定制100种班服设计图
  • 网站开发程序说明html网页制作接单
  • 企业网站货物查询怎么做制作文件的软件
  • 怎么做网站的防盗链北京门户企业网站建设
  • 网站推广的主流方法淘客网站 源码
  • 网站海外推广怎么做多用户商城系统源码教程
  • 猎头做单网站网站创建费用
  • 住房和城乡建设网站 上海自己做网站还是公众号
  • 投票网站怎么制作电商网站模板html
  • 攀枝花移动网站建设抖音广告投放平台
  • 什么是网站设计第一装修网
  • 公司网站建设一条织梦门户网站源码