关于代码规范:一文阐明何为基础设施即代码

 基础设施是软件开发过程的外围准则之一 —— 它间接负责软件应用程序的稳固运行。这种基础设施的范畴从服务器、负载平衡器、防火墙和数据库始终到简单的容器集群。 对基础设施的思考不仅要实用于生产环境,因为它们遍布整个开发过程,还包含工具和平台,如 CI/CD 平台、登台环境和测试工具。随着软件产品复杂度的减少,对这些基础设施的思考也要随之变动。为了满足 DevOps 古代疾速软件开发周期的需要,手工治理基础设施的传统办法很快就变成了一个无奈扩大的解决方案。这就是 IaC 已成为现在开发中事实上的解决方案的起因。 什么是基础设施即代码? IaC,Infrastructure as Code,基础设施即代码,是通过代码而非手动定义的基础设施的供给和治理过程。IaC 从开发人员那里拿走了大部分资源调配工作,开发人员能够执行脚本以筹备好基础设施。这样一来,应用程序部署就不会因为期待基础设施而碰壁,系统管理员也无需治理耗时的手动流程。 以下是创立 IaC 环境工作原理的步骤阐明: ●开发人员用特定于域的语言(DSL)定义配置参数。 ●指令文件被发送到主服务器、治理 API 或代码存储库。 ●IaC 平台依照开发人员的批示创立和配置基础设施。 通过将基础设施作为代码,用户不用在每次开发、测试或部署软件时都配置环境。所有基础设施参数都以称为清单的文件的模式保留。 与所有代码文件一样,清单易于重用、编辑、复制和共享,它使构建、测试、筹备和部署基础设施更快、更统一。 开发人员对配置文件进行编码,并将其存储在版本控制中。如果有人编辑了一个文件,拉取申请和代码审查工作流能够查看更改的正确性。 IaC 最佳实际 基础设施自动化的施行将须要大量的更改和重构,这对组织来说可能是相当沉重的过程。如果想防止大多数的限度,并使过渡尽可能平滑,请遵循上面的最佳实际! 为 IaC 的版本库应用 CI/CD 和品质管制 这将帮忙您放弃代码的良好品质,并从您的 DevOps 团队或开发人员那里取得疾速反馈循环(在利用更改之后)。侥幸的是,有一些测试框架,比方 Terratest for Terraform,容许咱们编写理论的测试。越早尝试用它笼罩所有内容,就越能从中受害,基础设施产生的意外问题也就越少。能够必定的是,在这里虽无奈预测应用程序谬误,但至多能够对本人的基础架构更有信念。 让你的基础设施成为模块化的代码 微服务体系结构是软件开发中的一种风行趋势,它通过开发更小、模块化的代码单元来构建软件,这些代码单元能够独立于产品的其余组件进行部署。 同样的概念也实用于 IaC。能够将基础设施合成为独自的模块或堆栈,并以自动化的形式将它们组合起来。 这种办法有如下劣势: ●首先,能够灵便管制根底构造代码各局部的拜访权限。例如,高级工程师可能不相熟或不具备基础设施配置某些局部的专业知识,通过模块化基础架构代码,就能够在高级工程师跟上进度之前,回绝他们拜访这些组件。 ●此外,模块化基础设施天然地限度了能够对配置进行的更改数量。较小的更改使 bug 更容易检测,并使您的团队更加灵便。 如果应用 IaC 来反对微服务体系结构,那么应该应用配置模板来确保基础设施扩大为大型服务器集群时的一致性。这最终将对配置服务器和指定它们应该如何交互十分有价值。 ...

March 4, 2024 · 1 min · jiezi

关于代码规范:代码签名证书常见问题解答

1、什么是代码签名证书?代码签名证书(Code Signing Certificate)是受信赖的证书颁发机构颁发给软件开发者,对其开发的可执行脚本、软件代码和内容进行数字签名的数字证书。代码签名证书用于验证开发者身份真实性、爱护代码的完整性。用户下载软件时,能通过数字签名验证软件起源可信,确认软件、代码没有被非法篡改或植入病毒,爱护用户不会被病毒、恶意代码和特务软件所侵害,也爱护了软件开发者的利益,让软件能在互联网上疾速平安地公布。 2、代码签名证书的工作原理是什么?对于代码签名证书的工作原理,次要分为签订代码和验证代码的完整性,下图能够很好的诠释: 3、代码签名证书分类有哪些?代码签名证书个别能够分为一般代码签名证书(OV代码签名证书)和EV代码签名证书。1)一般代码签名证书,须要进行电话验证和企业信息验证,验证工夫个别为1~3个工作日。2)EV代码签名证书,不仅须要进行电话验证和企业信息验证,还须要填写证书申请协定以及进行最终审核,验证工夫个别为1~5个工作日。一般代码签名证书和EV代码签名证书的区别见下图: 4、代码签名证书的作用有哪些?1)确保代码完整性,防劫持防篡改2)标识开发者身份,确保软件是来源于可信企业3)打消“未知发行商”不平安正告4)晋升软件品牌形象,建立良好的品牌信用5)显示企业信息,利于取得用户的信赖6)进步软件驳回率、下载率 5、代码签名证书利用范畴有哪些?代码签名证书在整个行业中有着宽泛的利用,微软,JavaSoft,Adobe、苹果IOS、Android等在公布软件时都会应用这个加密和签名工具。 6、代码签名证书反对哪些文件格式?代码签名证书可用于签订简直所有您能想到的文件格式,包含.exe,.ocx,.xpi,.msi,.dll和.cab等。 7、代码签名证书价格个别是多少?目前市面上的代码签名证书价格参差不齐,不同品牌、不同类型的代码签名证书价格都有所不同,个别都在千元以上。 8、代码签名证书怎么抉择?代码签名证书在抉择的时候须要留神品牌、证书类型、证书数量。对于品牌的抉择,Digicert、GlobalSign、Sectigo、等寰球可信的签发证书品牌都可。对于证书类型的抉择,一般代码签名证书和EV代码签名证书均实用于市面上大部分的软件程序,不同的是EV代码签名证书反对.sys、.cat等文件数字签名以及反对WHQL徽标认证帐户Azure AD账户注册。对于证书数量的抉择,代码签名证书在有效期内可不限次数的签名不同的软件产品,由此同一公司开发的多个软件能够用同一张代码签名证书。 9、代码签名证书怎么申请?代码签名证书申请流程次要分为4步:确认证书型号并购买→提交代码所属公司信息→验证程序代码所有权→收到Ukey并应用。 10、代码签名证书的有效期是多久?代码签名证书有效期依据不同的签发机构和证书类型而有所不同,个别有效期为1~3年。 申请代码签名证书:代码签名详情

February 26, 2024 · 1 min · jiezi

关于代码规范:CodeArts-Check代码检查服务用户声音反馈集锦5

作者:gentle_zhou 原文链接:https://bbs.huaweicloud.com/blogs/401608 CodeArts Check(原CodeCheck),是自主研发的代码查看服务。建设在华为30年自动化源代码动态查看技术积攒与企业级利用教训的积淀之上,为用户提供代码格调、通用品质与网络安全危险等丰盛的查看能力,提供全面品质报告、便捷的问题闭环解决帮忙企业无效管控代码品质,助力企业胜利:感兴趣的小伙伴能够体验下服务。 本期5个用户声音:21、曾经将问题赋予了“已解决”状态,然而为什么第二次扫描后果里还是显示了该问题? 22、那我确认不想再去批改这个缺点了,该怎么样屏蔽问题呢? 23、repo代码仓左边的代码衰弱度是什么指标?是Check提供的吗? 24、Check代码查看服务是否反对导出缺点? 25、扫描进去的BUG能不能告诉相干人员? “凝听客户并采取行动来解决他们的问题是客户胜利的第一步。这就是为什么客户之声(VoC,Voice of the Customer)是推动全公司为客户提供价值和实现客户称心的要害组成部分。包含旨在获取客户洞察,客户反馈闭环,确定产品改良优先级,进而让客户胜利和称心。” []()VOC集锦系列CodeArts Check代码查看服务用户声音反馈集锦(1) CodeArts Check代码查看服务用户声音反馈集锦(2) CodeArts Check代码查看服务用户声音反馈集锦(3) CodeArts Check代码查看服务用户声音反馈集锦(4) []()21、曾经将问题赋予了“已解决”状态,然而为什么第二次扫描后果里还是显示了该问题?用户只是在界面里将该缺点状态改为了“已解决”,然而该缺点实际上在代码层面并没有被修复,下次扫描的时候该缺点还是会显示。 []()22、那我确认不想再去批改这个缺点了,该怎么样屏蔽问题呢?如上图展现的,在相应缺点状态那抉择“疏忽问题”。 []()23、repo代码仓左边的代码衰弱度是什么指标?是Check提供的吗?是Check服务提供的;这是个对立的指标,代表以后我的项目代表的衰弱成都,跟告警影响度、告警数量、代码量都有关系。 []()24、Check代码查看服务是否反对导出缺点?反对通过工作级、我的项目级、租户级导出绝对应的缺点: 工作级 我的项目级 租户级 []()25、扫描进去的BUG能不能告诉相干人员?针对每个工作,设置-告诉治理里,能够设置服务动静或则邮件的模式,并抉择相应角色或人员,承受相干告诉。

September 20, 2023 · 1 min · jiezi

关于代码规范:CodeArts-Check代码检查服务用户声音反馈集锦4

作者:gentle_zhou 原文链接:https://bbs.huaweicloud.com/blogs/398470 CodeArts Check(原CodeCheck),是自主研发的代码查看服务。建设在华为30年自动化源代码动态查看技术积攒与企业级利用教训的积淀之上,为用户提供代码格调、通用品质与网络安全危险等丰盛的查看能力,提供全面品质报告、便捷的问题闭环解决帮忙企业无效管控代码品质,助力企业胜利:感兴趣的小伙伴能够点击>>体验下服务。 本期5个用户声音:16、“设置”里的源文件编码格局有什么作用? 17、“设置”里的自定义镜像怎么应用? 18、“设置”里的问题责任人精准匹配什么意思? 19、“设置”里的执行机有什么作用? 20、“设置”里的配置公有依赖仓扩大点有什么作用? “凝听客户并采取行动来解决他们的问题是客户胜利的第一步。这就是为什么客户之声(VoC,Voice of the Customer)是推动全公司为客户提供价值和实现客户称心的要害组成部分。包含旨在获取客户洞察,客户反馈闭环,确定产品改良优先级,进而让客户胜利和称心。” []()VOC集锦系列CodeArts Check代码查看服务用户声音反馈集锦(1) CodeArts Check代码查看服务用户声音反馈集锦(2) CodeArts Check代码查看服务用户声音反馈集锦(3) []()16、“设置”里的源文件编码格局有什么作用?在对源文件进行源码层面扫描的时候会用到。默认应用的文件编码格局为UTF-8(思考国际化和兼容性),用户也能够切换为GBK。 []()17、“设置”里的自定义镜像怎么应用?须要填入华为云SWR里的镜像链接。 p.s. 华为云SWR是一种容器镜像服务,它是一种反对容器镜像全生命周期治理的服务,提供简略易用、安全可靠的镜像治理性能,帮忙用户疾速部署容器化服务。 镜像站链接:https://mirrors.huaweicloud.com/home []()18、“设置”里的问题责任人精准匹配什么意思?针对的是将代码仓clone到check服务里的场景,如果“问题责任人精准匹配”开启,能够匹配并显示每次代码提交相干的负责人。如果不开启,仅能显示最近1次代码提交的负责人。 p.s. 开启后,会减少局部代码下载环节的时长,影响整体扫描时长。 []()19、“设置”里的执行机有什么作用?check服务会提供默认执行机,外部扫描环境,扫描配置都已装置好,反对引擎间接应用、扫描。 自定义执行机,则须要用户去租户设置-资源池治理里,创立资源池,绑定自定义执行机(须要有公网IP)。 []()20、“设置”里的配置公有依赖仓扩大点有什么作用?当用户我的项目有本人的公有依赖,须要maven编译的时候,就能够通过这个扩大点将依赖增加进来。 能够点击“扩大点治理”,之后点击“nexus repository”,填入服务扩大点信息(连贯第三方maven公有依赖仓库)。

September 20, 2023 · 1 min · jiezi

关于代码规范:CodeArts-Check代码检查服务用户声音反馈集锦3

作者: gentle_zhou 原文链接:https://bbs.huaweicloud.com/blogs/398291 CodeArts Check(原CodeCheck),是自主研发的代码查看服务。建设在华为30年自动化源代码动态查看技术积攒与企业级利用教训的积淀之上,为用户提供代码格调、通用品质与网络安全危险等丰盛的查看能力,提供全面品质报告、便捷的问题闭环解决帮忙企业无效管控代码品质,助力企业胜利:感兴趣的小伙伴能够点击>>体验下服务。 本期5个用户声音:11、Check 反对哪些编程规范? 12、CERT是什么? 13、CWE是什么?SANS是什么? 14、OWASP TOP 10是什么? 15、MISRA是什么? “凝听客户并采取行动来解决他们的问题是客户胜利的第一步。这就是为什么客户之声(VoC,Voice of the Customer)是推动全公司为客户提供价值和实现客户称心的要害组成部分。包含旨在获取客户洞察,客户反馈闭环,确定产品改良优先级,进而让客户胜利和称心。” VOC集锦系列CodeArts Check代码查看服务用户声音反馈集锦(1) CodeArts Check代码查看服务用户声音反馈集锦(2) 11、Check 反对哪些编程规范?提供了华为各大产品线多年研发经验总结进去的编程标准,同时反对CERT、CWE、OWASP TOP 10、SANS/CWE TOP 25、MISRA 5大业界支流编程规范。 12、CERT是什么?CERT是卡内基梅隆大学软件工程研究所的计算机应急响应小组,是美国国家信息基础设施爱护核心(NIPC)的一部分,负责协调美国联邦政府对网络攻击和网络威逼的响应。 而CERT编码标准,是由美国宾州软件工程学院(SEI)开发的,实用于多种语言,其目标是通过防止对安全性问题更敏感的编码构造来增强您的代码。在CERT编码框架中,将优先级计算为三个因素的乘积,并分为以下级别:L1,L2和L3。 13、CWE是什么?SANS是什么?CWE是常见弱点枚举(Common Weakness Enumeration)的缩写,在该枚举中,列出了大量对于编程谬误、软件设计谬误和软件体系结构谬误的缺点类型,这些谬误可能导致可被利用的破绽。 SANS则是美国信息安全协会(System Administration and Network Security),它与美国MITRE组织(面向美国政府提供系统工程、钻研开发和信息技术反对)单干保护CWE网站。 SANS/CWE TOP 25则是其中最危险的25个软件缺陷列表,可能导致宽泛产生过、重大的软件破绽,而这些破绽通常很容易被发现和被利用。 14、OWASP TOP 10是什么?OWASP TOP 10是一个由OWASP(Open Web Application Security Project,开放式Web应用程序平安我的项目)公布的安全漏洞列表,其中列举了10种最常见的Web应用程序安全漏洞:注入、生效身份验证和会话治理、敏感信息泄露、XML内部实体注入攻打(XXE)、存取控制中断、安全性谬误配置、跨站脚本攻打(XSS)、不平安的反序列化、应用具备已知破绽的组件、日志记录和监控有余。 15、MISRA是什么?MISRA是由汽车工业软件可靠性协会(MISRA)开发的编码标准,它是针对C和C++宽泛采纳的编码标准。 MISRA提供了一套全面的编码指南,重点是爱护应用程序免受已知的平安违规和安全漏洞。该协会将指导方针分为“规定”或“指令”。规定蕴含编码需要的残缺形容,通过这些规定能够确保代码的可读性、可维护性和可移植性。

September 19, 2023 · 1 min · jiezi

关于代码规范:深入浅出系列之代码可读性-京东云技术团队

这是“深入浅出系列”文章的第一篇,次要记录和分享程序设计的一些思维和方法论,如果读者感觉所有受用,还请“一键三连”,这是对我最大的激励。 一、陈词滥调,到底啥是可读性一句话:见名知其义。有人说好的代码必然有清晰残缺的正文,我不否定;也有人说代码即正文,是代码简洁之道的最高境界,我也不否定。但我都不齐全承受,如果照搬前者,有人会在每个办法、每个循环、每个判断都增加大量正文,对于一个表白不谨严的coder来说,代码与汉字可能词不达意;而且,一旦代码逻辑发生变化,正文改不改?对于后者,英语水平可能也就是个半吊子,动词名词不辨别,真能做到代码即正文的有多少人? 二、骂归骂,总归要硬着头皮干先来举个简略例子: public StepExitEnum doExecute(StepContext stepContext) throws Exception { String targetFilePath = this.getOriginFilePath(stepContext.getJobContext());//获取指标门路 File targetDir = new File(targetFilePath); if (!targetDir.exists()) { targetDir.mkdirs();//如果不存在目录则创立 } String encryptedFilePath = this.getEncryptedFilePath(stepContext.getJobContext());//获取加密文件门路 String fileName = this.getFileName(stepContext);//获取文件名 File[] encryptedFiles = new File(encryptedFilePath).listFiles(this.buildFilenameFilter(fileName));//过滤文件 FileEncryptor dencryptor = this.buildFileEncryptor(stepContext);//创立FileEncryptor Stream.of(encryptedFiles) .forEach(encryptFile -> { File targetFile = new File(targetFilePath, encryptFile.getName()); dencryptor.invoke(encryptFile, targetFile);//解密文件 }); return StepExitEnum.CONTINUING;}这种代码很常见,耐着性子其实也容易看懂:创立目录->读取加密文件->解密文件,就以后来说其实满足了业务需要也就能够了,但不够优雅,从长期来讲,这会产生bad smell,首先,“如果不存在目录则创立”、“获取文件名”这类正文有何意义?有可能这是coder过后的计划思路,但这里真的须要吗?它确确实实影响我的注意力了,但我没有获取到任何有价值信息;其次,若想要了解doExecute这个办法的目标,必须通读代码,而我只是想晓得它做了什么事;最初,这个办法如果某一行出问题了,那么影响范畴是整个业务流程。 如果前期须要改变,大部分人可能会减少条件判断,或是在前面持续追加代码实现,最初会导致越来越难以浏览,这其实也就是“能运行就不要动它”这个梗的本源了,因为没人能读明确它到底做了什么,但又不得不改,同时可能随同着“口吐芳香”。 三、意识后行,从一行做起那么到底该如何做呢?上面是我的一个例子: public StepExitEnum doExecute(StepContext stepContext) throws Exception { initTempFilePath(stepContext); File[] encryptedFiles = findEncryptedFiles(stepContext); dencryptFiles(encryptedFiles, stepContext); return StepExitEnum.CONTINUING;}先不管具体实现细节,是不是一眼看过之后就理解doExecute做了什么事?这个办法确实没有任何正文,是否影响浏览?其实我做的只是把先前的代码从新归类,别离放到了三个办法中,外围实现还是本来的代码,没有改变,当初浏览起来是不是顺畅了许多? ...

August 28, 2023 · 1 min · jiezi

关于代码规范:一文教你如何写出优质代码

优质代码是什么?优质代码是指那些易于了解、易于保护、可读性强、构造清晰、没有冗余、运行效率高、可复用性强、稳定性好、可扩展性强的代码。 这类代码不仅可能精确执行预期性能,同时也便于其余开发者了解和批改。 这类代码通常会遵循肯定的设计模式和编程标准,领有清晰的逻辑构造和标准的代码格局,且正文适量且失当。 优质代码该具备什么条件?1、轻量级轻量级的代码次要是指代码的复杂性低,易于了解和保护。 这个别通过缩小代码的冗余、进步代码的可读性和可维护性等伎俩来实现。例如,防止应用过多的嵌套语句,尽可能地应用简略的数据结构和算法,防止应用简单的编程语言个性等。 2、低耦合(松耦合)耦合是指代码之间的依赖关系。低耦合或者松耦合的代码是指代码之间的依赖关系尽可能地少,每一部分代码都能够独立地实现其性能。 这样能够使得代码更容易保护和批改,因为批改一部分代码不会影响到其余局部的代码。实现低耦合的办法次要有模块化设计、应用接口或者抽象类来暗藏实现细节等。 3、易替换易替换的代码是指当需要变更或者呈现更好的实现办法时,能够不便地替换掉原来的代码。 这须要代码的设计有良好的扩展性和灵活性,例如,应用接口或者抽象类来定义性能,应用设计模式来组织代码等。 4、易删除易删除的代码是指当某局部代码不再须要时,能够不便地删除掉,而不会影响到其余局部的代码。 这也须要代码的设计有良好的模块化和低耦合性。此外,还须要有良好的测试笼罩,以确保删除代码后,不会引入新的谬误。 如何写出优质代码?一、制订并恪守编码标准编码标准是一套事后设定并约定好的编程格调和代码书写规定。 这本规定指南的内容囊括了变量、函数和类的命名办法,空格和缩进的应用,正文的编写形式,以及代码构造的组织等等。其次要目标在于保障代码的一致性和易读性,以便别人能更便捷地浏览和了解代码。 举个例子,Python社区有一个十分驰名的编码标准PEP 8。PEP 8对Python代码的格局有一系列的规定,比如说,缩进应该应用4个空格,不要应用制表符;每行代码的长度不应超过79个字符;变量和函数的命名应该全副应用小写字母,并用下划线分隔单词等等。 二、写正文家喻户晓,鱼的记忆只有7秒钟,而程序员对他们写出代码的性能的记忆只有三天。 如果编程过程中不加以正文,那么在代码实现的那一刻,唯有程序员和上帝分明其真正性能。三天过后,恐怕只剩上帝明了这段代码的真正含意。 代码正文说白了就是对代码性能和实现逻辑的解释性补充,次要用于加强代码的可读性和可维护性。 它利用的场景十分明确,就是在编程过程中为代码加一个解释阐明,不便日后回顾。 然而,正文的品质并不等同于其数量,只有简洁、精准的正文才是高品质代码的标记。适度的正文如同背景乐音,反而会烦扰代码了解。因而,适当的正文策略应是仅对代码中的要害局部与简单逻辑进行注解。 除了其余惯例益处,正文还有助于疾速查找和了解之前编写的代码,从而进步代码的复用性。 三、应用有意义的命名命名和正文一样,都是程序员的大难题。 如果说正文考验的是程序员的总结能力,那么命名无疑是在考验程序员丰盛的想象力和创造力。我四周有不少灵机一动就会起奇葩名的程序员敌人,想一出是一出。写的时候自我感觉良好,感觉这个名适合或者不便,等到浏览代码时傻了眼,这都什么跟什么,为什么意大利面应该拌24号混凝土。 一个好的名字应该能精确地反映出其性能或用处,而不是随便地应用像list1或func1这样指代不明,看了就懂,下秒就忘的名字。 如果想解决命名这个难题,最好建设本人的命名规定,不论是对外部变量或全局变量,都应让人们可能高深莫测其变量含意。 四、防止应用全局变量全局变量是在程序全局范畴内定义的变量,它们能够在程序的任何处被拜访和批改。看起来很便当对吧,但如果大量应用全局变量,编程的整个环境会变得复杂且凌乱。 首先,全局变量毁坏了封装准则。封装是面向对象编程的一个重要准则,它暗藏了对象的外部细节以爱护外部环境。全局变量能够在任何中央被批改,这使得追踪和了解代码流程变得艰难。这意味着你须要记住全局变量的状态,并了解在程序的哪个局部会扭转它。 其次,全局变量导致函数之间产生隐含的耦合性。这意味着一个函数的行为可能依赖于另一个齐全不相干的函数是否批改了全局变量。代码便变得难以了解和预测。 最初,全局变量可能导致命名抵触。如果你在不同的中央应用雷同的全局变量名,你可能会意外地笼罩全局变量的值。 相比之下,应用局部变量和函数参数能使代码更加清晰和可保护。局部变量仅在函数外部存在,因而你不须要关怀它们在其余中央如何被应用或批改。函数参数能够明确地指出函数的输出和输入,使得了解和测试函数变得容易。 因而,只管全局变量在某些状况下可能是必要的,但在大多数状况下,最好尽量避免应用全局变量。如果你须要在多个函数之间共享数据,能够思考应用函数参数,返回值,或者创立一个蕴含这些数据的类。这将使你的代码更加清晰,易于了解,更容易进行测试和调试。 # 不好的实际x = 10def increment(): global x x += 1# 好的实际def increment(x): return x + 1五、尽量减少代码的反复在编程中,防止代码反复是一个十分重要的准则,通常被称为DRY准则,即"Don't Repeat Yourself"。 这意味着你应防止写入反复或类似的代码块,而是找出反复模式并创立可复用的函数或类代替。 例如,创立一个计算平均值的函数calculate_average,无论何处须要计算平均值,都能够调用此函数,而非反复编写雷同代码。 def calculate_average(numbers): return sum(numbers) / len(numbers)恪守DRY准则有三大益处: 晋升代码可读性:无反复代码让代码更易了解。缩小谬误:应用函数或类防止因批改反复代码而导致的谬误。进步生产力:一次编写,屡次应用,节省时间和精力。六、应用版本控制系统版本控制系统是一种记录文件或者我的项目的批改历史,以便未来查阅特定版本的零碎。 其中,Git是最受欢迎的版本控制系统之一,能够帮忙开发者跟踪和治理代码变动,反对多人合作。次要命令有git commit和git checkout。 git commit用于提交批改,并附加解释音讯。 当你对代码进行了批改,并心愿将这些批改成为新的“版本”时,就能够应用git commit命令。这个命令会将你的批改保留并附加一条你自行编写的音讯,以便解释此次批改的内容。通过这种形式,你能够清晰地跟踪每个版本的变动,以及进行这些变动的起因。 git checkout用于查看或回滚到晚期版本。 这个命令能够让你查看或回退到代码的晚期版本。如果你发现最新的代码存在问题,或者只是想查看晚期版本的样子,就能够应用这个命令。执行这个命令后,你的代码库将回到你抉择的那个版本的状态。 ...

August 22, 2023 · 1 min · jiezi

关于代码规范:记一次符合Google-Coding-Style的Bash脚本重构

最近我在思考这样一个问题,顺便看一下gpt对这个问题的解释。搜寻发现: 团队写代码,为什么要遵循coding guideline?一致性:编码准则确保整个团队的代码格调和格局是统一的,这使得团队成员之间更易于交换和合作。这也使得代码更容易保护和更新,因为其他人能够更轻松地了解代码。可读性:编码准则有助于进步代码的可读性。通过对代码进行格式化和正文,代码会更易于浏览和了解,从而缩小谬误和缺点,并进步代码的品质。可维护性:编码准则有助于进步代码的可维护性。通过应用统一的格局和格调,团队成员能够更轻松地了解代码,并进行更疾速的故障排除和修复。代码品质:编码准则有助于进步代码的品质。通过要求团队成员编写可读性高、可维护性强的代码,编码准则能够确保代码更加强壮、牢靠和平安。这也有助于缩小代码缺点和谬误,进步代码的可靠性和可用性。代码重用:编码准则有助于进步代码的重用性。通过编写符合标准的代码,团队成员能够更容易地将代码重用在其余我的项目中,从而进步生产力和效率。持续搜寻: 对于一个应用bash为次要语言的我的项目,业界举荐的coding guideline?应用有意义的变量名:变量名应该具备描述性,以便其他人能够轻松地了解代码。缩进:应用4个空格作为缩进,而不是制表符。正文:对代码进行正文,以解释代码的目标和性能。正文应该清晰、简洁,并且易于浏览。函数:编写短小精悍的函数,每个函数都应该具备一个特定的目标。函数应该应用有意义的名称,并且应该清晰地形容其目标和性能。错误处理:在代码中蕴含错误处理,以确保代码在遇到谬误时不会解体或产生不可预测的后果。应用双引号:在援用变量时,应用双引号而不是单引号,以确保变量扩大可能失常工作。应用全局变量:尽量避免应用全局变量,因为它们很难调试和保护。应用命令替换:应用$()语法而不是反引号 ``来执行命令替换。应用数组:应用数组来治理相干变量,而不是应用多个独自的变量。应用“set -u”:应用“set -u”来查看未定义的变量,以防止在援用未定义的变量时产生谬误。这些标准有助于进步 Bash 代码的可读性、可维护性和可靠性。而后我搜寻 "bash script style guideline",最下面的后果是: 即代码标准:https://google.github.io/styleguide/shellguide.html我仔细阅读了这份格调指南,对其中的“局部变量”的章节很感兴趣。文中说:「最好把局部变量的定义与赋值,换行实现,不要写到同一行上」,免得覆盖报错状态码。原文 Declare function-specific variables with local. Declaration and assignment should be on different lines. Ensure that local variables are only seen inside a function and its children by using local when declaring them. This avoids polluting the global name space and inadvertently setting variables that may have significance outside the function. Declaration and assignment must be separate statements when the assignment value is provided by a command substitution; as the local builtin does not propagate the exit code from the command substitution.我入手验证这个细节,发现果然如此: ...

May 25, 2023 · 2 min · jiezi

关于代码规范:良好的编程习惯都有哪些

本文首发自「慕课网」,想理解更多IT干货内容,程序员圈内热闻,欢送关注"慕课网"! 造就一个好的编程习惯,能让你整个职业生涯收益。 例如,做好正文,不便本人也不便他人读懂代码;用迷信的办法命名变量,而不是得心应手;规范化测试,而不是拖到所有程序都实现再去测试,等等。 上面是一些值得保持的好习惯,编程是个充斥创意的工作,但同时也是细节决定成败的工作,你真正工作中可能80%的工夫都在解决一些琐碎的问题。 所以,尽可能防止它们的频繁呈现,会让你的职业生涯更轻松,也能更好的迈向胜利。 一、技术层面1. 高级技巧(技术细节)1)咱们晓得在类C语言的编程语言中,int和bool是能够互相转换的。 因而 a = 1 与 a == 1 都能够作为if的判断条件。很多老手会把“=”当成“==”,而这并不会引起报错。因而这种谬误是比拟难以发现的。一个小技巧是将判断条件写成:1 == a**,这样如果误写为“=”,则会引起编译器的语法层面的报错,这样谬误就会立即被发现。 这个技巧只起到一个抛砖引玉的作用,编程语言品种繁多,但差不多每种语言里都能发现一些相似在类C语言中的这个技巧,这类技巧使用好了有时候可能节俭大量工夫。 2)长于利用位运算进步运行效率 在运算量较大的时候,长于使用位运算来代替一些一般的运算,往往能够起到进步代码效率的作用。例如,a * 2 能够写成 a << 1;再比方判断一个数字是否为奇数或偶数时,a & 1 要比 a % 2 的效率要高得多。 2. 中级技巧(代码的易读性)1)空格的应用 很多老手程序员还没有领会到一个小小的空格作用能有多大:a=b+c 和 a = b + c ——— 对计算机来说这是一回事,然而对程序员来说却是齐全两回事。当你面对成千上万行的代码要浏览时,你肯定会感激应用空格的程序员。 2)格调统一的代码 代码格调包含了代码自身的格调以及文件的命名。总之所有由你的手通过键盘写入到计算机里的货色,都应该保持一致的格调,包含文件名称、变量与函数名称、缩进等。这一点有教训的程序员肯定深有体会,统一的代码格调不仅会不便你也会不便读你代码的人。 举个简略场景,你四周亲戚朋友有个两三岁的小孩,他说了两个字“gu hu”,每一个字你都听的很分明,但因为音调和吐字的缘故很难第一工夫就了解这两个字的具体含意,通过他妈妈的翻译之后,你豁然开朗:哦,原来说的是“姑父”。这就和格调不一的代码一样,你很难弄懂它的意思,要花费大量工夫去解读敲代码的人的思维。 3)命名要有含意 这一条不须要多解释,a = 1.2 和 price = 1.2 哪种更清晰高深莫测。原则上,宁肯让变量名或者函数名长一些,也不要起含糊的或没有含意的名字。 4)学会如何写正文 什么时候用正文,这是个古老的问题,它始终没有一个特定的规范。有这样一个说法:在一个健全的代码中,正文的局部应该是代码自身的二分之一到三分之二。小慕对这种说法不是很同意,正文应该视状况而定,但这也阐明了正文的重要性。永远不要置信,只有变量名函数名起得好,就不须要正文这种舆论。 依据教训来说,在逻辑比较复杂的时候、容易踩坑的中央,正文是肯定要写的。至于每个函数是不是都要写对于函数的返回值、参数这样的正文,要具体情况具体分析。如果我的项目要求你必须写,那无需多问;而如果我的项目没有这类硬性要求,那么对于那些常常被大家应用的较为简单的函数,最好有正文。这样每个应用这个函数的人就能够通过正文很快明确如何应用这个函数。 另外,在一些函数体为空的中央,写一行正文也会起到踊跃的作用。比方: void func () {} 和 void func () ...

April 21, 2023 · 1 min · jiezi

关于代码规范:你关切的Code-Review三大问题我以业务实践作答

 近日,在极狐 TechTalk 播上,极狐(GitLab) 高级解决方案架构师杨周分享了高效 Code Review 秘籍以及 Code Review 在理论业务场景中的最佳实际,并手把手带大家基于极狐GitLab 进行了 Code Review。 以下内容整顿自本次分享,干货爆满,分为高低两期: 上期回顾代码品质问题、分支创立与评审、Git 标准、安全漏洞;这期持续剖析代码标准、Code Review 实际中大家最关注的几个问题。关注「极狐GitLab」不迷路,一起 get Code Review 小技巧吧! 一、代码标准1. 常见的代码标准问题有哪些?1.1 不同公司有不同代码标准很多公司制订了本人的代码标准,甚至是打印进去贴在墙上。Code Review 标准到底要不要去人工干预? 首先,咱们看一下这段 Java 代码,这里有 3 个问题,Java 书写标准个别要求: 类名和括号应该在同一行;函数名应该用驼峰;缩进应该用空格,而不是 tab。 1.2 不同语言的标准各不相同咱们再来看一个 Go 的代码。很多同学可能要抢答了,一眼看到这里的数据不对,底下俩空格下面是 tab?十分遗憾,这其实是对的。 大部分语言都是空格缩进,但 Go 官网要求用 tab……go fmt hello.go 会强制转换。这也是十分新鲜的做法,就是语言官网自带标准,所以大家不要带着一个语言的习惯去评审另一个语言。 1.3 魔法数字难以保护最初来看这个 PHP 代码有什么问题。这里有一个大括号换行问题,上面又有一个换行。 其实这些都是对的。PHP 很风行的标准是 PSR-2,它定义的是类前面大括号必须换行,和 Java 恰恰相反,但 if else 不换行。 大家要留神一下,不要搞得精神分裂了。 所以,这段代码超级换行没有任何问题,惟一的问题是魔法数字。if else 应用了 1 和 2 难以了解,这里应该用常量来示意。还有它的 if else 嵌套的太深了,复杂度太高,难以了解,难以保护。 ...

March 16, 2023 · 2 min · jiezi

关于代码规范:如何有效的解决代码的圈复杂度

作者:京东批发 杨学刚 背景介绍不论小型公司还是大型互联网公司,很多我的项目债台高筑,新性能开发艰难。其中一个很大的起因就是代码简单,可读性差。Sonar开发团队曾上纲上线的戏称开发人员的7宗罪,其中很要害的一条就是“复杂度”。那复杂度有没有一个明确的衡量标准,咱们又如何去解决代码的圈复杂度呢?明天我在这里和大家聊一下。 圈复杂度的计算方法咱们先来看一下圈复杂度与代码品质以及测试和保护老本之间的一个关系。 咱们能够看到当圈复杂度,在1-10之间的时候,代码是清晰,结构化的。可测试性比拟高,保护老本也比拟低。随着圈复杂度的升高,代码的情况开始好转,当大于30的时候,代码曾经逐渐变为不可读,保护老本十分高。 点边计算法那圈复杂度是如何计算的呢,罕用的第一种办法叫做点边计算法,它圈复杂度的计算形式 V(G) = E − N + 2,咱们用下边图来解释一下这个公式: 其中公式之中的E指的是控制流图中边的数量,N指的是控制流图中的节点数量。这两个图形指的就是控制流图。那咱们能够计算一下,第一个控制流图的圈复杂度是:4-4+2=2. 节点断定法除此之外圈复杂度还有一种更为直观的计算方法,因为圈复杂度实际上体现了“断定条件”的数量,所以圈复杂度实际上就是等于断定节点的数量再加上1。它的计算公式为:V (G) = P + 1 其中断定节点(P)指的是咱们罕用的分支语句。例如if语句、while语句、case语句等。 那如何来升高圈复杂度呢? 圈复杂度的罕用解决办法提炼函数接下来咱们重点介绍一些升高圈简单的办法,我通过工作中常见的代码,来表述一下,如何去升高复杂度,如果你有更好的办法,也欢送留言跟我交换。在咱们的工作中,做业务零碎的时候,通过异步音讯进行数据传递,是比拟罕用的一种形式,在咱们监听到对端系统的音讯的时候,个别会做这几件事件。判断音讯是否为空-->转换音讯为数据传输对象DTO-->进一步的判断对象的数据是否非法-->进行业务逻辑的解决。这几个典型的步骤,很多童鞋可能用右边图的形式进行解决。这个时候,如果每一个步骤的办法比较复杂的时候,这个总的办法会非常复杂,这个时候,咱们能够通过提炼办法的形式,对高内聚的操作,提炼到一个独立的办法中,来分治复杂性。 应用卫语句咱们晓得圈复杂度的一个因素就是分支语句多,咱们在写业务代码的时候,常见到这样的一种代码,if-then-else的层层嵌套。卫语句的准则是,如果某个条件极其常见,就应该独自查看该条件,并在该条件为真时,立即返回。上面是一个生产中的场景,如果记账申请落库胜利后就进行余额的操作,如果不胜利就返回失败后果。因为落库失败是不常见的,所以咱们采纳卫语句的形式,来缩小分支语句。让代码更清晰。 合并条件常常遇到一种状况,咱们对谬误的解决,须要返回给调用方,外部的错误码,为了不便快读的定位谬误会十分具体,然而对外可能会泛化这种错误码,这个时候咱们能够通过合并条件的形式,简化条件分支,来升高圈复杂度。上面是一个生产中的场景,如果记账失败,则对谬误后果进行包装解决,并返回给调用方。这个时候咱们能够将错误码合并,这里它是合并到map中,而后针对这组错误码对立进行了解决。 通过多态形式代替条件式在咱们开发中,如果是一个平台化的零碎,很多时候,有这样的需要。例如:不同的租户、不同的业务甚至不同的订单类型都会有不同的解决流程。 这个时候最简略的形式,就是通过条件分支来进行不同的解决。然而当业务繁多的时候,解决分支会显得凌乱,从而导致圈复杂度的升高,这个时候咱们通过利用多态的形式,能够无效的升高复杂度。咱们看一下下边这段代码,不同的订单类型,应用不同的解决流程,这里他应用了在枚举中实现多态的形式。咱们发现,其实他是实现了工厂模式。 替换算法简单算法会导致bug可能性的减少及可了解性/可维护性的升高,如果函数对性能要求不高,提倡应用简单明了的算法。这里我援用了重构中的一个例子,咱们能够一起看一下。这里传入一个人名的数组,如果数组中蕴含指定的名称,就立刻返回名称。 合成条件式在面对大块头的代码时,你能够通过提炼办法的形式,将它合成为多个办法。依据每个小块代码的用处,命名新的办法名。对于条件逻辑,将每个分支条件分解成新办法能够突出条件逻辑,并更分明的表白每个分支的作用。比方上面的例子中,冬季的时候商品的折扣和非夏天的商品折扣,是不同的计算方法。 这个时候,咱们能够把两种算法,提炼到两个不同的办法中. 移除管制标记有时候咱们会通过管制标记来对循环进行解决,咱们看一下这样的一段常常应用的代码,同一个数组列表中查找邪恶的人,匹配到任意一个邪恶的人后返回。这里found是管制标记,咱们可通过下边的形式去掉管制标记,来缩小一层循环,达到削减复杂度的成果。 圈复杂度的思辨那是不是当咱们检测到圈复杂度高的时候他就肯定简单呢,上面的代码是一个生产上的例子,他通过传入的MQ的名字,对MQ进行手动的暂停。这个中央实际上是能够通过mq的名称,从spring的容器中,获取bean的。这里的例子次要是让大家看到,尽管,这个分支比拟多,然而这种扁平化的构造可读性还是能够的。不过如果它做的不仅仅是一个暂停的操作,而是一个很简单的操作,这个时候,可能就须要通过提炼办法的形式进行重构。如果提炼办法重构后,这个类还是过长,那就须要咱们通过应用多态的个性,利用工厂模式等形式进行进一步的重构。如果一开始咱们就通过利用一些简单的设计模式进行重构,就会存在适度设计的弊病,使代码更不易于了解。 总结首先介绍了什么是圈复杂度,而后介绍了解决圈复杂度的几种办法。 通过圈复杂度计算的两种形式咱们能够看到,圈复杂度的外围是分支语句。那解决问题的外围就集中在如何去缩小分支语句。 不过最初咱们也看到了,实际上,只是刻板的应用圈复杂度的算法,去度量一个段代码的清晰度,有时候也是不可取的,所以咱们在重构零碎的时候,能够通过圈复杂度的工具,进行复杂度的统计,而后对复杂度高的代码,具体场景,具体分析。而不能一味的教条。 最初咱们通过思维导图来梳理一下:

February 23, 2023 · 1 min · jiezi

关于代码规范:代码质量与安全-嵌入式开发中不得不说的编码标准BarrC

来自Barr Group的编码标准Barr-C可能缩小嵌入式软件中的bug,并引入格调指南(stylistic guidelines),让保护、移植更简略。援用本文将讲述开发人员如何应用Barr-C:1018来检测用C语言编译的固件中的谬误,以及它如何与MISRA联合应用。援用龙智作为DevSecOps研发平安经营一体化解决方案供应商、Perforce受权合作伙伴,继续关注代码品质与平安畛域的动静与倒退,为您提供性能平安和规范合规当先的动态代码剖析解决方案与最佳实际参考。分割咱们,立刻理解C/C ++语言动态代码分析器Helix QAC如何帮您恪守Barr-C规定。 什么是Barr-C?Barr-C是由Barr Group开发的嵌入式C语言编码标准,致力于缩小固件中的bug数量,同时让嵌入式软件的保护、移植更简略。 BARR-C:2018指南分为两大类: 第一类:解决语言的子集,例如防止应用特定的关键字(例如“register”或“continue”)和应用相似函数的宏。第二类:与编程格调相干(例如缩进和命名约定)。第一类中的某些规定被标记为“0bug...句号(Zero Bugs…Period.)”。恪守这些规定有助于在第一工夫避免bug。 为什么Barr-C很重要?即便曾经应用了正确的工具来辨认缺点和合规性问题,开发嵌入式软件仍旧充斥着挑战。 BARR-C:2018定义了一种格调,次要是为了尽量减少编码谬误。因而,BARR-C:2018能够被视为C语言子集的第一步,实用于各种我的项目。 对于没有应用编码标准和动态剖析的状况来说,采纳BARR-C:2018会带来显著的提高。 如何实现Barr-C合规性?要想合乎BARR-C:2018,您必须强制执行所有规定。 检测不合规的代码有几种办法,例如应用非正式的代码审查或主动扫描。每条规定中都形容了倡议的施行办法。规范中的许多规定都能够应用动态剖析工具来进行主动查看,比方Helix QAC。 Barr-C与MISRA有何关系?设计要害平安零碎的开发人员都晓得,要严格遵循MISRA C:2012指南,因为合乎MISRA C:2012能确保嵌入式代码安全可靠。 BARR-C:2018不是为了与MISRA C:2012竞争而设计的,实际上,它们相容且互补。例如,某个我的项目应用MISRA C:2012,MISRA C给出的倡议是采纳和执行统一的编码(coding)格调,这就能够应用BARR-C:2018的某局部编程(programming)格调来满足。 同样的,一些要害我的项目能够先遵循Barr-C,而后顺利过渡到MISRA C。 为什么要应用Helix QAC来满足Barr-C合规性?因为Helix QAC能够帮忙您轻松恪守编码标准和指南,包含MISRA、Barr-C和其余性能平安规范。 作者简介:  吉尔·布里顿(Jill Britton)合规总监,Perforce 吉尔·布里顿在多个行业领有超过30年的嵌入式软件教训。她曾负责电信、汽车、国防和教育软件等畛域企业的软件工程师和管理者。吉尔当初是Perforce的合规总监,同时也是MISRA的委员会成员。吉尔领有纽卡斯尔大学计算机科学和统计学学士学位,以及伦敦布鲁内尔大学计算机科学硕士学位。文章起源:https://bit.ly/3DVYxoA

November 9, 2022 · 1 min · jiezi

关于代码规范:编码规范不要用参数控制代码逻辑

用参数控制代码逻辑可能是最经典的谬误编码习惯,我在公司的我的项目代码中见到过好几次相似编码,包含我自己在职业生涯初期也编写过相似的代码。什么叫参数控制代码逻辑?咱们可能常常在我的项目中看到过相似这种代码: func Worker(isA bool) { if isA { // codeBlockA } // repeatedCodeBlock}下面示例代码就叫做参数控制代码逻辑,它常常产生在咱们想复用代码的时候。然而它并不是复用代码正确的“姿态”,它是咱们代码中的“坏滋味”,为什么这么说呢?我在我本人的博客写了一点心得,具体内容请看:为什么说不要用参数控制代码逻辑

September 20, 2022 · 1 min · jiezi

关于代码规范:研发管理DevOps最佳实践之三问三答

近日,极狐(Gitlab)江狐会·北京站在极狐北京Demo Center如期发展。 会上,极狐(Gitlab)高级解决方案架构师杨周带来了《研发治理DevOps最佳实际》主题分享,解答了如下备受关注的问题: Git Flow过期之后举荐用什么?Java/VUE老我的项目如何落地代码标准?为什么不该用CI做部署,而是CD、GitOps?心愿给广泛面临这些问题的开发人员尤其是研发负责人、架构师,以及开源和DevOps的爱好者们提供一些参考。 以下内容整顿自本次分享,enjoy~ Git Flow过期了,那应该用什么呢?Git Flow是一种诞生于 2010 年的工作流,一篇名为《一个胜利的Git分支模型》的文章将Git Flow推入了开发团队的视线。但在2020 年,其作者 Vincent Driessen 发表Git Flow不适宜「继续交付」。 起因是Git Flow适宜当年多版本共存的软件,而古代软件大部分只有「最新版」,比方网站关上永远是「最新版」、App 会提醒降级而不会保护旧版本。所以Git Flow的公布分支(如 release/1.2.0)和反对分支(如 support/1.x)不再罕用。 那么问题来了:Git Flow过期了,咱们应该用什么呢? 当初业界罕用的 Git Workflow 有「繁难 Git Flow」、「GitHub Flow」、「GitLab Flow」,集体总结它们的特点如下,大家可应需选用。 繁难 Git Flow:保留 Git Flow 的双长期分支(main 和 develop)、几个长期分支(feature/xxx、bugfix/xxx、hotfix/xxx),而舍弃 release 和 support;GitHub Flow:非常简单,拉取长期分支,合并到骨干即可;适宜人少的小我的项目,比方集体开源我的项目;GitLab Flow:包含多种 Flow,比方 「Production branch with GitLab Flow」、「Environment branches with GitLab Flow」、「Release branches with GitLab Flow」。Java/VUE 老我的项目如何落地代码标准?如何做一名优良的研发工程师?从改善每一行代码开始。若有《程序猿的自我涵养》,缩进、换行、大小写、正文,应该大写加粗印在扉页上。 而教训通知咱们,标准写在纸上或者口头传播仍然不尽人意,因而,强制主动执行的主动查看代码标准(lint)出圈了。业界出名的代码标准都有配套的lint,比方 VUE 用 eslint,Java 用 checkstyle。新我的项目能够间接扫描整个目录,把查看命令放在 CI 里,即可实现在代码合并申请时强制查看标准。比方: VUE 我的项目执行 npm run lintJava 我的项目执行 ./gradlew check ...

August 29, 2022 · 1 min · jiezi

关于代码规范:CICD-使用静态代码分析工具有效补充持续集成

继续集成(Continuous Integration, CI)是DevOps自动化的要害组件之一,它指的是每次更改时构建和测试代码,而后将这些更改提交回地方存储库的自动化过程。 动态代码剖析是任何继续集成开发过程的天然补充,它能够提供对新的编码问题简直即时的反馈。 Klocwork是一款实用于 C、C++、C#、Java、JavaScript、Python和Kotlin的优良动态代码剖析和SAST工具,可辨认软件安全性、品质和可靠性问题,帮忙强制恪守规范。 如需理解更多对于Klocwork的信息,请分割Perforce受权合作伙伴——龙智。 继续集成(Continuous integration)是简化软件开发的一个重要过程。您团队所应用的流程将间接影响到软件开发工作流程的效率。 本篇文章将为您解释什么是继续集成、继续集成的工作原理以及如何胜利实现它。 什么是继续集成?继续集成是在每次进行更改时主动构建和测试代码,并将该代码提交回地方存储库的实际。 继续集成激励将开发工作分解成小块,这样就能够由团队中的每个开发人员频繁执行。 每次提交新代码都会触发一个统一的、自动化的构建和测试过程(通常称为“Pipeline 流水线”),以尽快报告在编译或测试期间发现的任何缺点。继续集成是DevOps自动化的要害组成部分之一。 继续集成有什么益处?CI的益处有: 修复bug更容易 更快地发现问题使开发人员更容易修复代码中的谬误、破绽和缺点。更重要的是,这有助于确保问题被正确地修复。这可能促成无问题的构建,并以尽可能快的速度工作。 升高项目风险 激励对代码进行小的、模块化的更改,能够使新性能更快地从版本中退出,甚至能够齐全阻止它进入主码流。这将最大限度地缩小了对其余开发人员的影响。 进步软件品质 最大化 CI 的价值意味着通过自动化在每个集成构建中检测尽可能多的问题。这减少了测试的广度、深度和可重复性,同时防止了手动测试。 进步生产力 自动化这些工作能够让开发人员腾出工夫专一于价值更高的性能开发。 继续集成和继续交付有什么区别?继续集成(CI)和继续交付(CD)都是软件开发实际,领有一个无效的CI/CD流程很重要。 CI是在构建和测试阶段应用的,而CD是在提交更改之后应用的。CD的最终目标是在代码存储库(或版本控制系统)中始终有通过验证和验证的代码筹备公布。 为什么继续集成很重要?继续集成十分重要,因为它能够减速软件开发,并帮忙开发人员防止这些常见的陷阱: 频繁的代码集成有助于打消代码抵触和代码不兼容。激励开发人员在工作时领有最新的存储库代码。升高重构复杂度。有助于辨认问题,例如内存透露。质量检验关口确保只有洁净、无效且通过测试的代码能力进入存储库。缩小存储库提交瓶颈。有了CI流水线,每个更改都被集成、测试和验证。这使提交更靠近于一个可行的候选版本。 动态剖析如何扩大继续集成?动态代码剖析是任何继续集成开发过程的天然补充。动态剖析工具对新的编码问题提供简直即时的反馈。它们能够是特定于分支的,也能够是蕴含它们的提交。您将可能应用质量检验关口来避免这些问题进入主码流——它们须要稍后解决。这进步了开发效率。 动态剖析补充了其余验证和确认技术,例如动静测试,因为: 动态剖析笼罩了所有可能的执行门路。在生命周期的晚期检测bug方面,动态剖析十分具备老本效益。它须要更少的工夫来运行。在编写动静测试之前,通过动态剖析检测到的问题还能够节俭上游的返工老本。大多数动静测试都十分依赖于代码自身。更改也会对测试产生影响。继续集成的现实动态剖析工具: 只解决批改过的代码和受影响的执行门路,而不是始终解决整个代码库。报告这些更改的影响。动态代码剖析操作源代码,而不须要理论执行代码。因而,它能够对特定工夫范畴内对提交的代码更改进行残缺剖析。此外,动态代码剖析不须要编写特定的测试用例。 为了无效地补充继续集成,动态代码剖析工具必须疾速、可扩大和自动化的。 Klocwork如何补充继续集成Klocwork实用于C、C++、C#、Java、JavaScript、Python和Kotlin,它可与构建零碎和继续集成环境相集成,其独特的差分剖析技术能为CI流水线提供最快的剖析后果。 文章起源:https://bit.ly/3vWN9V5 如需深刻理解Klocwork如何帮忙您补充继续集成,请分割Perforce受权合作伙伴——龙智:电话:400-775-5506邮箱:marketing@shdsd.com

August 12, 2022 · 1 min · jiezi

关于代码规范:不是吧连公司里的卷王写代码都复制粘贴这合理

没错,我,自己,就是那种卷心菜,就是那种想卷但卷不过他人的, 我每天吭哧吭哧写代码,写到办公区里空荡荡地只剩下我一个人,但咱们组里,就我需要写得最慢,bug写得最多,我弟常问我:“哥,别的共事加班都没你多你绩效肯定不错吧?” 但、其实是因为我写不过他人,尤其公司里那个卷王,代码写得好,还写得快,改bug测试小姐姐一提他立马响应改好。 搞得测试组那边买奶茶经常会给他捎一杯,从来不带我。 我真的、写bug写得好慢啊。 这天,卷王关掉关掉显示器,拎起电脑包甩到肩膀上就要走,通过我的工位凑过去瞄了一眼,意味深长地说“其实代码没必要本人写。” “我很多代码都复制粘贴的”他神秘一笑。 我眼睛都瞪大了:“不是吧!没想到你是这种人...” “那当然,我写代码是脑力活儿,你都快把写代码变成膂力活儿了。” “比如说,这些这些”他戳了戳我的屏幕,指着那些数据模型定义代码、接口申请代码说,“这些你写它干啥,用工具主动生成代码不好嘛?” 说完他关上某度搜了“apifox”跳入官网下载,两下就装置好了。 "看好了哈,我要开始表演了。” “你是干后端的,不少活儿都是写接口,写完接口文档再写接口的代码,费时费力,这个工具能够间接把你写的接口文档生成接口代码。 把swagger 文档导入到 Apifox外面去,或者间接在Apifox 外面写接口也行,纯可视化界面,不必学,写完再一键生成代码,就搞定了。” 咱们后端罕用的语言和框架,这里有 java 和php 下都提供了好几种框架可选,就算你用了别的偏一点的语言,这里有130多种语言和框架,也能找到适合的。 我闻到一股比拟浓的广告味,不晓得各位读者老爷看到这里有没有感觉,我心生警觉:“原来你是来拉新的,Apifox给了你多少广告费” “浮浅,我还不是为你好。“他翻了个白眼,”就你这么菜,公司裁员第一批就能有你的名单。写代码的活儿也不是这么干的” “像字段定义、实体类、接口申请、业务代码这些,很多都是固定格局和标准的,你本人写也是那个样,人家主动生成的还比你写得好。 这些反复的,不能给你带来成长的,能用工具生成就别本人做。 “你的精力要花在什么中央呢?花在梳理业务逻辑上,专一于业务代码,花在功攻克技术问题上,花在总结复盘,把踩过的坑都总结成为教训上,不要花在这些反复的没有难度的事件上。 不然你就是干到猝死,你都未必能变强。” 我心里尽管被压服了一半,嘴上还是很强硬: “能反对这么多的语言类型,那性能反对就很个别啊” 卷王杂色道:“那还真不是,垃圾软件别想入我法眼,对于单个接口来说,它能够生成接口代码,接口数据模型代码,业务代码和接口申请代码,也能生成整个我的项目的代码。” 而且,他迫近一步,“你也能够本人配置代码模板和代码格调嘛,软件性能都反对了” 这个货色,对前端也是福音,你把你写的接口分享进来给它用,它也能生成前端的代码 https://www.apifox.cn/apidoc/... 这个用起来不香吗? 我被彻底压服了,毕竟反复写那些货色也很烦。 然而,明天的我复制粘贴和今天的我复制粘贴,情绪是齐全不一样的。以前是感觉本人偷懒摸鱼搪塞,当初是感觉把反复无聊的货色交给apifox,程序员在解放全人类的生产力之前,先解放本人,这很正当。 下载链接:www.apifox.cn

August 9, 2022 · 1 min · jiezi

关于代码规范:代码合规性开发人员使用Helix-QAC的5大原因

Helix QAC是一款实用于性能平安和规范合规性畛域的当先动态代码分析器。30多年来,Helix QAC凭借其对C/C++语言深刻且精准的剖析而享誉业界,并成为须要满足刻薄合规要求的严格监管和平安要害行业的首选动态代码分析器。如需理解更多Helix QAC相干信息,请分割Perforce受权合作伙伴——龙智。 30多年来,Helix QAC(原PRQA)始终是一款值得信赖的动态剖析工具,可满足监管严格、重视平安的行业的严格合规要求。在这里,咱们将分享开发人员抉择Helix QAC的5大起因。 为什么合规性对软件开发至关重要?对于一些平安至上的行业,例如汽车、航空航天和国防、铁路和医疗设施等,合乎性能平安规范将有助于他们缩小和打消潜在危险。为了无效地执行举荐的功能性编码标准和指南,并验证合规性,龙智建议您应用行业标准化的工具——特地是动态剖析工具。 开发人员应用Helix QAC的5大起因尽管开发人员最终抉择Helix QAC的起因有很多,但以下是5个最常见的起因。 笼罩深度Helix QAC提供了深度剖析,更全面地涵盖C和C++次要编码标准的动态可执行规定。这包含但不限于以下内容:MISRA C - 100%MISRA C++ - 98%AUTOSAR C++14 - 95%CERT C - 100%CERT C++ - 100%ISO/IEC TS 17961 (C平安)- 98%High Integrity C++ (HIC++) - 89%可定制的报告Helix QAC是齐全可定制的。您能够定制布局和报告,更充沛地满足团队和我的项目的需要。此外,Helix QAC功能性工具让您可能:按我的项目和模块查看所有代码辨认问题并建设偏差查看我的项目更新和告诉调配规定配置,如MISRA、AUTOSAR c++ 14、CERT等验证代码是否合乎编码标准和行业最佳实际掂量整体代码品质在可定制的报告中监控发展趋势3.命令行接口 Helix QAC具备丰盛的命令行接口,可高度灵便地集成于: IDE,包含Microsoft Visual Studio版本控制系统,包含Perforce Helix Core自动化、继续集成构建服务器,包含Jenkins和GitLab4.低误报率Helix QAC能发现更多的缺点、破绽和合规性问题,误报更少。这有助于确保您的代码库更容易保护,并始终保持一致性。独立合规认证Helix QAC通过独立的合规认证,其中包含在ISO 9001 | TickIT plus根底程度认证,这是最宽泛采纳的规范之一,可确保满足您的要求,而且往往还超过了您的期待。此外,Helix QAC还通过了TÜV-SÜD认证,合乎平安要害零碎的次要性能平安规范,包含:ISO 26262 up to ASIL D级IEC 61508 up to SIL 4EN 50128 up to SW-SIL 4IEC 62304 up to Software Safety ClassC级IEC 60880文章起源:https://bit.ly/3axfdXT 如果您筹备亲自体验为什么Helix QAC几十年来始终是来自寰球各地开发人员确保软件合规性的首选,请立刻分割Perforce受权合作伙伴——龙智:电话:400-775-5506邮箱:marketing@shdsd.com

July 15, 2022 · 1 min · jiezi

关于代码规范:Helix-QAC更新至20221版本将持续提供高标准合规覆盖率

Helix QAC是一款实用于性能平安和规范合规性畛域的当先动态代码分析器。30多年来,Helix QAC凭借其对C/C++语言深刻且精准的剖析而享誉业界,并成为须要满足刻薄合规要求的严格监管和平安要害行业的首选动态代码分析器。 此次更新的2022.1版本,进一步扩大了动态代码剖析工具的合规率,并加强了语言反对性能等。如需理解更多Helix QAC最新性能,请分割Perforce受权合作伙伴——龙智。 Helix QAC最新版扩大了规范合规性的覆盖面,加强了语言性能反对,并进步了生产率和可用性。上面将盘点Helix QAC的最新性能个性亮点。 进无止境,Helix QAC 2022.1进一步提高合规率Helix QAC以其对C/C++语言深刻且精准的剖析享誉业界,而此次最新版本更进一步扩大了动态代码剖析的合规率,扩大了语言性能反对。Helix QAC 2022.1最显著的改良是将AUTOSAR C++14的合规率进步到了95%。此外,最新版本还做出了以下改良: MISRA C:2012合规模块已降级为可反映TC2中类别与措辞的变更。CWE的覆盖范围已拓展至“共享资源与不当同步(竞争条件)并发执行”的新音讯。C++20语言性能反对功能测试宏和std ::is constant evaluated()办法。缩小了具备大量别名对象的大型switch语句和指针的内存应用。抉择Helix QAC的理由Helix QAC通过最新版本继续提供一流合规模块覆盖率,同时判若两人地提供全面而高质量的剖析,让这个动态剖析工具博得了寰球十大汽车零部件制造商的信赖。 如需理解更多Helix QAC的全新加强性能,或者收费体验最新版本Helix QAC等,请分割Perforce受权合作伙伴——龙智:电话:400-775-5506邮箱:marketing@shdsd.com 文章起源:https://bit.ly/3HCDZ4D

June 24, 2022 · 1 min · jiezi

关于代码规范:得物质量度量之三级指标体系及其应用实践

管理学巨匠彼得 - 德鲁克曾说过:无数据不治理。 数字是人们疾速认知事物的一种无效形式。无论在生存还是工作,对事还是对人都非亲非故。碰上难以用数字形容的事物或景象必定是没有找对实用的指标和度量形式。尤其对于品质工程方面的工作,定量的出现远比定性描述更有说服力。而“三级指标体系”就是品质平台在这一年的重复打磨中,逐步清晰并成型的,可能将得物工程质量加以体系化度量的一种最佳工程实际。 为什么是三级?而不是四级或者更少?通过一级指标,直观反馈在工程化过程中某个方面的水准,具备后果性质的指标,相似“后视镜”的作用,但也具备较大滞后性且粒度较大;从而引入二级指标,对大颗粒度的一级指标进行拆解,分而治之以获取改善。因为粒度的平均水平问题,需进一步纳入三级指标才具备可操作性,以便着手改善以最终影响到后果。通常状况下,三级指标即可起到无效的下钻剖析并落入改良闭环的成果。 通过实际演绎,选取效率 、品质、稳固、资源四个方面独特构建三级指标体系。四个方面的关系可形容为品质是立命之本,稳固是无效品质流动的天然后果;业务方冀望的是有品质地(约束条件)疾速交付,且尽可能少的资源投入,其中也隐含着对资源的高效利用的诉求。 简而言之就是 “多、快、好、省” 地把活干了。三级指标别离指的是: 一级指标,即后果指标。起到“后视镜”的作用,有肯定的提早性。二级指标,即拆解指标/改善指标。对后果造成进行形成拆解或者间接能够作用以改善后果。三级指标,即改善指标。能够对应到一个或一组改良行为以获取对后果的局部改善。下文针对上述四个方面一一开展相应三级指标形成、外在逻辑及利用阐明。 一、效率效率是工程团队与业务团队沟通的热点话题,也是工程团队被诟病的高频方面。从面向高效交付的品质保障工作为切口,进行利用阐明。 效率方面,通过业务交付能力、打算保障能力以及过程协同能力自底向上逐级撑持与保障以实现高效的目标,也就是用数据出现“多”与“快”。 业务交付与响应,通过吞吐率这一相对值体现;绝对值方面采纳总需求数对照观测,而需要上线率、需要散布体现的是对打算的保障能力。指标方面反映了业务方提了多少需要,排上了多少需要,排上了多少大需要,排上的按时实现了多少。 进而下钻到协同效率体现,其依赖于估时精准性,而过程中准时提测率作为契约撑持,自动化率以及工程配套可用率影响着测试执行效率。这趴指标偏重施行过程的能力阐明,属于“肌肉”展现。解释了为什么能以及如何能保障效率。此处隐去了泛滥三级指标,以便清晰阐明(下同)。 二、品质软件的品质是开发进去的,程序(制品)一旦流转至测试流程后即被固化。这里指的是内建品质,是主观的程序品质。所有的测试行为是对这一主观品质的开掘。因而,测试行为是通过场景笼罩尽可能地迫近这一主观的品质流动。 通常状况下,设置正当的准入规范有利于提前终止不达标制品的流转,保障流程的顺畅性,将提测品质独立度量,并对提测前进行延展收集成因数据以便造成论断。 提测品质是品质门禁的卡尺,是让研发流水线中的品质流动顺畅进行的必要保障。工程上,对于品质流动的投入为被动投入,即不可少,但冀望尽可能减少投入。因而品质门禁的设置能够用绝对低成本的形式,防止不必要的过渡资源耗费,就好比给汽车上蜡前,先让洗车工把车冲洗洁净;否则,上蜡工不得不破费更多的工夫去除车上笼罩的尘土,再进入要害工序。如下图,从缺点老本曲线来看,是笔不划算的投入。 而内建品质,是一系列品质流动之后天然的形容后果。其中,缺点引入率是最间接的形容。缺点数这一相对数量,联合其形成即缺点散布,可能形容较为清晰的内建品质。 职能的作用是什么?这一灵魂拷问联合上图做必要的阐明,从价值视角论述其内在导向以及良性的促成闭环逻辑。 测试执行从价值视角切入,尽可能体现品质流动投入而产生的价值,从缺点价值、回归价值两发面着手并造成正向闭环领导测试设计。简而言之: 发现高价值缺点。联合PRD及技术实现,笼罩用户场景的同时,刻意针对技术实现形式设计用例。如幂等校验、异样解决、数据兼容等。并参考覆盖率报告增补用例,确保笼罩绝对全面性。自动化高价值的回归用例。抓住外围、稳固两个关键词,随着回归用例的一劳永逸,定期review进行无效用例增补与有效用例剔除以缩小不必要的保护老本。三、稳固稳固,个别状况下是无效品质保障的天然后果。往往由稳定性或运维团队主导,对线上进行实时监控,故障应急响应。生产故障数及其散布是次要核准指标。策略上听从:不出大问题,小问题疾速复原,将故障影响尽可能最小化,即:故障影响 = 故障重大等级 x 故障修复时长。 具体指标体现为P1P2生产故障数缩小或清零,P3P4生产故障数收敛缩小。通常故障定级规范,除了影响面作为一个维度,如资损金额、客诉量等,也会将故障复原工夫作为一个必要维度进行阶梯式定义。 另外,因为生产故障的滞后性,针对某次生产故障的复盘而产生的待办项是无效改善上述后果指标的措施,所以,待办闭环率是该方面的改善指标。此处,品质平台联手PMO,通过“迭代品质复盘会”机制周期性收集与review。 此处须要阐明的是,系统性的危险累计最终会导致某次生产故障。这是品质保障工作的“黑天鹅事件”,也是最难解释质保策略有效性的局部。品质平台听从的是品质保障和稳定性治理并行不悖,相互补充。部分的优化即便达到炉火纯青的境地,难抵一次结构性的毁坏。而生产故障驱动的系统性复盘可能领导局部优化策略的迭代,使其更加夯实与全面。所以,这是整体与部分的二元互补加强的循环过程。 四、资源提及资源,次要聚焦在人的维度进行最优配置,即:面向指标,将适合的人用在适合的的中央,并施展出效益。围绕着上面三个方面进行动静调优。 配置多少人?集中用在哪?效益如何放大?这是一个配置策略的问题,而策略自身源于指标,在一段时间内解决一个什么样的问题,应该合乎“SMART 准则”而设定与发展。 别离引入资源开测比、预实比及间接反馈职能效益的时均用例执行数与上述三个方面一一对应。其中: 资源开测比反映的是增益投入(开发)与被动投入(测试)的后果。预实比反馈的是资源利用率及无效投入状况。时均用例执行数是反映职能从事品质流动的效率程度。依赖内建品质品质、协同效率、测试策略及配套工程伎俩的综合状况。五、利用场景1:迭代“开发测试比”的下钻剖析 举例交易域某迭代(预估时)开发测试比为 4.1 : 1,是一项典型的后果指标,即一级指标。想理解其形成,从而下钻进入二级指标: 总预估时为 1659.7 人日, 开发 预估时 1333.7 人日、测试预估时 326 人日。 观测到预估时规模极其散布。下钻理解到每10人日吞吐需要个数,理解以后业务域的需要吞吐水位;联合需要维度开测比明细表,理解吞吐的具体需要及所投入资源的散布状况。准时 提测 率、自动化率、T0T1环境可用率。剖析研发过程中的顺畅水平以及测试执行的提效能力。下钻三级指标需要维度开测比明细,对应每需要最小颗粒度剖析以辨认待改良点,于“迭代品质复盘会”上落入待办项事项跟踪闭环,如下图所示: 六、利用场景2:迭代品质危险预警-“红绿灯机制” “红绿灯机制”是品质平台在研发过程数字化方面的一项无效实际。根据指标的趋势、稳定状况,对间断迭代的指标数据进行公式测算,作为“亮灯”的根据;波及有门禁品质、内建品质、协同效率三个方面的定量分析;同时,联合定性的形容进行补充阐明。从而疾速给出迭代品质危险预警,以促成上线前的危险躲避措施的制订。 进一步联合品质大盘的版本论断,以对以后某一业务域的迭代版本品质状况及危险点有疾速理解。举例交易域某迭代版本论断,如下图所示: 总结“无数据不治理”。数据是工作过程中的一种低成本沟通形式。定性的形容,故事性的解说都不如定量的摆事实来的间接与高效。 总结下三级指标指的是: 一级指标,即后果指标。起到“后视镜”的作用,有肯定的提早性。二级指标,即拆解指标/改善指标。对后果造成进行形成拆解或者间接能够作用以改善后果。三级指标,即改善指标。能够对应到一个或一组改良行为以获取对后果的局部改善。“三级指标体系”可能将工程质量加以体系化度量的一种最佳实际。历经基线建设,数据校准,特地是与体感的拟合,这也是体系打磨的主体工作,极为耗时耗力,最初是系统化收集与可视化出现,让数据实时服务于日常工作。 效率、品质、稳固、资源四个方面的关系可形容为一下三句话: 品质是职能线立命之本,稳固是无效品质流动的天然后果;累加效率这一约束条件,以实现有品质地疾速交付;同时,尽可能少的投入资源。三级指标体系是系统化的、体感拟合的、可继续积攒的研发数字化资产。随着继续的积攒与利用,能够通过部分组合解决特定阶段的工程问题,如组合冒烟通过率、冒烟缺陷率、延期提测率反馈提测品质,即门禁品质。而针对其组合指标的改良行为是被验证过的无效措施,通过总结落入一套“专家意见库”,成为团队的教训与可复制能力,甚至是企业的有形财产。 同样,联合上线前的品质评审机制,通过对测试前、中、后三个阶段,选取组合并通过算法计算而造成品质危险预警成果的“红绿灯”提醒,是数据可视化利用的一种无效尝试。 综上,设计一套无效的指标体系,并一直积攒数据,能帮忙咱们选取正当、迷信的门路实现一个个工程指标的达成。 文/布鲁斯关注得物技术,做最潮技术人! ...

June 16, 2022 · 1 min · jiezi

关于代码规范:内功修炼好代码与坏代码

要写出好代码,首先须要晋升品位。 很多软件工程师写不好代码,在评审别人的代码时也看不出问题,就是因为不足对好代码规范的意识。 当初还有太多的软件工程师认为,代码只有能够正确执行就能够了。这是一种非常低的评估规范,很多重要的方面都被忽视了。 好代码的个性 好代码具备以下个性: 1. 鲁棒(Solid and Robust) 代码不仅要被正确执行,咱们还要思考对各种谬误状况的解决,比方各种零碎调用和函数调用的异常情况,零碎相干组件的异样和谬误。 对很多产品级的程序来说,异样和错误处理的逻辑占了很大比例。 2. 高效(Fast) 程序的运行应应用尽量少的资源。资源不仅仅包含CPU,还可能包含存储、I/O等。 设计高效的程序,会使用到数据结构和算法方面的常识,同时要思考到程序运行时的各种约束条件。 3. 简洁(Maintainable and Simple) 代码的逻辑要尽量扼要易懂,代码要具备很好的可维护性。对于同样的指标,可能应用简略分明的办法达成,就不要应用简单艰涩的办法。 “大道至简”,是否把简单的问题用简略的形式实现进去,这是一种编程程度的体现。 4. 简短(Small) 在某种意义上,代码的复杂度和保护老本是和代码的规模间接相干的。在实现同样性能的时候,要尽量将代码写得简短一些。 简洁高于简短。这里要留神,某些人为了能把代码写得简短,应用了一些艰涩难懂的形容形式,升高了代码的可读性。这种形式是不可取的。 5. 可测试(Testable) 代码的正确性要通过测试来保障,尤其是在麻利的场景下,更须要依赖可主动回归执行的测试用例。 在代码的设计中,要思考如何使代码可测、易测。一个比拟好的实际是应用TDD(Test-Driven Development,测试驱动开发)的办法,这样在编写测试用例的时候会很快发现代码在可测试性方面的问题。 6. 共享(Re-Usable) 大量的程序实际上都应用了相似的框架或逻辑。因为目前开源代码的大量遍及,很多性能并不需要反复开发,只进行援用和应用即可。 在一个组织外部,应激励共享和重用代码,这样能够无效升高代码研发的老本,并晋升代码的品质。 实现代码的共享,不仅须要在意识方面晋升,还须要具备相干的能力(如编写独立、高质量的代码库)及相干基础设施的反对(如代码搜寻、代码援用机制)。 7. 可移植(Portable) 某些程序须要在多种操作系统下运行,在这种状况下,代码的可移植性成为一种必须的能力。 要让代码具备可移植性,须要对所运行的各种操作系统底层有充沛的了解和对立形象。个别会应用一个适配层来屏蔽操作系统底层的差别。 一些编程语言也提供了多操作系统的可移植性,如很多基于Python语言、Java语言、Go语言编写的程序,都能够跨平台运行。 8. 可观测(Observable) / 可监控(Monitorable) 面对目前大量存在的在线服务(Online Service)程序,须要具备对程序的运行状态进行粗疏而继续监控的能力。 这要求在程序设计时就提供相干的机制,包含程序状态的收集、保留和对外输入。 9. 可运维(Operational) 可运维曾经成为软件研发流动的重要组成部分,可运维重点关注老本、效率和稳定性三个方面。 程序的可运维性和程序的设计、编写严密相干,如果在程序设计阶段就没有思考可运维性,那么程序运行的运维指标则难以达成。 10. 可扩大(Scalable and Extensible) 可扩大蕴含“容量可扩大”(Scalable)和“性能可扩大”(Extensible)两方面。 在互联网公司的零碎设计中,“容量可扩大”是重要的设计指标之一。零碎要尽量反对通过减少资源来实现容量的线性进步。 疾速响应需要的变动,是互联网公司的另外一个重要挑战。可思考应用插件式的程序设计形式,以包容将来可能新增的性能,也可思考应用相似Protocol Buffer 这样的工具,反对对协定新增字段。 以上十条规范,如果要记住,可能有些艰难。咱们能够把它们演绎为四个方面,见表1。 表1  对一流代码个性的汇总分类 坏代码的例子 对于好代码,下面介绍了一些个性,本节也给出坏代码(Bad Code)的几个例子。对于坏代码,本书没有做系统性总结,只是心愿通过以下这些例子的展现让读者对坏代码有直观的感觉。 1. 不好的函数名称(Bad Function Name) 如do(),这样的函数名称没有多少信息量;又如myFunc(),这样的函数名称,集体色调过于强烈,也没有足够的信息量。 2. 不好的变量名称(Bad Variable Name) ...

June 6, 2022 · 1 min · jiezi

关于代码规范:基础设施即代码你需要知道的一切

 基础设施是软件开发过程的外围准则之一 —— 它间接负责软件应用程序的稳固运行。这种基础设施的范畴从服务器、负载平衡器、防火墙和数据库始终到简单的容器集群。 对基础设施的思考不仅要实用于生产环境,因为它们遍布整个开发过程,还包含工具和平台,如 CI/CD 平台、登台环境和测试工具。随着软件产品复杂度的减少,对这些基础设施的思考也要随之变动。为了满足 DevOps 古代疾速软件开发周期的需要,手工治理基础设施的传统办法很快就变成了一个无奈扩大的解决方案。这就是 IaC 已成为现在开发中事实上的解决方案的起因。 什么是基础设施即代码? IaC,Infrastructure as Code,基础设施即代码,是通过代码而非手动定义的基础设施的供给和治理过程。IaC 从开发人员那里拿走了大部分资源调配工作,开发人员能够执行脚本以筹备好基础设施。这样一来,应用程序部署就不会因为期待基础设施而碰壁,系统管理员也无需治理耗时的手动流程。 以下是创立 IaC 环境工作原理的步骤阐明: ●开发人员用特定于域的语言(DSL)定义配置参数。 ●●指令文件被发送到主服务器、治理 API 或代码存储库。 ●IaC 平台依照开发人员的批示创立和配置基础设施。 通过将基础设施作为代码,用户不用在每次开发、测试或部署软件时都配置环境。所有基础设施参数都以称为清单的文件的模式保留。 与所有代码文件一样,清单易于重用、编辑、复制和共享,它使构建、测试、筹备和部署基础设施更快、更统一。 开发人员对配置文件进行编码,并将其存储在版本控制中。如果有人编辑了一个文件,拉取申请和代码审查工作流能够查看更改的正确性。 IaC 最佳实际 基础设施自动化的施行将须要大量的更改和重构,这对组织来说可能是相当沉重的过程。如果想防止大多数的限度,并使过渡尽可能平滑,请遵循上面的最佳实际! 为 IaC 的版本库应用 CI/CD 和品质管制 这将帮忙您放弃代码的良好品质,并从您的 DevOps 团队或开发人员那里取得疾速反馈循环(在利用更改之后)。侥幸的是,有一些测试框架,比方 Terratest for Terraform,容许咱们编写理论的测试。越早尝试用它笼罩所有内容,就越能从中受害,基础设施产生的意外问题也就越少。能够必定的是,在这里虽无奈预测应用程序谬误,但至多能够对本人的基础架构更有信念。 让你的基础设施成为模块化的代码 微服务体系结构是软件开发中的一种风行趋势,它通过开发更小、模块化的代码单元来构建软件,这些代码单元能够独立于产品的其余组件进行部署。 同样的概念也实用于 IaC。能够将基础设施合成为独自的模块或堆栈,并以自动化的形式将它们组合起来。 这种办法有如下劣势: ●首先,能够灵便管制根底构造代码各局部的拜访权限。例如,高级工程师可能不相熟或不具备基础设施配置某些局部的专业知识,通过模块化基础架构代码,就能够在高级工程师跟上进度之前,回绝他们拜访这些组件。 ●此外,模块化基础设施天然地限度了能够对配置进行的更改数量。较小的更改使 bug 更容易检测,并使您的团队更加灵便。 如果应用 IaC 来反对微服务体系结构,那么应该应用配置模板来确保基础设施扩大为大型服务器集群时的一致性。这最终将对配置服务器和指定它们应该如何交互十分有价值。 ...

May 16, 2022 · 1 min · jiezi

关于代码规范:约束前端项目中的目录和文件名

好的目录设计架构就胜利了一半 --- 如何束缚我的项目中的目录和文件名编程中命名标准有: camelCase (驼峰命名法)PascalCase (帕斯卡命名法,又名大驼峰命名法)snake_case (下划线命名法)kebab-case (中划线命名法)Hungarian notation(匈牙利命名法 - 一个非常零碎又古老的命名标准)背景入职后接了个新的模块需要,笔者能够自在地创立代码文件目录和文件。上线前回看了下代码,我滴老天爷一会儿大写,一会小写,一会驼峰,之前我如同没这么轻易。为啥之前我没乱写呢?答案是有 CI、CD流水线卡控,不符合规范的代码无奈进 master。 问题代码的文件目录和文件命名短少束缚会导致代码横蛮成长。有人说:好的目录设计架构就胜利了一半。 计划通过正则匹配文件门路。问题来了:我既不会正则也不会获取文件门路。找找工具吧,于是我找到了 ls-lint。 https://ls-lint.org/ ls-lint: ls-lint is an extremely fast file and directory name linter which provides a simple and fast way to bring some structure to your project directories以前端为例,介绍下应用形式: 增加依赖npm install @ls-lint/ls-lint # local增加配置文件.ls-lint.yml ls: src: .js: kebab-case .ts: kebab-case .d.ts: kebab-case .vue: kebab-caseignore: - .git - node_modulesls-lint 的配置非常灵活,能够依照后缀名和子目录别离设置规定。规定包含:lowercase、camelcase、pascalcase、snakecase、screamingsnakecase、regex 执行命令npx @ls-lint/ls-lint 执行机会Git Hook 的 pre-commit 阶段能够让开发者及时感知、及时批改流水线上线前某个阶段触发命令,防止开发者本地应用 --no-verify 绕过,双重保险。 ...

April 6, 2022 · 1 min · jiezi

关于代码规范:Google-的工程实践指南-上代码审核指南

原文由知無涯发表于TesterHome社区,点击原文链接可与作者间接交换。在代码审核的长期实践中,Google总结出了最佳实际,并在此基础上整顿出了这些倡议。整篇文档各局部的连接性并不大,在浏览时,你能够选取本人感兴趣的局部,而不用按程序浏览全文。当然,咱们仍旧倡议你按程序通读全篇,你会发现这份文档对你十分有用。 一. 代码审核的规范规范代码审核的目标是为了保障代码库中的代码品质继续改良,代码审核的工具和流程都是为了实现这个目标而设计。 为了达到目标,咱们须要权衡得失。 首先,开发人员必须能在工作上 获得停顿 。如果从没向代码库提交代码,那么代码库就不会改善。同时,如果审核者让开发者在提交代码时变得很艰难,那么开发者不得不破费大量的精力解决审核评论,没有能源在将来的提交中改良代码品质。 另一方面,审核者有责任确保提交者的代码品质。随着工夫的推移,代码库的品质不会升高。这有点辣手,冰冻三尺非一日之寒,代码库品质的升高是随着每次代码提交的渺小升高累积而成的,尤其当团队面临很大的工夫压力时,为了实现工作,他们不得不采取一些长期计划。 另外,代码审核者对他们审核的代码有所有权和责任,他们有任务确保代码库是统一的、可保护的,所有这些内容可参见代码审核过程中要看些什么?(What to Look For In a Code Review)这篇文章。 因而,咱们心愿在代码审核中能遵循这条准则: 个别状况下,如果代码提交者的代码能显著进步代码库的品质,那么审核者就应该批准它,只管它并不完满。 这是代码审核中所有规定的 最高准则。 当然,也有例外。例如,一次提交蕴含了零碎中不应退出的性能,那么审核者就不应批准它,即便它设计得十分完满。 还有一个关键点,那就是世上基本就没有“完满”的代码——只有 更好 的代码。审核者不应该要求代码提交者在每个细节都写得很完满。审核者应该做好批改工夫与批改重要性之间的均衡。无需谋求完满,而应寻求 继续的改良 。假使一个 CL 可能改良零碎的可维护性、可读性,那么它不应该仅仅因为不够完满而提早数天(甚至数周)才批准提交。 咱们应该营造这种气氛:当审核者发现某些事件有更好的计划时,他能够无拘束地提出来。如果这个更好的计划并不是非改不可,能够在正文前加上:“Nit:”,让提交者明确,这段评论只是精益求精,你能够抉择疏忽。 留神:在提交代码时不应显著地 好转 代码品质,惟一的例外是 紧急情况。 领导代码审核还有一项重要的性能:能让开发者学到新常识,可能是编程语言方面的,也可能是框架方面的,或一些惯例的软件设计准则。作为审核者,如果你认为某些评论有助于开发者学到新常识,那就毫不犹豫地写下来吧。分享常识是进步代码品质的一种形式。记住,如果你的评论是纯学习相干的,与文档中提及的规范关系不大,那就最好在后面加上“Nit”,否则就意味着开发者必须在 CL 中修改这个问题。 准则以技术因素与数据为准,而非集体爱好。 在代码款式上,听从代码款式指南的权威。任何与款式指南不统一的观点(如空格)都是集体偏好。所有代码都应与其保持一致。如果某项代码款式在文档中并未提及,那就承受作者的款式。 任何波及软件设计的问题,都不应由集体爱好来决定。 它应取决于根本设计准则,以这些准则为根底进行衡量,而不是简略的集体认识。当有多种可行计划时,如果作者能证实(以数据或公认的软件工程原理为根据)这些计划根本差不多,那就承受作者的选项;否则,应由规范的软件设计准则为准。 如果没有可用的规定,那么审核者应该让作者与以后代码库保持一致,至多不会好转代码零碎的品质。 抵触解决在代码审核中碰到抵触时,首先要做的永远是先尝试让单方(开发者和审核者)在两份文档(开发者指南 和 审核者指南)的根底上达成共识。 当很难达成共识时,审核者与开发者最好开一个面对面的会议(或视频会议),而不要持续通过代码审核评论进行解决。(在开会讨论之后,肯定要在评论中记录探讨的后果,以便让当前浏览的人晓得前因后果。) 如果仍旧无奈解决问题,最好的形式是降级。常见的降级形式比拟多,如让更多的人(如团队的其他人)参加探讨,把团队领导卷进来,咨询代码保护人员的意见,让工程经理来决定。千万不要因为开发者与审核者无奈达成统一而让CL停留在阻塞状态。 二. 代码审核过程中要看些什么?设计审核一个 CL 最重要的事件就是思考它的整体设计。CL 中的代码交互是否有意义?这段代码应该放到代码库(codebase)里,还是库(library)里?它能很好地与零碎其余局部集成吗?当初退出这个性能是机会正好吗? 性能这个 CL 所实现的性能与开发者冀望开发的性能是统一的吗?开发者的用意是否对代码的“用户”有益处?此处提到的“用户”通常蕴含最终用户(应用这些开发进去的性能的用户)和开发者(当前可能会“应用”这些代码的开发者)。 绝大多数状况,咱们冀望开发者在提交 CL 进行审核之前,曾经做过充沛的测试。但作为审核者,在审核代码时仍要思考边界状况、并发问题等等。确保毁灭那些通过浏览代码就能发现的缺点。 作为审核者,你 能够 依据须要亲自验证 CL 的性能,尤其是当这个 CL 的行为影响用户交互时,如UI扭转。仅通过浏览代码,你很难了解有哪些扭转,对用户有哪些影响。对于这种批改,能够让开发者演示这个性能。当然,如果不便把 CL 的代码集成到你的开发环境,你也能够本人亲自尝试。 在代码审核过程中,对性能的思考还蕴含一种重要场景:CL 中蕴含一些“并行计算”,可能会带来死锁或竞争条件。运行代码个别很难发现这类问题,通常须要(开发者和审核者)认真思考,以确保不会引入新的问题。(这也是不要引入并发模型的一个好理由,因为它可能引入死锁或竞争条件,同时也减少了代码审核和代码了解的难度。) 复杂性是不是 CL 能够不用这么简单?在 CL 的每个档次上查看——哪一行或哪几行是不是太简单了?性能是否太简单了?类(class)是否太简单了?“太简单”的定义是代码阅读者不易疾速了解。 同时意味着当前其余开发者调用或批改它时,很容易引入新的缺点。 ...

March 30, 2022 · 2 min · jiezi

关于代码规范:昇思MindSpore再突破蛋白质结构预测训练推理全流程开源助力生物医药发展

近日,昇思MindSpore与昌平实验室、北京大学生物医学前沿翻新核心(BIOPIC)和化学与分子工程学院、深圳湾实验室高毅勤传授课题组及鹏城实验室陈杰团队基于全场景AI框架昇思MindSpore实现AlphaFold2蛋白质构造训练。继2021年11月公布推理工具后,本次训练意味着国产AI框架具备了弱小的AI for Science底层软件能力,同时也为相干科研工作者提供新的抉择。该联结工作依靠鹏城云脑II 昇腾AI 集群进行,单步迭代性能晋升超过60%,TM-score达85分(国内权威评测数据集CASP14)。相干训练代码已在昇思MindSpore社区开源,后续也会在Openl启智社区进行开源并定期扩大与保护。图.1 T1052-D1 预测结构图(左)CASP14 87 targets TM-score 比照(右)蛋白质构造预测是取得蛋白质性能构造和构象的过程,近半个世纪以来,这一问题始终被誉为“21世纪的生物物理学”最重要的课题之一。在过来,因蛋白质构象数量微小,计算过程简单,通过AI来对蛋白质构造进行预测始终未能获得实质性冲破,获取蛋白质空间结构的办法依然以冷冻电镜、X-ray等试验技术为主,单个蛋白质的观测老本高达数月及数百万人民币。直至AlphaFold2的呈现,使得这一问题迎来新的曙光。AlphaFold2凭借其靠近试验精度的问题获得CASP14蛋白质空间结构预测较量的榜首,这一成就也被Nature誉为“前所未有的提高”。2021年7月DeepMind发表对AlphaFold2的推理代码进行开源,昇思与高毅勤课题组第一工夫对其进行了复现及优化,并于同年11月开源了基于昇思MindSpore的推理工具,效率同比晋升2-3倍。因为开源范畴仅限推理,相干从业者无奈基于此进行优化,因而许多团队踊跃地投入训练过程的复现。AlphaFold2模型自身存在内存需要大,数据处理繁琐,管制编译简单等特点,对根底AI框架存在着微小挑战。近期,昇思MindSpore联结高毅勤课题组、鹏城实验室陈杰团队全面买通AlphaFold2的训练。采纳昇腾根底软硬件平台后,在混合精度下,单步迭代工夫由20秒缩短到12秒,性能晋升超过60%。依靠昇思MindSpore内存复用能力, 训练序列长度由384晋升至512。为了尽可能主观地评估训练后果,昇思MindSpore选取了AlphaFold2论文附录中提到的87条验证集进行验证,均匀TM-score达到85分,根本持平AlphaFold2。昇思MindSpore对蛋白质构造预测训练推理的反对填补了国产AI软硬件的空白。在训练精度靠近AlphaFold2的根底上,昇思MindSpore将在算法、规模和软硬件反对等方向上继续改良,并打算凋谢共享训练数据集供同仁应用。昇思MindSpore也冀望与更多学术界和工业界搭档单干,进一步晋升模型精度、扩大利用场景。代码开源门路:https://gitee.com/mindspore/m...昇思MindSpore:Gitee:https://gitee.com/mindspore/m...Github:https://github.com/mindspore-...

March 4, 2022 · 1 min · jiezi

关于代码规范:这样才是代码管理和-Commit-的正确姿势-研发效能提升36计

简介:效力晋升从小习惯开始,这样才是代码治理和 Commit 的正确姿态! 专栏策动|雅纯 意愿编辑|张晟 软件交付是以代码为核心的交付过程,其中代码的作用有几点:第一,最终的制品要交付成什么样,须要通过代码形容分明;第二,代码定义了零碎和软件是怎么工作的;第三,代码定义了零碎的运行环境是怎么的。所有这些都是围绕代码。 那咱们的代码治理和软件配置管理应该怎么做呢?咱们先看一个例子。下图是某个团队的代码组织构造,这样的代码组织构造会有什么问题呢? 问题1:代码组的命名形式凌乱 咱们发现在最上层的目录中叫risk-managenment,这是一个零碎,这个零碎是风险管理。然而子目录写的是叫“qinglong”,那“qinglong”是利用还是团队,我不晓得。而后上面还有一个玄武,上面还有一个aTeam,中英文混淆,这样的命名形式是很凌乱的。 问题2:用代码块存储内部二进制文件 在android-sdks外面会寄存很多sdk文件,这些文件是很大的,这个代码库存储很多内部二进制文件,咱们晓得在代码库间接存这样的大文件,对整个代码库的资源耗费是十分大的。 问题3:同一归属的代码保留在不同的代码组 在aTeam目录下有一个data-model,然而其余相干的文件都在玄武下,就是data-console、data-task、data-ui,咱们不晓得它具体是什么,然而咱们晓得这几个大概率是同一个利用或者是同一个产品,所以它在两个不同的层级也是不合理的。 问题4:公共库保留在子代码组里 再下一个是common-lib,通过名字来了解就是公共库,然而这个公共感觉只给玄武这个子代码组应用。 问题5:利用的文档(或测试)与利用离开寄存 最初还有一个docs目录下有risk-docs和data-docs,一个是针对危险管制的零碎,一个是针对数据地零碎。那这个外面文档也是一个代码库,文档代码库和测试代码库,它和利用是离开寄存的,这也是不合理的。 好的代码库组织模式是怎么的?问题:假如所有的代码都保留在一个代码库,且所有人均可拜访,代码库应该怎么组织? 咱们认为代码库是能够分组的,代码组(+子代码组)+代码库=大库。 基于这个逻辑,咱们再看看方才那个例子里正当的代码组的构造应该是怎么的。 如上图所示,整个代码库是一个零碎,这个零碎有两个利用,一个是risk,一个是data。每个利用上面是有很多的服务和文档。它们有一个公共的Model,叫common-lib,这是被所有的利用所依赖的。所以咱们把属于同一个利用的Git仓库放在一起,让common放到该有的中央去。不是依照团队,而是依照利用组划分,这样划分,构造就更加清晰了。这里咱们略微总结了一些实际的倡议。 代码库的内容:-软件的源代码(ProductionCode);-将文档(和测试)的git库放到其相干利用组下;-不要将制品(如零碎二进制包)保留在代码库中,如果的确须要,以LFS或相似形式寄存;(小编举荐:云效代码治理Codeup为企业提供收费不限容量的LFS存储) 代码库的组织构造:-依照零碎、利用和模块的档次来组织代码库;-同一个零碎/利用层级的所有内容位于同一个代码组下; 代码库的可见性:-通用代码库放在其通用级别都能够拜访的地位;-除外围算法等多数代码库外,倡议对代码库的拜访在同一零碎/利用下对所有相干人员公开; 代码组织完了当前,开发者就能够围绕代码库来进行合作。整个代码库的合作过程就是:所有皆Commit。无论是rebase还是merge,都是Commit。 那对于Commit,咱们有什么要留神的呢? 什么是好的Commit咱们总结了3点倡议给到大家: 1.Samll Git库要尽可能地小。尤其是目前的基础设施现状下,尽管你的一个仓库里能够放多个利用,然而保护起来的老本会很大的。还有治理方面,不要在Git上存储构建产物和其余二进制文件。把构建产物放在构建仓库上,尽管给他人不便了,却很难晓得这个构建产物是当初的代码产生进去的还是之前产生进去的,这是很难去追溯的。对于二进制文件,如果确有必要(例如游戏的素材),倡议应用LFS的形式来保留。 2.Linear 防止无意义的merge,尽量用rebase操作。其次是防止有效commit,有很多代码库commit记录很长,然而外面80%都是有效的,例如都是fix1、fix2这样的commit,都却不晓得它具体做了些什么,这种显然是不合理的,对于这种简短的commit列表,有时候能够在merge的时候squash一下。 3.Atomic 原子性,指操作的原子化。原子性有什么益处呢?一个Commit解决一个特定的问题,比如说我就是修复一个UTcase,或者是加一个UT或者是加一个性能,或者是加一个API,这些明确的问题对应到一个commit,很容易追溯。解决的问题不能很大,不能写了2000行代码解决了一个feature,一起提交,这是十分危险的。作为开发者,做的好的应该是疾速有阶段性的成绩,并且继续地有反馈,继续地贴近指标。反之,开发者的体验不好,相干协作者的体验也不好,因为他人不晓得你做了多少了,很有可能跟你产生mergeconflict。 上面列举一些Commit的反模式: 1.有效的commit 如Mergebranch'develop'of https://codeup.aliyun.com/abc...第一个问题,在简直所有公司外面都是轻易拉开一个代码,本地和近程都有这种状况,原本一个rebase搞定的事件,这样做会导致很多有效的commit,甚至对commit追溯能力会产生很大地影响。 2.巨型commit 一个commit外面蕴含了大量的代码变动,且属于多个实现目标,就像codereview,有些人提的mergerequest,一下子过去3000多行代码,作为reviewer,你齐全不晓得他做了什么,这是十分危险的。 3.半成品的commit 如蕴含有根本语法问题或实现谬误的代码的commit半成品的commit。例如,到饭点了,不论了,先提交一把。这样的代码连编译都过不了,这个显然是不好的,没有任何意义。 4.分支间的相互merge 最初一个是分支间的相互merge。从develop合到master,又从master合到develop,相互合来合去,一旦这种合并多了当前,commit就会很难追溯,因为不晓得源头在哪。咱们倡议代码库应该有一个惟一的骨干,单向往骨干merge,尽量避免反向merge的状况。 (小编举荐:云效代码治理Codeup的骨干开发模式,就提倡轻量的commit评审 和骨干研发,帮忙企业防止分支间的简单合并~) 软件配置管理问题:软件配置常常被批改,被公布,它属于代码吗? 软件配置其实是另外一种模式的代码。有可能大家在理论工作中配置不是存在Git仓库外面的,可能是在一个配置核心或者其余相似零碎外面,但无论在哪里,实质上,咱们能够把配置等同于某种类型的代码。 下图是大家常见的动态配置和动静配置,或者说启动相干的配置和运行相干的配置。 启动相干配置 启动相干配置是构建到镜像中或者作为启动参数传进去的。启动之后不再批改了,不须要去动静监听它的变动。对这类配置的批改,个别须要从新创立或者重启容器。以此类推,哪些配置是启动相干的呢?比方DB连贯串、容器CPU规格、启动模式等(比方有的压测利用启动的时候辨别master模式和worker模式)。其它像DNS服务地址等,诸如此类的咱们都认为是启动相干的配置。 运行相干配置 通常是通过监听某个服务或文件来获取和更新的。比如说我要看一下我的白名单是什么,我去读一下白名单。配置的更新是不须要批改容器和Pod。运行中的容器须要继续监听配置的变动,当有变动后主动失效、无需重启。咱们举一下场景实例阐明一下: 大促期间调整日志级别,只记录ERROR级别的日志。服务的黑白名单,为了限度某些IP的拜访,将其列入黑名单。个性开关,通过开关关上或敞开某个feature。监控采样频率,由每分钟采样一次调整为每5分钟采样一次。这些配置不须要也不应该每次批改都重新部署利用,他们都属于运行相干的配置。 咱们再来看一个demo示例外面哪些是启动相干的,哪些是运行相干的。咱们列举一下: 这是启动的时候就会须要的一个参数。 咱们将secret文件注入到Deployment中,利用主动从文件感知secret的值,无需重启,因而它是运行时的配置。越内层的配置,批改老本越高。 从另外的角度看一下配置,它有不同的档次,代码、镜像、Pod和零碎。代码中的配置位于最内层,批改老本是最高的。因而,如果是编码级别的批改,要通过所有的阶段能力上线。如果运行阶段的话,我是不须要动后面的局部。 最初,留一个问题给大家:运行环境相干的配置是属于哪一种?欢送大家在评论区留言互动。 软件交付的终态是提供稳固可预期的零碎,要做到这点,须要确保:1.运行环境的一致性;2.软件制品的一致性。所以下篇,咱们将开始分享如何保障运行环境的一致性,以及环境中大家常见的痛点和应答计划。敬请期待! 原文链接本文为阿里云原创内容,未经容许不得转载。

February 11, 2022 · 1 min · jiezi

关于代码规范:看完这篇文章再也不用担心代码格式不对无法合并了

本文由RT-Thread论坛用户@RTT_逍遥原创公布:https://club.rt-thread.org/as... 这篇文章能够将RT-THREAD的官网的formatting和astyle等整顿文档的工具整合到git外面从而实现git commit的时候主动帮你实现formatting等格式化的问题,再也不必放心代码没有通过formatting 无奈PR胜利,而后须要本人手动操作了。这边只有部署一次,当前都是由git hook 自动化实现。 GITHUB仓库:git_auto_script欢送START和提issue。有好的倡议能够PR或者提issue。一、简介 你是否会遇到过遗记应用formatting脚本来整顿下代码,导致RTTHREAD PR不通过打回去从新批改?你是否总是遗记整顿那些astyle的格局问题,总是提交的代码不够好看?总是因为空格TAB等格局问题,让熊大等合并者头疼?你是否总是有些bug是因为没有通过动态查看,导致前面bug一大堆?来看下这个软件吧,保障对你有肯定帮忙,而且在做其余我的项目的时候这个软件包也能够应用。 本软件包通过整合cppcheck(动态编译软件), astyle(格式化代码), formatting(RTTHREAD格局整顿) 三款软件,将这三款软件整合到git的hook中,让你当前提交代码再也不要放心被CI的formatting检测出问题从新提交了。 本软件一次部署长期有效,只有你的git仓库没有更换,就始终无效。 当然如果有好的倡议或者批改,欢送PR,咱们大家一起来保护。 当然也如果有更好的软件或者更好的需要,也欢送在issue外面提出来。二、如何应用 第一次应用可能会麻烦一点,不过我感觉这个就是一劳永逸的事件,前面就简直无感了。2.1 CPPCHECK STEP1: CPPCHECK官网 下载安装 STEP2: 环境变量path增加cppcheck门路 STEP3:命令行外面执行cppcheck命令,能够用即可2.2 ASTYLE STEP1: ASTYEL官网 下载解压 STEP2: 环境变量path增加astyle门路 STEP3:命令行外面执行astyle命令,能够用即可2.3 formatting 这个是来自formatting.py 的自动化脚本,这边我把这个python脚本整顿成exe命令行的模式: STEP1: 间接clonegit_auto_script目录 STEP2: 将Windows_exe 文件夹增加到path环境变量中 STEP3: 命令行外面执行formatting 能够用即可 生成exe采纳命令(这一步我曾经弄好放到Windows_exe中,通常不须要操作,如果须要更新的话在formatting.py目录下执行上面操作) pyinstaller --onefile --nowindowed formatting.py 2.4 pre-commit装置 将 RTTHREAD_auto/pre-commit拷贝到你的工程的.git/hook 文件夹上面,当前commit无需操作任何操作就能够间接commit 无需思考formatting或者格局问题或者动态查看问题 image-20211025223018211.png 好了, 所有ready。 这个时候,只有你失常commit,你就会发现,你的代码格局曾经通过astyle优化过了,如果代码动态查看有问题,会commit不过,并且提醒你须要批改,同时也是通过formatting的批改了。之后再也不必放心PR会有格局上的问题了。 上面看下动画演示:help.gif GITHUB仓库:git_auto_script欢送START和提issue。又好的倡议能够PR或者提issue。三、FAQ3.1 cppcheck和astyle等命令在哪里能够去掉? 在pre-commit文件夹中,找到cppcheck命令和astyle命令和formatting命令,后面加#就能够去掉 如下所示:正文掉所有的命令,就不会执行自动化脚本了 if [ -n "$changed_files" ]; then #cppcheck --enable=warning,performance,portability --inline-suppr --error-exitcode=1 --force $changed_fileserr=$?if [ $err -ne 0 ]; then echo "Hello! we found a obvious fault, please fix the error then commit again" exit $errfifi ...

November 10, 2021 · 1 min · jiezi

关于代码规范:p3c-插件是怎么检查出你那屎山的代码

作者:小傅哥博客:https://bugstack.cn原文:https://mp.weixin.qq.com/s/RwzprbY2AhdgslY8tbVL-A 一、前言你会对你用到都技术,好奇吗? 尽管咱们都被称为码农,也都是写着代码,但因为所处场景需要的不同,所以各类码农也都做着不一样都事件。 有些人对立标准、有些人开发组件、有些人编写业务、有些人倒腾验证,但越是工作内容简略如CRUD一样的码农,用到他人提供好的货色却是越多。一会装置个插件、一会引入个Jar包、一会调他人个接口,而本人的工作就像是装配工,东拼拼西凑凑,就把产品需要写完了。 坏了,这么干可能几年下来,也不会有什么技术上都冲破。因为你对那些应用都技术不好奇,不想晓得它们是怎么实现的。就像阿里的P3C插件,是怎么查看代码剖析进去我写的拉胯的呢? 二、P3C 插件是什么P3C 是阿里开源代码库的插件工程名称,它以阿里巴巴Java开发手册为规范,用于监测代码品质的 IDEA/Eclipse 插件。 源码:https://github.com/alibaba/p3c插件装置实现后,就能够依照编程规约,动态剖析代码中呈现的代码:命名格调、常量定义、汇合解决、并发解决、OOP、管制语句、正文、异样等各项潜在危险,同时会给出一些优化操作和实例。 在恪守开发手册规范并依照插件查看都状况下,还是能够十分好的对立编码标准和格调都,也能剔除掉一些潜在都危险。如果你是老手编程用户或者想写出规范都代码,那么十分倡议你依照这样都插件来辅助本人做代码开发。当然如果你所在的公司也有相应都规范手册和插件,也能够依照后恪守它都约定的。三、P3C 插件源码在最开始应用这类代码查看都插件的时候,就十分好奇它是怎么发现我的屎山代码的,用了什么样都技术原理呢,如果我能剖析下是不是也能够把这样都技术手段用到其余中央。 在剖析这样一个代码查看插件前,先思考要从 IDEA 插件都源码查起,看看它是什么个逻辑,之后剖析具体是如何应用都。其实这与一些其余的框架性源码学习都是相似的,拿到官网都文档、GitHub 对应的源码,依照步骤进行构建、部署、测试、调试、剖析,进而找到外围原理。 P3C 以 IDEA 插件开发为例,次要波及到插件局部和规约局部,因为是把规约查看的能力与插件技术联合,所以会波及到一些 IDEA 开发的技术。另外 P3C 插件波及到都技术语言不只是 Java 还有一部分 kotlin 它是一种在 Java 虚拟机上运行的动态类型编程语言。 插件源码:https://github.com/alibaba/p3c/blob/master/idea-plugin规约源码:https://github.com/alibaba/p3c/tree/master/p3c-pmd1. 插件配置 p3c.xml<action class="com.alibaba.p3c.idea.action.AliInspectionAction" id="AliP3CInspectionAction" popup="true" text="编码规约扫描" icon="P3cIcons.ANALYSIS_ACTION"> <keyboard-shortcut keymap="$default" first-keystroke="shift ctrl alt J"/> <add-to-group group-id="MainToolBar" anchor="last"/> <add-to-group group-id="ProjectViewPopupMenu" anchor="last"/> <add-to-group group-id="ChangesViewPopupMenu" anchor="last"/> <add-to-group group-id="EditorPopupMenu" anchor="last"/></action>翻看源码最重要是要找到入口,这个入口通常也是你在应用插件、程序、接口等时候,最间接进入都那局部。那么咱们在应用 P3C 插件的时候,最显著的就是 编码规约扫描 通过源码中找到这个关键字,看它都波及了哪个类都配置。action 是 IDEA 插件中用于配置窗体事件入口都中央,以及把这个操作配置到哪个按钮下和对应都快捷键。2. 编码规约扫描( AliInspectionAction)class AliInspectionAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return val analysisUIOptions = ServiceManager.getService(project, AnalysisUIOptions::class.java)!! analysisUIOptions.GROUP_BY_SEVERITY = true val managerEx = InspectionManager.getInstance(project) as InspectionManagerEx val toolWrappers = Inspections.aliInspections(project) { it.tool is AliBaseInspection } val psiElement = e.getData<PsiElement>(CommonDataKeys.PSI_ELEMENT) val psiFile = e.getData<PsiFile>(CommonDataKeys.PSI_FILE) val virtualFile = e.getData<VirtualFile>(CommonDataKeys.VIRTUAL_FILE) ... createContext( toolWrappers, managerEx, element, projectDir, analysisScope ).doInspections(analysisScope)} 这是一个基于 kotlin 语言开发的插件代码逻辑,它通过 actionPerformed 办法获取到工程信息、类信息等,接下来就能够执行代码查看了 doInspections3. 规约 p3c-pmd当咱们再往下翻看浏览的时候,就看到了一个对于 pmd 的货色。PMD 是一款采纳 BSD 协定公布的Java 程序动态代码查看工具,当应用PMD规定剖析Java源码时,PMD首先利用JavaCC和EBNF文法产生了一个语法分析器,用来剖析一般文本模式的Java代码,产生合乎特定语法结构的语法,同时又在JavaCC的根底上增加了语义的概念即JJTree,通过JJTree的一次转换,这样就将Java代码转换成了一个AST,AST是Java符号流之上的语义层,PMD把AST解决成一个符号表。而后编写PMD规定,一个PMD规定能够看成是一个Visitor,通过遍历AST找出多个对象之间的一种特定模式,即代码所存在的问题。该软件功能强大,扫描效率高,是 Java 程序员 debug 的好帮手。 ...

September 28, 2021 · 2 min · jiezi

关于代码规范:阿里巴巴代码规约检测Java-代码规约扫描

阿里巴巴代码规约检测&云效Java 代码规约扫描《阿里巴巴 Java 开发手册》是阿里巴巴团体技术团队的个体智慧结晶和经验总结,经验了屡次大规模一线实战的测验及一直的欠缺,系统化地整顿成册,反馈给宽广开发者. 阿里巴巴 Java 开发手册检测的能力也被集成在RDC的自动化测试服务中,做代码规约检测能够间接对代码进行扫描以检测室是否合乎阿里巴巴代码规约。《阿里巴巴 Java 开发手册》是阿里外部 Java 工程师所遵循的开发标准,涵盖编程规约、单元测试规约、异样日志规约、MySQL 规约、工程规约、平安规约等,这是近万名阿里 Java 技术精英的经验总结,并经验了屡次大规模一线实战测验及欠缺。依据约束力强弱,规约顺次分为强制、举荐、参考三大类:【强制】必须恪守。是不得不恪守的约定,违反本约定或将引起重大的结果。【举荐】尽量恪守。长期恪守这样的规定,有助于零碎稳定性和单干效率的提醒。【参考】充沛了解。技术意识的疏导,是集体学习、团队沟通、我的项目单干的方向。Java 代码规约扫描应用《阿里巴巴 Java 开发规约》插件扫描 Java 规约问题。开启或敞开扫描管理员角色有权限开启或敞开扫描。开启扫描1、在 「设置」- 「集成与服务」中开启2、弹出的 「用户承诺书」窗口中,浏览,并勾选 「我已浏览相干协定并确认开明服务」,而后点击「确认」3、抉择触发扫描的机会 代码提交触发扫描:代码提交即 git push 后触发扫描合并申请触发扫描:合并申请事件触发扫描,即创立合并申请、合并申请更新触发扫描敞开扫描在 「设置」- 「集成与服务」中敞开在 「提交」中查看扫描后果当开启了代码提交触发扫描,能够在 「提交」中查看扫描后果 在 「提交」列表查看整体后果鼠标点击查看 Java 代码规约扫描后果点击 「详情」查看扫描详情在「合并申请」中查看扫描后果当开启了合并申请触发扫描,能够在 「合并申请」中查看扫描后果在合并申请详情中查看扫描后果点击 「详情」查看扫描详情,点击具体的扫描问题查看扫描详情点击 「扫描汇总」查看所有扫描后果阿里巴巴代码规约检测&云效Java 代码规约扫描《阿里巴巴 Java 开发手册》是阿里巴巴团体,近万名阿里 Java 技术精英的经验总结,技术团队的个体智慧结晶和经验总结,经验了屡次大规模一线实战的测验及一直的欠缺,系统化地整顿成册,反馈给宽广开发者. 阿里巴巴 Java 开发手册检测的能力也被集成在RDC的自动化测试服务中,能够间接对代码进行扫描以检测室是否合乎阿里巴巴代码规约。欢送大家应用云效代码治理 codeup是阿里云出品的一款企业级代码治理平台,提供代码托管、代码评审、代码扫描、品质检测等性能,全方位爱护企业代码资产,帮忙企业实现平安、稳固、高效的研发治理。

September 2, 2021 · 1 min · jiezi

关于代码规范:Android-Lint-实践之二-自定义-Lint

背景如前文《Android Lint 实际 —— 简介及常见问题剖析》所述,为保障代码品质,团队在开发过程中引入了 代码扫描工具 Android Lint,通过对代码进行动态剖析,帮忙发现代码品质问题和提出改良倡议。Android Lint 针对 Android 我的项目和 Java 语法曾经封装好大量的 Lint 规定(issue),但在理论应用中,每个团队因不同的编码标准和性能偏重,可能仍需一些额定的规定,基于这些思考,咱们钻研并开发了自定义的 Lint 规定。 根底创立自定义 Lint 须要创立一个纯 Java 我的项目,引入相干的包后能够基于 Android Lint 提供的根底类编写规定,最终把我的项目以 jar 的模式输入后就能够被主我的项目援用。这里咱们以 QMUI Android 中的一个理论场景来阐明如何进行自定义 Lint:咱们在我的项目中应用了 Vector Drawable,在 Android 5.0 以下版本的零碎中,Vector Drawable 不被间接反对,这时应用 ContextCompat.getDrawable() 去获取一个 Vector Drawable 会导致 crash,而这种状况因为只在 5.0 以下的零碎中才会产生,往往不易被发现,因而咱们须要在编写代码的阶段就能及时发现并作出揭示。在 QMUI Android 中,提供了 QMUIDrawableHelper.getVectorDrawable 办法,基于 support 包封装了平安的获取 Vector Drawable 的办法,因而咱们最终的需要是查看出所有应用 ContextCompat.getDrawable() 和 getResources().getDrawable() 去获取 Vector Drawable 的中央,进行揭示并要求替换为 QMUIDrawableHelper.getVectorDrawable 办法。 创立工程如下面所述,创立自定义 Lint 须要创立一个 Java 我的项目,我的项目中须要引入 Android Lint 的包,我的项目的 build.gradle 如下: ...

August 27, 2021 · 4 min · jiezi

关于代码规范:提升代码质量的方法领域模型设计原则设计模式

简介: 咱们能够列举出十分多品质差的代码的体现景象,其中最影响代码品质的两个体现是命名徒有虚名、逻辑可扩展性差,当一个新人浏览代码时,有时发现办法命名与理论逻辑对不上,这就让人感到十分纳闷,这种景象在平时工作并不少见;另一个就是逻辑扩展性差,一个新业务需要提出来后,发现要在多处改变,须要回归的业务逻辑比拟多,造成研发效率不高。 作者 | 不拔起源 | 阿里技术公众号 一 影响代码差的根因1 差代码的体现咱们能够列举出十分多品质差的代码的体现景象,如名字不知所意、超大类、超大办法、反复代码、代码难懂、代码批改艰难……其中最为影响代码品质的两个体现是命名徒有虚名、逻辑可扩展性差,当一个新人浏览代码时,有时发现办法命名与理论逻辑对不上,这就让人感到十分纳闷,这种景象在平时工作并不少见;另一个就是逻辑扩展性差,一个新业务需要提出来后,发现要在多处改变,须要回归的业务逻辑比拟多,造成研发效率不高。 2 问题演绎对第1节中提到的景象进行问题演绎整顿,大抵整顿出6类问题,别离开展加以阐明。 命名问题:命名问题是一件十分头疼的事,想要取一个货真价实又好了解的名字并不那么容易。波及到变量的命名、办法的命名、类命名,常见的命名问题有两种:一种是不知所云;另一种是徒有虚名。命名不知所云是一个人初一看,不晓得它是什么意思,根本原因就是没有想到一个适合的词汇去形象问题;命名徒有虚名是命名和理论逻辑想表白的意思不一样,这样的命名会误导人。代码构造问题:当一个人初看工程代码时,当还没有深刻看代码逻辑时,从模块划分、类划分、办法划分整体上能够感触得出代码品质,如果一个类有几千行代码,一个办法有几百行,这样的逻辑置信没有多少人违心去看,复杂度比拟高。好的代码层次结构十分清晰,就像看一本柔美的书一样有一种赏心悦目的感觉。编程范式问题:有三种编程范式:表模式、事务脚本模式和畛域设计模式,大家用得最多的是事务脚本模式,这种模式最合乎人做事的办法,step by step,这种模式最大的问题就是承当了不该本人承当的职责,看起来比拟合乎逻辑,实际上问题比拟多,平时大家喜爱称之为"面条型代码"。可读性问题:代码除了实现业务性能外,还要具备良好的可读性,有的代码没有任何正文;有的代码格局不对立;有的是为了夸耀技术,大段大段的Lambda表达式(并不是说Lambda表达式不好,要害要管制档次深度),这样的代码看起来简洁,可读性并不太好。扩展性问题:可扩展性问题是一个陈词滥调的问题,要实现良好的可扩展性并不那么容易,个别是没有形象问题,如店铺在店招头展现Tab,面条型的代码就是间接定义一个List,而后往里面加Tab对象,如果须要再加一个Tab怎么办?典型的就是不满足开闭准则。无设计问题:整个代码看起来比拟平淡,他人看了之后也从中学习不到内容。个别这种问题是没有深入分析问题,仅仅解决了问题,而没有思考如何更好地解决问题,比方反复解决流程的工作是否能够形象成一个通用的模板类、不同解决类是否能够通过工厂类去获取具体的策略、异步解决是否能够应用事件模式去解决、对于新减少的能力是否通过主动注册去发现……3 根因剖析接下来剖析下为什么会产生代码差的起因,这个问题有内部起因,也有外部起因。内部起因次要有:我的项目排期急,没有多少工夫去设计;资源短缺,人手不够,只能怎么快怎么来;紧急问题修复,长期计划疾速解决……。外部起因次要有:本身技能低,怎么技能没有把握到,如Lamda表达式、罕用的工具类、框架高级用法等;无极致谋求的精力,仅仅实现需要就行,稳定性、可扩展性、性能、数据一致性等没有思考…… 笔者认为最为要害的是外部本身的问题,根因就两个:自我要求不高;无反馈通道。如果对自已要求不高,仅仅满足实现需要开发就止步了,很难写出高质量的代码,另外如果没有内部反馈,也难以进步本人的技能。笔者之前的主管十分严格,对大家写的代码review比拟认真,一个变量名、一段逻辑的写法,重复让批改,这其实是晋升技能最快的办法。 二 晋升代码品质的办法晋升代码品质的办法,笔者喜爱用三个办法:领域建模、设计准则、设计模式,次要谈下如何应用。 分析阶段:当拿到一个需要时,先不要焦急想着怎么把这个性能实现,这种很容易陷入事务脚本的模式。剖析什么呢?须要剖析需要的目标是什么、实现该性能须要哪些实体承当,这一步外围是找实体。举个下面进店Tab展现的例子,它有两个要害的实体:导航栏、Tab,其中导航栏外面蕴含了若干个Tab。设计阶段:剖析完了有哪些实体后,再剖析职责如何调配到具体的实体上,这就要使用一些设计准则去领导,GRASP中提到一些职责调配的准则,感兴趣的同学能够去具体看看。回到下面的例子上,Tab的职责次要有两个:一个是Tab是否展现,这是它本人的职责,如上新Tab展现的逻辑是店铺30天内有上架新商品;另一个职责就是Tab规格信息的构建,也是它本人要负责的。导航栏的职责有两个:一个是承受Tab注册;另一个是展现。职责调配不适理,也就不满足高内聚、低耦合的特色。打磨阶段:这个阶段抉择适合的模式去实现,大家一看到模式都会了解它是做什么的,比方看到模板类,就会晓得解决通用的业务流程,具体变动的局部放在子类中解决。下面的这个例子,用到了2个设计模式:一个是订阅者模式,Tab主动注册的过程;另一个是模板模式,先判断Tab是否展现,而后再构建Tab规格信息,流程尽管简略,也能够形象进去通用的流程进去,子类只用简略地重写2个办法。 三 畛域模型的作用领域建模的入门门槛比拟高,蕴含了一些难了解的概念。本篇文章中并不会讲述如何进行建模(能够私下交换),笔者发现让大家承受领域建模远比晓得如何建模更重要,当你晓得了领域建模的作用后,本人会想各种方法去学习。上面通过笔者经验的一些理论案例进行论述,让大家听起来并不感觉到那么空洞。 1 简化意识笔者工作一年后退出到了一家金融公司,过后对金融无所不知,开始接触到标的、债务、债务转让、融资担保、非融资担保等名词后,一时感到莫衷一是,每天要学习十分多的新内容。 两个月后,我的主管给咱们做了一次分享,就拿了一张ppt来讲,它外面蕴含了畛域的实体,以及实体之间的关联关系,一下子我就晓得了整个业务是怎么玩转的。模型的作用就是简化人对事物的意识,如果一开始咱们就陷入到代码细节中,很难看到业务的全貌,而且代码是为了实现业务能力,当你晓得了业务之后,再去看代码就会快得多。 2 统一认识在公司里,有研发、产品、经营、测试……,当咱们在一起交换的时候,大家默认的语言是不对立的,开发常常讲怎么操作这张数据库表,产品常常讲业务模式……这就导致大家的意识并不对立。 那是一个早晨,刚和交互同学确认完交互流程后,忽然她问了一个问题:把类似的页面让卖家移到同一个文夹中,这个好实现吧?听完后告知不能,交互同学一据说这很正当呀,怎么实现不了?开始给她讲了下现有的零碎流程,发现她听得一脸懵逼,马上发现问题了,我是用开发的语言在形容问题,立马换了一种形式,找了一支笔和一张纸,给交互同学画了咱们的畛域模型是什么,业务实体之间的交互是怎么的,一讲完后,交互同学马上明确了为什么不能实现的起因所在了。 3 领导设计有的同学感觉领域建模偏空洞,比拟虚,其实除了可能简化意识和统一认识外,领域建模还可能领导代码设计,比方下面举的店铺导航Tab的例子,笔者就是通过领域建模来设计的,尽管它是一个小的需要,并不障碍领域建模的使用。在下图中,能够清晰的看到,导航栏蕴含了若干个Tab,一个Tab蕴含规格信息和点击操作信息。把这个业务模式画进去之后,对应的代码中也会有下面的概念,事实与代码之间存在映射关系,模型即代码,代码即模型。如果你的模型不能反映事实,模块只能算是一个花架子,范钢老师对此总结了三句话:事实有什么事物,对应有什么对象;事实事物有什么行为,对应对象有什么办法;事实事物有什么分割,对应对象有什么关联。 四 设计准则的底层逻辑1 SOLID对于设计准则,个别咱们谈判到SOLID,它蕴含了五个设计准则: 繁多职责准则:A class should have one, and only one, reason to change,一个类只能因为一个理由被批改。开闭准则:Entities should be open for extension, but closed for modification,对扩大凋谢,对批改敞开。里氏替换准则:Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it,子类能够替换父类。接口隔离准则:A client should not be forced to implement an interface that it doesn’t use,不能强制客户端实现它不应用的接口,应该把接口拆的尽可能小。依赖倒置准则:Abstractions should not depend on details. Details should depend on abstractions,形象不依赖于细节,而细节依赖于形象。2 为什么要有设计准则咱们对SOLID准则基本上据说过或者理解过,但为什么要有这些设计准则呢?为了答复这个问题,咱们从指标往下推导下。软件开发的指标是高内聚、低耦合,这句挂在嘴边的话,发现很难掂量,比方要答复:什么样的叫高内聚?什么样的叫低耦合?高内聚要高到什么水平?低耦合要低到什么水平?这四个问题并不太好答复。 ...

August 20, 2021 · 1 min · jiezi

关于代码规范:AI抄代码无罪GitHub-Copilot拿用户的开源代码改一改就去挣钱

剽窃可耻,但AI能够?刚公布的Copilot就被推上了「侵权」的风口浪尖!网友示意:你再训练都是基于咱们的开源代码,这改一改就想用来赚钱真的好么? Github和OpenAI联结公布的AI代码生成工具——Copilot,看起来几乎就编(mo)程(yu)神器。 Copilot不仅能根据程序员写的几行正文生成对应的代码,而且还能够依据代码的上下文主动补全整段函数。 在1750亿个参数的GPT-3语言模型的加持下,其外围Codex模型承受了来自GitHub的数十亿行开源代码的训练。 显然,Copilot的成果非常现实,用过的人都对其大加赞叹。 「Copilot仿佛确切地晓得我接下来要输出的内容,而且Copilot在解决React组件时特地有用,它能够做出十分精确的预测。」 GitHub的CEO Nat Friedman也十分兴奋地示意:「每天都有数百名GitHub的开发者在应用Copilot,如果预览版停顿顺利的话,咱们将打算在将来某个时候将其扩大为付费产品。」 等一下,GitHub这是把开源的代码一波操作之后变成「付费」的产品? 网友们一下子炸了,看这架势是要忽视General Public License? 「他们本人抵赖,Github Copilot承受了大量GPL(通用公共许可证)代码的训练,这难道不是一种将开源代码荡涤为商业产品的模式么。『它通常不会重现准确的代码』这个申明很难令人满意。」 GPL——通用公共许可证是什么? 依据维基百科的解释,GNU General Public License,中文翻译为通用公共许可证,简称GPL,是一系列自由软件许可证,可保障用户运行、钻研、共享和批改软件的自在。 同时,GPL是一个Copyleft许可证,这意味着任何衍生作品都必须遵循雷同或等效的许可条款。 GNU官网对于GPL的解释说,如果你想把批改过的GPL代码向公众公布,就须要提供源代码。 https://www.gnu.org/licenses/... GPL许可证系列始终是开源软件畛域中最受欢迎的软件许可证之一。其中就有赫赫有名的Linux内核。 对于Linux的胜利,GPL在其中也表演了至关重要的地位,它保障了为内核做出奉献的程序员的工作放弃自在,而不是被别人利用。 而Copilot用基于GPL的代码进行训练这件事,网友概括道:「GPL明确申明『不要将我的工作放在专利软件中』,而Copilot则是一种将他们的工作放在专利软件中的机制。」 有网友示意不解:「为什么这是一个问题?GPL不是说能够自在地共享和批改代码?」 「是的,GPL容许共享和批改代码,但必须将其作为GPL公布。」 也有网友示意:「你怎么晓得『你想进去』的代码不是源自GPL的代码?」 「然而,人类也通过浏览开源代码来学习,所以这不是一回事么?」 「不,人类具备形象的理解能力,并有宽泛的常识可供借鉴,而统计模型没有。」 「人类开发人员在大量关闭和开源我的项目上进行训练,并反刍他们作为片段藏起来的代码,是在创作衍生作品吗?」 「呃,是的,如果你『暗藏』了GPL代码的片段,而后将其复制粘贴到商业我的项目中,这听起来就像是在违反许可。」 难道真能用他人的代码赚钱? 针对把他人的代码商用化这件事,甲骨文对谷歌侵权的诉讼能够说是一个十分驰名的案例了。 其中的争议集中在Java的局部API和约11,000行源代码的应用上,这些源代码归甲骨文所有,而谷歌则把它们用在晚期的安卓操作系统上。 甲骨文提起诉讼,称这些API是受版权保护的,要求谷歌从侵权的安卓版本的销售和许可中取得88亿美元的损害赔偿。 尽管两次地区法院级别的陪审团审判都反对谷歌,但联邦巡回法院颠覆了这两项决定,宣称 API受版权保护,并且谷歌的应用不属于正当应用。 谷歌在2019年的任期内胜利向最高法院申请审理此案,重点关注API的版权和后续正当应用。2021年4月,最高法院以6比2的裁决裁定谷歌对Java API的应用属于正当应用。该决定颠覆了联邦巡回法院的裁决,并将案件发回重审。 网友调侃道:「在谷歌的某个中央:『咱们有 0.1% 的机会从甲骨文中逐字复制一小块代码,咱们应该应用它吗?』」 反方观点 「被视为一个受版权保护『作品』的『衍生作品』,必须包含原始作品的『实质性』局部。而Copilot主动生成的5行函数不会被法律畛域的任何人视为『衍生作品』。」 对于AI学习了开源代码之后,从新组装并复用它们,而背地的公司则用这个AI去赚钱,你怎么看?

July 5, 2021 · 1 min · jiezi

关于代码规范:被解救的代码-代码即服务时代来了

简介: 人类对自在的谋求从未进行,咱们用战斗取得民族自在,咱们用代码取得双手自在,同时代码作为服务器的奴隶,也开始蠢蠢欲动,反动曾经开始,当代码翻身做主,作为开发者的咱们又该如何适应新时代的到来?人类对自在的谋求从未进行,咱们用战斗取得民族自在,咱们用代码取得双手自在,同时代码作为服务器的奴隶,也开始蠢蠢欲动,反动曾经开始,当代码翻身做主,作为开发者的咱们又该如何适应新时代的到来? 所有皆代码的反动 代码始终是服务器中的囚徒,然而反动已来,看代码和如何一步一步掌控环境,走向服务。 1.反动:用代码管制编译打包Pipeline as code:代表技术 Jenkins Pipeline[1] 2.反动:用代码管制服务器Machine as code:代表技术 Docker 3.反动:用代码管制服务器集群Server cluster as code:代表技术 K8s 4.反动:用代码管制根底资源Infrastructure as code:代表技术 Terraform 当所有皆代码,A=B 可得 B=A,代码即服务时代就来了。 代码即服务时代的到来 1.传统时代的代码仓库传统的代码仓库阐明中,"运行环境装置向导"文档是必备的,以 SpringBoot 代码[2]为例,自带装置向导[3]文档。 2.新时代的代码仓库参考代码仓库 aws-lamda-spring-boot2[4],包含 springboot 运行到 aws 的 lamda 须要的全副代码。 3.支流技术对新时代的拥抱以 Spring[5]的倒退为例,从 SpringBoot 开始,一直对环境管制进行集成,直到 SpringNative,曾经能够间接构建镜像。 代码即服务下的云原生架构 1.容器服务[6]:用代码管制所有 2.微服务引擎务[7]:信赖规范平台 3.函数计算[8]:信赖规范平台,将大部分控制权交给平台13.webp 代码即服务下的研发平台和平在代码即服务的时代,各大厂商都在建设本人的云上研发闭环,谁做好云上的开发平台,谁就能抓住下一带云原生开发者的心。 1.代码托管之战:得代码者得天下• 微软发表收买 GitHub[9]• 谷歌投资 Gitlab[10]• AWS 自建公有仓库 CodeCommit[11]• 阿里云企业级代码托管平台 Codeup[12] 2.在线开发之战• 微软整合 VS Code 和 Github,推出 Github Codespace[13]• 谷歌另辟蹊径,做线下 IDE 插件 Cloud Cod[14],对接 Google Cloud• AWS 在线云 IDE:Cloud 9[15]• 阿里云 IDE:DevStudio[16] ...

May 17, 2021 · 1 min · jiezi

关于typescript:因为这几个TypeScript代码的坏习惯同事被罚了500块

作者:Daniel Bartholomae 翻译:疯狂的技术宅 原文链接:https://startup-cto.net/10-ba... 近几年 TypeScript 和 JavaScript 始终在稳步发展。咱们在过来写代码时养成了一些习惯,而有些习惯却没有什么意义。以下是咱们都应该改过的 10 个坏习惯。 1.不应用 strict 模式这种习惯看起来是什么样的没有用严格模式编写 tsconfig.json。 { "compilerOptions": { "target": "ES2015", "module": "commonjs" }}应该怎么只需启用 strict 模式即可: { "compilerOptions": { "target": "ES2015", "module": "commonjs", "strict": true }}为什么会有这种坏习惯在现有代码库中引入更严格的规定须要破费工夫。 为什么不该这样做更严格的规定使未来保护代码时更加容易,使你节俭大量的工夫。 2. 用 || 定义默认值这种习惯看起来是什么样的应用旧的 || 解决后备的默认值: function createBlogPost (text: string, author: string, date?: Date) { return { text: text, author: author, date: date || new Date() }}应该怎么应用新的 ?? 运算符,或者在参数重定义默认值。 function createBlogPost (text: string, author: string, date: Date = new Date()) return { text: text, author: author, date: date }}为什么会有这种坏习惯?? 运算符是去年才引入的,当在长函数中应用值时,可能很难将其设置为参数默认值。 ...

April 17, 2021 · 3 min · jiezi

关于代码规范:编码入门

一. 编码基本功1. 前言依据实际数据能够看出,调试工夫占据了咱们开发工夫中的最大局部,广泛能到60%。如果咱们有办法大幅消减调试阶段的工夫,效率天然可能大幅晋升。通过什么伎俩可能做到? 写好代码,以模块化为核心指导思想,尽量把代码写清晰,写强壮,少出一些BUG;做好单测,以自动化为核心指导思想,尽量早,尽量低代价,尽量全面,验证所有逻辑,把BUG毁灭于萌芽之中;2. 6步法这6个步骤,围绕『单测』这个外围,目标是进步单测的效率、成果,让单测能够成为一道『拦河大坝』,把BUG阻断在开发阶段,防止后续『海底捞针』,在大范畴代码中定位BUG。设计改善:对设计产出的API进行优化,以及对模块内部结构进行微调,做好分层和解耦。目标是晋升代码的模块性,让代码更容易了解,更容易调试,测试,批改,复用,扩大。本步骤输入API函数的原型定义。编写单测的用例&代码:在编写函数实现代码前,先编写函数的单元测试代码,利用单元测试来调试函数,升高函数调试的难度和工作量。本步骤输入API函数的单测代码。函数代码实现:编写函数的实现代码,重点关注代码的易了解性,健壮性。利用前一步写好的单测案例进行逐函数调试。本步骤输入API函数的实现代码,实现代码调试。覆盖率剖析:在函数编写实现,并利用单测调试结束后,收集覆盖率数据并剖析,依据覆盖率数据掂量单测品质,增补新的单测用例。valgrind检测:对于C/C++,单元测试无奈发现内存透露、溢出、线程类问题。能够利用valgrind对单测运行过程进行查看,排除这几类问题。codereview:对于设计类问题,以及只在特定异样场景产生的谬误,单测、valgrind检测都无奈齐全打消。能够通过代码review,人工排除这一类的问题。3. 设计中注意事项在函数中要查看参数的有效性(能够应用assert),调用函数要查看函数返回值memcpy不能对重叠区域进行拷贝,memmove能够开释过的指针要置为null局部变量要初始化malloc分配内存要初始化能力应用应用strtol替换atoi

April 14, 2021 · 1 min · jiezi

关于代码规范:评审恩仇录IDE也能做代码评审

简介: 云效Codeup推出了本地IDE插件端的评审,罢黜了黄药师来回华山的奔走之苦 现代科技公司的共事们素日一起交换开发规约和产品需要,肩上独特扛着业务倒退和同行竞争的压力,这份还书贻剑的情谊如何能引来恩仇呢?通过与一线开发者的交换,最集中的矛盾点往往呈现在代码评审环节。对于代码评审,经常听到这样的反馈: 不不便,评审须要来回切网页和IDE不深刻,评审须要代码元素的穿插援用不高效,评审参与者相互依赖进度 还记得当年“华山论代码”,东邪、西毒、南帝、北丐四人关山迢递齐聚华山,为了抢夺《Java开发手册华山版》,比拼代码武艺。 四人评审了各自代码,在云效Codeup的网页上相互评论切磋,几轮交锋下来相互之间都对代码格调有了理解,黄药师回顾了华山论代码刀光剑影的那一夜,暗自庆幸本人能全身而退,一点点漏洞公布到线上都存在致命的危险。南帝段智兴的一阳指,再加上云效世外高人云豆学生通过自动化检测输入的指导,让黄药师的武力再次飞升。 近期,云效Codeup推出了本地IDE插件端的评审,罢黜了黄药师来回华山的奔走之苦。 这款本地评审工具就是Alibaba Cloud Toolkit,它是一个实用于 IntelliJ IDE的插件,旨在帮忙企业开发者更无效地编码、评审、测试、诊断和部署应用程序。 01 足不出户,心流合一本地评审工具缩小页面切换,带来代码开发评审心流合一的沉迷体验 药师足不出户,在本地编辑器端便能够查看评审评论,并且做修复和提交,不再须要频繁地切换网页和代码编辑器,大大晋升了编码效率。 黄药师选中“华山论代码”的那次武艺评审,点开详情,回顾起了这场世纪大战,一招一式的接化似在眼前。 读书有三到,谓心到眼到口到。开发者可能在代码编辑器中潜心评审,沉迷式地实现代码品质晋升。 02 深刻语法,摸索内力本地评审工具联合代码穿插援用,深刻语法结构,帮忙开发者发现更多的潜在问题借助本地IDE的语法服务劣势,可能在评审过程中自在跳转二三方包的定义和工程项目内的援用。黄药师通过与欧阳锋的过招教训,深入分析了StringBuilder外部的实现原理,并查看了我的项目工程内是否存在多线程调用的危险。 O3 疾速迭代,见招拆招本地评审工具可能让评审发起人和评审人都能疾速批改代码,晋升迭代效率 黄药师回顾了华山论代码刀光剑影的那一夜,暗自庆幸本人能全身而退,一点点漏洞公布到线上都存在致命的危险。南帝段智兴的一阳指,还有世外高人云豆学生的指导,让黄药师的武力再次飞升。 黄药师让蓉儿备齐桃花岛的上等药材,在家中打坐修行,疾速修复招式破绽。 本地代码评审工具不光可能帮忙评审发起人依据评论疾速修复破绽,作为评审人,在本地评审过程中看到一些问题,也可能疾速切到评审源分支,帮忙评审人飞速修复缺点,晋升代码品质,防止了“评审人评论——发起人本地修复提交——评审人确认并标记评论已解决”的简短流程,使代码评审简洁高效。 评审参与者们群策群力晋升晋升代码品质,并且通过更新的告诉(目前有站内信,邮件,钉钉等形式,后续会退出IDE侧),防止相互依赖影响开发迭代,在保障评审品质的根底上晋升评审效率。 Cloud Toolkit云效代码评审介绍为什么抉择 Cloud Toolkit云效代码评审 ?零老本:收费- 极致高效:不便的代码治理和评审,摈弃手工冗余的部署操作,反对本地一键自动化部署利用,针对阿里云产品如 ECSROSRDS 提供丝般顺滑的公布体验如何启用 Cloud Toolkit云效代码评审 ?关上「IntelliJ IDEA」-> 「Preference」-> 「Plugins」,搜寻 “Alibaba Cloud Toolkit”,点击装置; 原文链接本文为阿里云原创内容,未经容许不得转载。

March 31, 2021 · 1 min · jiezi

关于代码规范:2B-领域下低代码的探索之路

简介: 低代码将成为B端服务畛域的基础设施,必将颠覆传统开发方式,将来可期。 作者:天晟 前言大家好,我是钉钉宜搭前端一个小团队的负责人天晟,在阿里做了五年的低代码。明天的分享咱们不讲技术细节,次要会分享下咱们这五年的摸索过程和以后的市场剖析,心愿能给大家带来一个对低代码搭建不一样视角的意识。 什么是低代码说起低代码(Low-Code)这个词,是在 2014 年,Forrester Research 第一次正式应用低代码来形容这个市场。国内也就是近几年开始风行的,以前咱们这边叫「可视化搭建」,可视化搭建讲起来有个很大的毛病,就是很容易和数据可视化傻傻分不清楚。我还记得,2018 年的时候,过后做一个分享,主题是 「泛可视化搭建的解决方案」,我老板的老板说倡议我把「泛可视化」改为「低代码」,我过后回复说不改,低代码听着有点 low,「泛可视化」高大上些。起初也不晓得什么时候开始习惯了一口一个低代码,而且衍生了 Node-Code/Pro-Code。当初回想起来,过后是本人 low。 看下业界领军者对低代码的定义: outsystems: 「低代码是一种软件开发办法,能够更快地交付应用程序,并且只需很少的手工编码。低代码平台是一组工具,这些工具能够通过建模和图形界面来可视化利用程序开发。能够使开发人员能够跳过手工编码,从而放慢了将应用程序投入生产的过程。」mendix: 「低代码开发是一种可视化利用开发方法。通过低代码开发,不同教训程度的开发人员可能通过图形用户界面,应用拖放式组件和模型驱动逻辑来创立 Web 和挪动利用。低代码开发平台加重了非技术开发人员的压力,帮其免去了代码编写工作,同时也为业余开发人员提供了反对,帮忙他们提取利用开发过程中的繁琐底层架构与基础设施工作。业务和 IT 部门的开发人员能够在平台中协同,创立、迭代和公布利用,而所需工夫只是传统办法的一小部分。这种低代码利用开发方法可针对不同用例开发各种类型的利用,包含将原有利用降级为反对 IoT 的智能利用。」 能够提炼出几个词:模型/建模、图形界面、拖放组件、放慢、加重。连起来就是:通过模型/建模、图形界面拖放组件能够放慢利用开发,加重了非技术开发人员的压力。其实从前端的角度看,低代码的鼻祖应该是它: 从我目前阶段的了解,低代码是这个: 以后市场剖析市场规模依据 Forrester 的报告,2019 年该畛域的规模预计为 38 亿美元,预计在 2021 年这一赛道的市场规模将增长到 152 亿美元,75% 的应用程序将在低代码平台中开发。到 2022 年该市场规模将达到 212 亿美元。 依据 Gartner 预测,到 2021 年利用开发需要的市场增长,将至多超过企业 IT 交付能力的 5 倍。到 2024 年寰球约有 65% 的应用程序都将波及低代码开发(Forrester 、Gartner 寰球最具影响力的独立钻研征询公司)。 1、领导者:行业领导者既要体现出超强的执行能力(好的产品与良好的销售业绩相匹配),又要体现出具备远见(产品翻新和相称的营销策略)的策略打算。LCAP 的领导者次要包含云 SaaS 提供商(Microsoft、Salesforce、ServiceNow),业余的低代码提供商(Mendix、OutSystems)以及混合 RPA 和低代码应用程序供应商(Appian)。这些供应商具备弱小产品能力、市场影响力以及用户体验。 2、挑战者:在市场占有率、产品能力方面与领导者的差距并不是很大,将来有能力成为该行业领导者。 3、特定畛域者:不仅能够提供低代码利用平台技术,还混合了其余技术,例如,RPA、业务流程开掘、BPM 等技术。他们是 LCAP 行业的中流砥柱,领有良好的倒退空间。 ...

March 23, 2021 · 1 min · jiezi

关于代码规范:怎么提高代码复用性

缩小代码耦合对于高度耦合的代码,当咱们心愿复用其中的一个性能,想把这个性能的代码抽取进去成为一个独立的模块、类或者函数的时候,往往会发现牵一发而动全身。挪动一点代码,就要牵连到很多其余相干的代码。所以,高度耦合的代码会影响到代码的复用性,咱们要尽量减少代码耦合。 满足繁多职责准则咱们后面讲过,如果职责不够繁多,模块、列设计大而全,那么依赖它的代码就会比拟多,进而减少代码的耦合度。依据上一点,也就会影响到代码的复用性。相同,越细粒度的代码,代码的通用性越好,越容易被复用 模块化这里的“模块”,不单单指一类形成的模块,还能够了解为单个类、函数。咱们要长于将性能独立的代码,封装成模块。独立的模块就像一块一块的积木、更加容易复用,能够间接拿进去搭建更加复用的零碎。 业务与非业务逻辑拆散越是跟业务无关的代码越是容易复用,越是针对特定业务的代码就越难复用。所以,为了复用跟业务代码无关的代码,咱们将业务和非业务逻辑代码拆散,抽取成一些通用的框架、类库、组件等。 通用代码下沉从分层的角度来看,越是底层的代码越通用、会被越多的模块调用,越是应该设计足够能够复用。个别状况下,代码,在代码分层之后,为了防止穿插调用关系凌乱,咱们只容许下层代码调用上层及同层代码之间的调用,杜绝上层代码调用下层代码、所以,通用的代码咱们尽量下沉到更上层。 继承、多态、形象、封装在讲面向对象个性的时候,咱们讲到,利用继承,能够将公共的代码抽取到父类,子类复用父类的属性和办法。利用多态,咱们能够动静地替换一段代码的局部逻辑,让这段代码可复用。除此之外,形象和封装,从更加狭义的层面、而非广义的面向对象个性的层面来了解的话、越形象、越不依赖具体的实现,越容易复用。代码封装成模块,暗藏可变的细节、裸露不变的接口,就容易复用。 利用模块等设计模式一些设计模式,也能进步代码的复用性。比方,模版模式利用多态来实现,能够灵便替换其中局部代码,整个流程模版代码可复用。 总结:最近在学习-设计模式之美(王争老师),作为对本人的要求,也会吐槽共事的代码的可读性的根底上就想好好学习,看看优良的代码怎么写,为什么这么写。这个过程是思维转变的一个过程!只有本人多看看优良的代码怎么写的才可能把代码写的越来越好,当初学到了21课,了解了SOLID,KISS,DRY等准则,也跟着老师把代码实现一遍,也去从新查问本人原来模糊不清的概念。比方接口、抽象类、trait等,更加加深了印象。

January 11, 2021 · 1 min · jiezi

关于代码规范:代码整洁之道程序员的职业素养读书笔记

本书尽管主题目为「代码整洁之道」,但其实内容次要讲的是:如何成为一个业余合格的程序员。所以副标题作为主题目更为适合 — 「程序员的职业素养」。 程序员作为业余技术的工种,「职业素养」是咱们须要在整个职业生涯中一直最求的货色,它不仅代表你单纯的技术能力(当然优良的技术水平是必须的),还代表着你解决问题和发明价值的能力。也就是说,集体的技术能力并不齐全代表你作为程序员这个职业的价值,更重要的是你对问题思考和解决的形式、对工作的承诺、共事之间的合作等,最终可能率领团队实现一个又一个看似不可能的工作! 以下我将会依据本书的书写思路,筛选几个观点,介绍大抵内容和我本人的感想,心愿对本文读者有所帮忙。 业余主义"业余主义"有很深的含意,它岂但象征着荣誉与自豪,而且明确意味着责任与任务。这两者密切相关,因为从你无奈负责的事件上不可能取得光荣与自豪。 本章节次要叙述了做一个业余工程师须要的几点要求: 承担责任理解你的畛域保持学习、训练单干与辅导理解业务畛域与客户保持一致谦虚作为了一个合格的工程师,首要一点是懂得承担责任。这一点至关重要,因为这是表明你这个人是否靠谱最显著的个性。从工作是否可能按时实现,对系统上线前的测试验证,哪怕是因为你本人的谬误导致的损失,都须要敢于承担责任,尽力实现本人承诺的事件,致力补救谬误。一旦被他人打上不靠谱的标签,那就很难再撕掉了。 第二点是咱们须要保持学习,因为技术的变革十分快,只有保持学习能力不被这个行业所遗弃,同时也保持训练,毕竟游刃有余在各行各业都实用。 最初,除了业余技术,咱们也须要也有任务去理解本人开发的模块对应的业务畛域,未必须要成为该畛域的专家,但还是须要花工夫去理解业务的背地价值和准则,知其然知其所以然。 说不能就是能,不能就是不能,不要说“试试看“ 本章次要叙述一个业余的工程师,要用于说“不”,也要懂得如何说“不”。 一个专业人士要懂得说“不”,因为只有将问题裸露进去了,才有解决问题的机会。本章作者用了一些例子来阐明,当你尽管认为项目经理分下来的工作是不可能实现的,但当你抉择不反抗,导致他认为你可能按时实现,最初引发了劫难。 所以咱们在平时的工作中,要懂得说“不”,要懂得回绝,而不是一味的承受。 而“为什么不“重要吗?文中的观点是“为什么“远不如”事实“重要,对于这一点,我认为能让决策者晓得为什么是再好不过了。 文中还特别强调了“试试看“的危害性,因为决策者往往会将“试试看”当作一个承诺,排入了他的我的项目打算中,而工程师往往想表白的只是我尽力,但什么都不保障。 这时候有个问题,我的项目管理者往往心愿工程师可能精确的预估工作量,然而工程师预估的工作量往往是「我试试看」,理论状况可能差异很大。这里我次要有两点想法:一是作为我的项目管理者,须要每天实时的理解进度,调整计划,毕竟预估的工作量往往无奈做到非常精确,有太多的因素会影响了;二是预估工作量,能够采取 PERT 办法,减少确信度。 说是本章次要讲述了承诺是什么,如何给出承诺。 做出承诺,蕴含三个步骤: 口头上说本人将会去做。心里认真对待做出的承诺。真正付诸行动。有时候咱们没方法做到本人的承诺,往往是因为咱们承诺了一件本人不是能齐全掌控的事。 当然有时有各种起因导致咱们无奈兑现承诺,这很失常。但如果你心愿你在共事的形象是一个靠谱的人,那么最重要的是尽快向本人承诺的对象收回正告,越快越好!! 当然,咱们不应该因为承诺就放弃一些底线,突破纪律和准则往往会拖慢进度,同时也要测试过代码,保障代码整洁。 工夫治理一天的工夫其实会过得十分的快,如何在这短暂的工夫内尽可能高效的工作、获得尽可能多的成绩是十分值得钻研的事件。 会议是在日常工作中无可避免的事件,然而会议同时也会节约大量的工夫。作为会议的执行人,须要确定议程和指标,确定每个议题所花的工夫以及明确的指标。 而作为会议的参与者,首先要懂得回绝会议,防止加入没有必要的会议,因为对你工夫负责的人只有你本人。 咱们日常举办过最多的会议,是站会,每个人顺次答复以下3个问题: 我昨天做了什么?我明天打算做什么?我遇到了什么问题?每个人发言不超过1分钟,目标是缩小整个站会的工夫,所以要求我的项目负责人在会议开始前就思考好要安顿的内容,而不是现场随便的想,每个人干脆利落的交代本人的工作,缩小无止境的对话交换。 本书还介绍了一种工夫治理办法:番茄工作法。这也是我当初正在应用的一种工夫安顿办法,有趣味的小伙伴能够自行去理解一下。 预估管理者和开发者对预估可能有不同的认识,管理者可能感觉预估就是承诺,而开发者往往预估只是猜想。然而不可否认,一个绝对精确的工夫预估能够让管理者做出适合的打算。 这里介绍一种预估办法:PERT,能够依据3个数字预估工作: O:乐观预估,这是十分乐观的数字,示意所有异样顺利的状况下;N:标称预估,这是概率最大的数字;P:乐观预估,思考到各种意外状况下的乐观数字。那么工作的期待实现工夫:u = (O + 4N + P) / 6 标准差(数字越大,示意期待实现工夫越不确定):v = (P - O) / 6 比方一个工作,乐观预估须要3天,标称预估须要6.25天,乐观预估须要11天,那么通过上诉的两个公式能够失去,期待实现的工夫是6.5天,标准差是1.3。 结束语当然本书还有很多内容这里没有提到,比方如何解决压力,如何合作,编码的节奏和测试等内容。尽管随着时代的倒退和本书作者所在的外国职场和国内职场的差异,有一些的内容我不尽然批准,或者感觉会难以实际。但这并不障碍本书十分值得每一个工程师都浏览一下,置信这对你成为一个更加业余的工程师是有十分大的帮忙的。

November 9, 2020 · 1 min · jiezi

关于代码规范:完全理解如何统一项目中的代码风格

对代码进行格式化,是程序员的日常。格式化很爽,然而配置相干的规定、装置对应插件却很烦。与其每次碰到问题再缓缓排查,不如一次性死记硬背。 一、代码格调是什么(Code Conventions)咱们能够依照批改后是否会影响程序运行后果来把格调分为两个局部。例如上面的代码 var a= 1;if (a=='1') console.log(true )1. Format 格局 -> format 格式化(首字母大小写以便辨别)格局,简略来说就是变量前面是否须要空格,语句前面是否须要分号等,这一类无论如何改变,都不会影响代码运行后果的局部。对格局进行扭转叫格式化。 应用如下规定对代码进行 format: 语句之后必须接分号括号头尾须要 1 个空格运算符前后须要 1 个空格var a = 1;if ( a == '1' ) console.log( true );2. Source 源码 -> (source action 源动作)源码,与格局绝对的,是被批改之后会切实影响代码运行后果的局部。对源码进行扭转叫源动作 应用如下规定对代码进行 source action: 未产生扭转的变量必须应用 const 定义必须应用 ===,禁止应用 ==const a = 1;if ( a === '1' ) console.log( true );格局加源码,形成了代码格调 定义起源:vscode 任意选中一段代码之后右键 二、格调工具格调当然是有各种各样的,有的工具能够设定本人的格调,有的工具强制应用特定格调。为了便于了解,本文只介绍业界最支流的工具(也很少有人用其余的) Prettier Prettier 专一于 Format,根本反对了前端我的项目相干的所有文件类型,包含但不限于 JavaScriptJSXVueTypeScriptCSS、Less、SCSSHTMLJSONMarkdownPrettier 最大的特点是独裁,在本身规定的几百上千条 Format 规定中,可配置的仅有 20 条。这也导致其余工具与 Prettier 并存时,都须要迁就 Prettier 的规定 ...

September 1, 2020 · 3 min · jiezi

关于代码规范:话说软件开发中的规范性

这个话题要从最近工作中接触到的一些问题说起:大略状况是这样的,公司年前收买了一家公司(以下简称Y公司),尽管行业畛域雷同,但从业务模式到技术框架都是截然不同的。咱们原有采纳的是C#、.Net架构,Y公司全栈采纳Java,Dubbo微服务架构,自己刚好在公司主导了几个Java我的项目实际,被调配到接手Y公司的局部我的项目。几个月下来,感触颇多,简记如下: 我的项目模块不足整体规划,同一性能呈现在我的项目的多个模块中,反复代码亘古未有;与第三方平台接口不标准,比方与X团的API接口中须要获取Token及加密,这样的接口本能够在一个中央对立实现,但却散落在各个中央,且用法不一;最奇葩的是明明对方的后果有返回代码(returnCode)和响应音讯(message),却偏偏要本人定义一个枚举类来解释返回代码,最要命的是这个枚举是不残缺的,后果就是有些代码找不到就抛出了一个异样”找不到对应的代码“云云,在调试过程中一头雾水—难道不能间接用人家的代码和音讯吗?对于底层协定调用没有对立封装,最典型的比方HTTP协定,简直所有的十几个我的项目中都有HttpUtil,从Header到PUT/GET/POST都要层层解决,不晓得有OkHttp,更有下层封装Retrofit能够间接用吗?还有Json解决,甚至String解决都要写一堆,还各个我的项目各自为政,后果是呈现了一堆无用的代码,臃肿还不能保障效率和正确性;    下面的问题都能够归结为代码的规范性,如果大家是一个团队,就应该互通有无,有所分工,不要反复造轮子,首先要利用曾经有的开源框架,其次要有对立的底层框架;这样既能进步整体效率,也保障了代码的稳定性和可维护性。试想,如果一个中央出了问题,比方第三方接口做了变动,那么上述的编码方式岂不是要改几十个中央?        其实规范性的重要性显而易见,大家都懂,特地是对于团队开发而言,更是如此。那为什么理论执行下来就这么难呢?其实是一个团队领导力的问题,当今互联网行业,许多是赚快钱,只求疾速上线,不出bug就行,至于怎么实现的,什么规范性、复用性,不值一提。然而认真想想,与日俱增,这些货色就变得了“负”能量,时刻在影响着你的产品质量,当然也包含老本。到最初,大家都改不动了,习惯了差,没有了改的能源,到这时候就是整个团队的悲痛了。说到底是一种文化和精力,如果一个公司只求眼前利益,没有对细节和品质的谋求,那么永远也成为不了一家平凡的公司,为之工作的员工也只能糊里糊涂,打更混日子了! ![SourceCode.jpg](/img/bVbKy4O)

July 31, 2020 · 1 min · jiezi

关于代码规范:可读代码编写炸鸡三-审美

大家好,我是多选参数的一员 —— 大炮。 在上一篇 可读代码炸鸡二(下篇) - 命名的歧义 的结尾处,提到了接下来的炸鸡会围绕 多行代码,多个函数 的代码范畴来探讨代码可读性的优化。 由这个思路走的话,那么接下来的炸鸡大抵会分成两个内容: 代码审美代码正文所以本篇炸鸡将探讨 代码审美 对于可读性的作用。 准则统一布局,让读者很快习惯。类似代码看起来要类似。相干代码分组分块。须要辨别于设计这只是代码外观组织上的优化,并非代码外部逻辑构造的重构优化。 然而审美上的要求在肯定水平上会影响到代码外部逻辑构造。 为啥审美重要喏,实际出真知。显著如下代码就是很差劲的代码编写。 class hamBurgerShop { public: // 敌无不斩,斩无一直void Add(double d); // 减少一个货色 private: int count; /* 多少 */ public:double Average(); private: double minimum; list<double> past_items ;double maximum;};而后做一点审美层面的批改,你再看看,可读性霎时进步。 // 汉堡店类 - 其实这个正文不必加。class hamBurgerShop { public: void Add(double d); double Average(); private: list<double> past_items; int count; // 多少个汉堡 double minimum; double maximum;};代码中提到了一件事,也作为一个问题抛给大家。 为什么汉堡店类不须要正文?这个问题会留到下一篇或者下下一篇炸鸡给出一些见解。 ...

July 20, 2020 · 4 min · jiezi

Maven项目分析剔除无用jar引用

一、为什么要做这件事?项目持续研发,不停地在上面新增功能,新增特性,引入新的框架和组件,jar包依赖多并且复杂,再加上需求各种变更,有不少已经存在的功能下线,但jar包依赖没人管,还是放在项目的pom.xml文件里。项目持续的时间一长,经常会出现项目打包要求内存多,时间慢的问题,如何分析项目中哪些依赖是有用的,哪些可以剔除的,一方面减轻打包内存占用多,时间慢的问题,另一方面照顾研发童鞋的强迫症问题(容不得半点无用jar包在我的项目里),这事就可以提上日程了。 二、怎么做?如果是Maven项目,执行起来还是比较简单,Maven自己提供了一个检测工具,输入命令即可。在IDEA中,切换到Terminal窗口,或者用命令行打开相应工程目录,直接输入 mvn dependency:analyze查看控制台输出的日志,重点关注这两部分: [WARNING] Used undeclared dependencies found:[WARNING] com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile[WARNING] com.fasterxml.jackson.core:jackson-databind:jar:2.9.9:compile[WARNING] io.jsonwebtoken:jjwt:jar:0.9.0:compile[WARNING] org.apache.rocketmq:rocketmq-common:jar:4.5.2:compile[WARNING] org.springframework:spring-beans:jar:5.1.8.RELEASE:compile[WARNING] com.google.code.gson:gson:jar:2.8.0:compile[WARNING] org.springframework.boot:spring-boot:jar:2.1.6.RELEASE:compile[WARNING] com.fasterxml.jackson.core:jackson-core:jar:2.9.9:compile[WARNING] org.springframework:spring-core:jar:5.1.8.RELEASE:compile[WARNING] org.apache.rocketmq:rocketmq-remoting:jar:4.5.2:compile[WARNING] Unused declared dependencies found:[WARNING] org.projectlombok:lombok:jar:1.16.20:provided[WARNING] org.springframework.boot:spring-boot-starter-test:jar:2.1.6.RELEASE:testUsed undeclared dependencies found间接依赖,就是说你在当前项目工程的pom.xml里没有直接声明,这个依赖是由你声明过的dependency里的pom.xml依赖传递得来的。例如org.apache.rocketmq:rocketmq-common:jar:4.5.2:compile是你引用了这个: <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.5.2</version></dependency>Maven本来就是这样用的,也不建议说你把这部分引用拷贝到你的pom.xml里,一般来说这部分的WARNING可以忽略。 Unused declared dependencies found无用依赖,这个指我们在pom.xml声明了这个jar包的依赖,但在项目工程里没有使用到,这个不是我们此次关注的重点,确定不需要,就可以剔除掉这个依赖,Reimport后这个jar包就从我们项目中剔掉了。 三、什么时候做?1)新项目建立时,引用jar包时要慎重,不要一股脑儿直接拷贝老项目的依赖,避免后期又花时间来剔除。2)功能代码重构时,可以适当做一次剔除,因为后面还有自测,提交测试环节,如果有误删,测试的时候能发现。 四、有什么风险要注意的?1)这个检测的结果仅供参考,有时也不准确,如上文提及的org.projectlombok:lombok:jar:1.16.20:provided,实际上在项目中有使用到它的注解@Data,这个属于误判。要注意剔除依赖后多测试,工具毕竟有毕竟的缺陷性。2)如果童鞋们接手遗留的老项目时,这种问题肯定很多,但刚接手时不建议做这个操作,因为本身对项目不熟悉,上来就删东西导致问题会浪费很多时间和精力搞定依赖的问题,这块东西建议暂时先不要动。 五、补充一个小插件查看pom.xml的依赖关系时,可以在IDEA上安装maven help插件,可以直观地看到各jar依赖关系 专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号

October 15, 2019 · 1 min · jiezi

前端代码质量圈复杂度原理和实践

写程序时时刻记着,这个将来要维护你写的程序的人是一个有严重暴力倾向,并且知道你住在哪里的精神变态者。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循环、三元运算符等等,都属于一个判定节点,例如下面的代码: function 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语句,一个三元运算符,所以代码复杂度为 4+1+1=6。另外,需要注意的是 || 和 && 语句也会被算作一个判定节点,例如下面代码的代码复杂为3: ...

October 14, 2019 · 4 min · jiezi

代码美化的艺术

Ng-Matero 中文版文档已经发布 点击查看前言原本只是想简单的聊一下代码格式化的问题,无奈本文拖沓了很久,在此期间,我又思考了很多,我越来越觉得代码格式化是一门艺术。为了衬托“艺术”二字,可能叫“代码美化”更贴切一点,但是本文的深度远没有标题那么宏大。 在我看来,代码质量不仅体现在逻辑上,也要体现在形式上。尤其前端代码,在日渐复杂的单页面开发中,代码格式化不仅是为了美观,也是为了更好的阅读。关于代码的格式化并没有统一的标准,每个人都有自己的见解,所以本文的目的以探讨和推荐为主。 可能很少有人会去考虑这方面的问题,毕竟美化插件都是现成的,比如常用的 Prettier,只要一个快捷键就可以迅速格式化,但是代码格式化插件的标准并不一定是最好的。 本文范例主要以 Angular 为主,但是代码美化的建议同样适用于 React 和 Vue。 每行代码多少字符合适?关于代码字符数一直是一个争论不休的问题。在 Python编码风格指导(PEP8) 规定了每行不超过 80 个字符。Prettier 默认也是 80 个字符。 赞成这条规范的人认为 80 个字符紧凑美观,在大屏显示器也可以分多栏显示。如下图所示: 我最开始也是赞成 80 个字符的建议,但是当我遵循这条规范写了近一年的 Angular 代码之后,我发现这条规范有一些缺陷。 首先这条规范是 Python 编码风格的建议,而 Python 的代码是以缩进代表代码块,类、函数等在定义时也没有大括号及小括号,算上括号前的空格,这就比一般的代码少几个字符。 其次现代的编程模式大多是面向对象的风格,类的继承、接口实现等都可能导致代码很长,在 Angular 中可能还会实现多个钩子函数的接口。 另外,Angular 的风格指南建议不要为了精简变量命名而损失易读性,所以很多时候函数命名可能很长,再加上类型系统及链式调用等,单行代码很容易超过 80 个字符,这样会造成过多的折行。 下面是一段使用 80 字符宽度格式化的 TS 代码: 我们再看一下扩大到 100 字符之后的效果: 这段代码或许还不是最典型的例子,但是也能看出两者的不同,在实际的业务当中,类似的折行可能更多,而从我个人的角度来看,过多的折行反而破坏了代码的完整度。目前常用的代码宽度有三种,分别是 80、100、120,很显然,80 太短,120 太长,以中庸之道,取 100 刚好。 模板格式化代码宽度对模板(html)的影响也很大,下面我们重点聊一下关于模板的格式化问题。以下是使用 Prettier 的默认设置格式化的效果。 上面这种格式化方案非常普遍,但是我个人并不喜欢这种格式化的效果,原因有以下几点: 开始标签末尾的尖括号看上去有点突兀。所有属性全部换行,整体有些松散,模板代码可能变得很长。标签和属性的区分度不高。我比较喜欢下面的格式化方案,整齐紧凑,属性之间对齐,标签一目了然。 简单说一下上面这种格式化效果的方法:需要使用 VSCode 默认的 HTML 格式化插件。在 首选项-设置-扩展-HTML,设置 Wrap Attributes 属性,选择 preserve-aligned(保留属性的包装,但对齐),这个选项允许多个标签单行显示。 ...

September 20, 2019 · 1 min · jiezi

随时发布REST-API文档的代码仓库中的持续集成与协作

本文主要内容:API文档提供了预测客户成功的关键路径;在代码附近的文档上进行协作可以更好地检查代码和文档文件,提高自动化效率,并专门针对文档进行质量测试;提供通用文档框架,标准,自动化和工具,以提高团队效率。编写文档有时候会非常枯燥乏味,但优秀的文档是增加API被采用的一个很好的前提。编写出色的文档与编写代码一样需要严谨。随着API的质量逐渐成为产品增长的指标,您的文档比以往任何时候都更加重要,优秀的文档很大程度上代表创建了成功的API。API定义和文档常常结合在一起,虽然今天的API规范越来越多地作为GitHub中的代码进行管理,但API文档并非如此。所以需要让我们对此进行更改,以便在GitHub和相关代码库中编写和管理API文档(包括相关网站)的标准。 通过尽可能靠近代码和API定义协作编写文档,您可以自动执行文档测试,构建和部署。API的文档通常构建为网站,因此如果在分段构建期间就可以进行链接检查等测试。这种方法提供了许多好处:经过测试的文档构建;支持连续发布;支持对文档内容和代码的评论;多个输出(包括经过测试的代码示例);文档的发布管理(如API的早期访问版本)或增量更改和添加到发布了API,并防止代码合并。 文档持续集成/交付对于REST API文档,三个框架以网页的形式提供文档输出,其中许多是交互式的。这些是OpenAPI(Swagger),RESTful API建模语言(RAML)和API蓝图。OpenAPI(以前称为Swagger)基于JSON输出,由于YAML是JSON的超集,因此您可以交换描述API的源文件。RAML是一种基于YAML的语言,用于描述REST API。API Blueprint使用Markdown,也可以遵循GitHub Flavored Markdown语法。 许多编程语言都有一个文档框架,可以很好地与代码本身集成。通常,这些是静态站点生成器,例如Jekyll for Ruby和Sphinx for Python。文档的源文件是Markdown或reStructured Text(RST)。使用这些静态站点生成器,您可以创建漂亮的文档站点。事实上,GitHub上有一系列链接到漂亮的文档网站,其中包括Stripe API文档站点和Basho文档 - 这些是获得美观和实用程序最高分的示例API站点。 由于可以使用脚本转换这些文档源文件和网站配置文件,因此您可以使用与代码相同的构建作业来持续构建文档。通过从静态目录复制平面文件来部署Jekyll站点,因此您可以存储脚本以使用其他构建文件在代码存储库中构建站点。您还可以使用简单的链接检查程序在部署站点之前测试任何损坏的链接。HTMLProofer库是一个为此而编写的Ruby库。 GitHub提供的部署机制称为GitHub Pages。您可以选择触发文档网站部署。您可以从gh-pages分支,主分支自动化构建,或始终从主分支上的/ docs目录部署文档。虽然您可以部署到自定义域名,但GitHub页面的一个限制是您不能直接通过HTTPS提供服务,但作为免费服务,它是一个很好的起点。对于生产网站,您可以从GitHub部署到具有所需安全要求的云服务器或VPS。而GitHub Enterprise是GitHub的内部部署,用于内部部署,提供类似的托管站点功能。 为什么要像代码一样处理文档当成果已经可以交付给开发人员时,那与开发人员一起写文档会很有效。API文档任务为处理代码等文档的原因和时间提供了一个很好的示例。特别是在设计API或向API添加功能时的关键设计点,开发人员可以像文档代码一样贡献文档。 例如,在自动化参考信息时,您可以获得即时性和准确性,并通过在GitHub,Bitbucket或GitLab等社交编码系统中协作编写来获得贡献,质量和同理心。此外,API的最大成功指标之一是文档的准确性和有用性。当您的团队处理代码等API文档时,以下是一些特定的好处,下面将对此进行更深入的探讨: 1.协作效率可以为开发人员和文章协作编写者两个角色提供有价值的信息。开发人员希望为类似于自己的受众撰写文章,为读者提供经验分享。协作编写者有一个特殊的诀窍来组织信息,文笔更好,并以适当的顺序揭示概念和参考信息。如果在同一个存储库中协同工作可以提供沟通的效率,增加教学和被教学的机会。 2.贡献收益当没有专门的技术写作团队时,你可以扩大贡献者的数量,即使API本身不是公共文档的公共文件。或者,您可以通过在GitHub或Bitbucket等版本控制系统中提供开源文档存储库,从最终用户自己获得更多贡献。当文档与代码位于同一存储库中时,任何感兴趣的开发人员(包括客户)都可以订阅拉取请求的通知。 3.跟踪文档中的错误要获得更高质量的文档,请提供直接在输出页面上报告文档错误的方法。正如莱纳斯定律所述,“给予足够的眼球,所有的错误都是浅薄的”。通过为这些眼球提供报告错误的位置,您可以为文档提供更多类似代码的质量跟踪。此外,通过问题跟踪制定的指标,您可以衡量文档的质量,并确保在需要解决这些错误时可使用指标来判断。 4.对文档和代码的评论在查看代码中包含的文档时,审阅者可以在文档不足时阻止对代码的更改。该审查指南为团队提供了使文档具有高质量的能力,即使它们必须与快速变化的代码同步。 将文档源文件放在像GitHub这样的开放系统中可以使内容具有开放贡献,类似于开源代码。在OpenStack中,大量的开源云项目,文档贡献过程与代码贡献过程相同。编写者和开发人员在访问仅文档存储库(仅代码存储库)时具有相同的协作工具和背景知识。 当您的API定义需要一定程度的守门或小心防护时,您还可以考虑将GitHub Enterprise用于内部API文档。您的团队仍然可以在内部获得协作优势,而无需向全世界打开您的文档和代码。 5.部署和发布处理代码等文档时,意识到您正在将构建与部署分离。通过这种方式,您可以对文档的早期草稿进行审核,并且在文档构建部署并发布到网站之前,它都可以随时进行修正。或者,您可以选择不断发布一些文档以跟上代码。例如,您可以选择编写叙述性文档和教程,这些文档和教程会随着每个补丁集添加而不断发布。但对于像OpenAPI规范这样的合同文档,只有在考虑在特定版本下发布API时,才能部署新文档。 6.测试和构建文档通过为评论提供匹配的分段构建和向读者交付的生产构建,您可以确信您对构建的文档的审核满足用户需求。请参阅以下部分中的示例。 docs的示例测试您可以测试文档源文件的质量以及是否构建。您还可以检查拼写或语法,但也可以通过人为进行检查。但测试文档的目的是减轻人类审阅者的审查负担,自动化能节省时间,以便可以编写,发布和发布更多文档文件。 链接检查对于许多静态站点生成器,有专门用于检查站点中所有链接的库。例如,在检查像docslikecode.com这样的Jekyll网站上的链接时,Travis CI工作很简单: #!/usr/bin/env bashset -e # halt script on errorbundle exec jekyll buildbundle exec htmlproofer ./_site通过这种类型的测试,人工审阅者不必花时间点击新补丁中的每个链接。如果需要更新外部链接,那么这个测试的结果会通知您。如果内部链接因修补程序本身而中断,则系统可以在人为查看修补程序之前修复它。 JSON格式使用REST API文档,请求和响应通常是JSON文件,对于阅读文档的人在将自己的环境与文档进行比较时非常有价值。在读者需要复制和粘贴请求的情况下,正确格式化示例至关重要。在OpenStack中,我们有一组包含JSON测试器和格式化程序的通用文档工具。通过对传入的修补程序对文档文件运行此测试,读者可以确定所包含的JSON文件是否格式正确。此外,当它们可以在本地运行简单命令以确保JSON格式正确时,它可以使贡献者更容易创建补丁。 验证的请求和响应高级文档测试可以检查文档中包含的示例请求和响应。用查看代码文件相同的方式查看文档文件时,准确性通常是最高值。因此,通过针对正常工作的API端点测试示例,您可以证明这些示例也适用于实际情况。这种类型的验证提供了每次都可用的成功文档示例,因为只有它们通过验证测试,它们才被发布。 建立检查自动化文档测试可以节省读者的时间,因为他们不必自己构建文档来查看输出。此外您可以测试损坏的链接或不正确格式化的JSON文件的构建。对于任何奇怪的问题,查看源文档和输出文档都很有帮助。 结论在与代码库相同的仓库中协同处理文档,可以更好地为客户提供服务,无论他们是组织的内部还是外部。通过将API文档视为代码,您可以找到自动化途径,提高效率,加快文档构建,在文档中构建成功示例。 自动化测试功能除了能减少开发的时间之外,自动化测试还有助于进行项目流程测试,最近因为一直在使用EOLINKER进行API研发管理,因此推荐自动化测试功能,因为它支持UI模式和高级模式,可以实现不同类型的自动化测试项目,比如登录验证就可以用UI模式,高级模式则用来测试较为复杂的项目,对比之前效率高了不少,对API自动化测试等方面有兴趣的小伙伴前往了解下哦!https://www.eolinker.com 作者:Anne Gentle,思科的技术产品经理; 原文标题:Always Be Publishing: Continuous Integration & Collaboration in Code Repositories for REST API Docs; ...

July 9, 2019 · 1 min · jiezi

译编写更好的-JavaScript-条件式和匹配条件的技巧

原文地址:Tips and Tricks for Better JavaScript Conditionals and Match Criteria原文作者:Milos Protic介绍如果你像我一样乐于见到整洁的代码,那么你会尽可能地减少代码中的条件语句。通常情况下,面向对象编程让我们得以避免条件式,并代之以继承和多态。我认为我们应当尽可能地遵循这些原则。 正如我在另一篇文章 JavaScript 整洁代码的最佳实践里提到的,你写的代码不单单是给机器看的,还是给“未来的自己”以及“其他人”看的。 从另一方面来说,由于各式各样的原因,可能我们的代码最终还是会有条件式。也许是修复 bug 的时间很紧,也许是不使用条件语句会对我们的代码库造成大的改动,等等。本文将会解决这些问题,同时帮助你组织所用的条件语句。 技巧以下是关于如何构造 if...else 语句以及如何用更少的代码实现更多功能的技巧。阅读愉快! 1. 要事第一。小细节,但很重要不要使用否定条件式(这可能会让人感到疑惑)。同时,使用条件式简写来表示 boolean 值。这个无须再强调了,尤其是否定条件式,这不符合正常的思维方式。 不好的: const isEmailNotVerified = (email) => { // 实现}if (!isEmailNotVerified(email)) { // 做一些事...}if (isVerified === true) { // 做一些事...}好的: const isEmailVerified = (email) => { // 实现}if (isEmailVerified(email)) { // 做一些事...}if (isVerified) { // 做一些事...}现在,理清了上面的事情后,我们就可以开始了。 2. 对于多个条件,使用 Array.includes假设我们想要在函数中检查汽车模型是 renault 还是 peugeot。那么代码可能是这样的: const checkCarModel = (model) => { if(model === 'renault' || model === 'peugeot') { console.log('model valid'); }}checkCarModel('renault'); // 输出 'model valid'考虑到我们只有两个模型,这么做似乎也还能接受,但如果我们还想要检查另一个或者是几个模型呢?如果我们增加更多 or 语句,那么代码将变得难以维护,且不够整洁。为了让它更加简洁,我们可以像这样重写函数: ...

June 25, 2019 · 4 min · jiezi

代码整洁之道读书笔记

看完《代码整洁之道》之后我受益匪浅,但等到自己实践时却很难按照书中给的建议编写出整洁的代码。 一方面是规则太多,记不住,另一方面书上引用了大量示例代码对这些规则进行佐证,在我记不住的时候亦不方便我查阅。于是我把书中的规则摘了出来并加以一定的解释,闲暇时候多过几遍,希望这些规则时刻警示我,成为我的习惯。 想看此书却还没开始的人也可以从这篇笔记出发,对笔记中列出的规则有疑问再翻书找答案,相信会比直接啃书来的快一些。 ps: 未必要严格遵循书中的规则,代码不是八股文。 命名1.避免误导"一组账号"别用accountList表示,List对程序员有特殊含义,可以用accountGroup、bunchOfAccounts、甚至是accounts不使用区别较小的名称,ZYXControllerForEfficientHandlingOfStrings和ZYXControllerForEfficientStorageOfStrings难以辨别不使用小写l、大写O作变量名,看起来像常量1、02.做有意义的区分不以数字系列命名(a1、a2、a3),按照真实含义命名Product/ProductInfo/ProductData 意思无区别,只统一用一个别写冗余的名字,变量名别带variable、表名别带table3.使用可搜索的名称单字母名称和数字常量很难在上下文中找出。名称长短应与其作用域大小相对应,越是频繁出现的变量名称得越容易搜索(越长)4.命名时避免使用编码把类型和作用域编码进名称里增加了解码负担。意味着新人除了了解代码逻辑之外,还需要学习这种编码语言。别使用匈牙利语标记法(格式:[Prefix]-BaseTag-Name 其中BaseTag是数据类型的缩写,Name是变量名字),纯属多余不必用"m_"前缀来表明成员变量接口和实现别在名称中编码。接口名IShapeFactory的前导"I"是废话。如果接口和实现必须选一个编码,宁可选实现,ShapeFactoryImp都比对接口名称编码来的好5.类名、方法名类名应当是名词或名词短语,方法名应当是动词或动词短语6.每个概念用一个词fetch、retrieve、get约定一个一直用即可7.别用双关语add方法一般语义是:根据两个值获得一个新的值。如果要把单个值加入到某个集合,用insert或append命名更好,这里用add就是双关语了。8.添加有意义的语境很少有名称能自我说明,需要用良好命名的类、函数、或者命名空间来放置名称,给读者提供语境,如果做不到的话,给名称添加前缀就是最后一招了。函数1.越短小越好if/else/while语句的代码块应该只有一行,该行应该是一个函数调用语句。函数的缩进层级不应该多于一层或两层。2.只做一件事如果函数只是做了该函数名下同一抽象层上的步骤,则函数只做了一件事。要判断函数是否不止做了一件事,就是要看是否能再拆出一个函数。3.每个函数一个抽象层级4.switch语句把switch埋在较低的抽象层级,一般可以放在抽象工厂底下,用于创建多态对象。5.使用描述性的名称函数越短小、功能越集中,就越便于取个好名字。别害怕长名称,长而具有描述性的名称,要比短而令人费解的名称好,要比描述性的长注释好。别害怕花时间取名字。6.函数参数参数越少越好,0参数最好,尽量避免用三个以上参数参数越多,编写组合参数的测试用例就越困难别用标识参数,向函数传入bool值是不好的,这意味着函数不止做一件事。可以将此函数拆成两个。如果函数需要两个、三个或者三个以上参数,就说明其中一些参数应该封装成类了。将参数的顺序编码进函数名,减轻记忆参数顺序的负担,例如,assertExpectedEqualsActual(expected, actual)7.副作用(函数在正常工作任务之外对外部环境所施加的影响)检查密码并且初始化session的方法 命名为checkPasswordAndInitializeSession而非checkPassword,即使违反单一职责原则也不要有副作用避免使用"输出参数",如果函数必须修改某种状态,就修改所属对象的状态吧8.设置(写)和查询(读)分离if(set("username", "unclebob")) { ... } 的含义模糊不清。应该改为: if (attributeExists("username")) { setAttribute("username", "unclebob"); ...}9.使用异常代替返回错误码返回错误码会要求调用者立刻处理错误,从而引起深层次的嵌套结构: if (deletePate(page) == E_OK) { if (xxx() == E_OK) { if (yyy() == E_OK) { log(); } else { log(); } } else { log(); }} else { log();}使用异常机制: try { deletePage(); xxx(); yyy();} catch (Exception e) { log(e->getMessage());- try/catch代码块丑陋不堪,所以**最好把try和catch代码块的主体抽离出来,单独形成函数**try { do();} catch (Exception e) { handle();}```函数只做一件事,错误处理就是一件事。如果关键字try在某个函数中存在,它就该是函数的第一个单词,而且catch代码块后面也不该有其他内容。定义错误码的class需要添加新的错误码时,所有用到错误码class的其他class都得重新编译和部署。但如果使用异常而非错误码,新异常可以从异常class派生出来,无需重新编译或部署。这也是开放闭合原则(对扩展开放,对修改封闭)的范例。10.别重复自己重复是软件中一切邪恶的根源。当算法改变时需要修改多处地方11.结构化编程只要函数保持短小,偶尔出现的return、break、continue语句没有坏处,甚至还比单入单出原则更具有表达力。goto只有在大函数里才有道理,应该尽量避免使用。12.如何写出这样的函数并不需要一开始就按照这些规则写函数,没人做得到。想些什么就写什么,然后再打磨这些代码,按照这些规则组装函数。注释若编程语言足够有表现力,我们就不需要注释。注释总是一种失败。代码在演化,注释却不总是随之变动。不准确的注释比没注释坏的多。1.用代码来阐述创建一个与注释所言同一事物的函数即可 ...

June 24, 2019 · 2 min · jiezi

对Android和iOS项目中的模块结构和类结构设计的探讨

现有的代码规范缺少探讨的部分1.1 关于项目的代码结构通常来说,一个项目由多个模块组成;一个模块由多个类组成;一个类由多个方法组成;一个方法由多条语句组成;按照代码粒度从大到小,可以划分为三个级别,并且分别对应IDE(XCode、Android Studio)的三个不同的视图: 项目结构,包括模块和类的组织——红框视图;类结构,包括属性和方法的组织——绿框视图;方法结构,包括变量和语句的组织——蓝框视图;Xcode的三种视图(如下图) Android Studio的三种试图(如下图) 1.2 关于现有代码规范对于Android和iOS的现有代码规范,有大量的公司和大神进行了细致的探讨。其中,最有影响力的,笔者认为是苹果爸爸和阿里妈妈的两个版本——《Introduction to Coding Guidelines for Cocoa》、《阿里巴巴Android开发手册》。强烈推荐大家进行学习。1.3 本文探讨的代码规范但笔者发现,大部分现有的代码规范,讨论的主题都是命名规范、书写格式要求、特定技术点的处理要求等内容,关注点都是项目中具体代码细节,也就是蓝框部分的内容。但对于更大粒度的红框和绿框部分,也就是项目中模块和类的组织以及对类中方法的组织,讨论的并不多。而在实际工作中,一位新员工加入公司,当然必须先学习公司的代码规范,明晰代码编写时需要注意的事项。然而,新员工加入实际项目后,首先看的其实并不是代码细节,而是项目代码的组织架构。一个具有良好组织结构的项目代码,可以让新员工在不看代码细节的前提下,直接了解项目的整体架构。本文介绍的内容,就是通过对红框和绿框部分的设计,来探讨如何搭建一个“具有良好组织结构的项目”。 模块结构设计的探讨一个好的项目结构,应该对模块和类的组织进行设计,实现不看实现细节,能够大概了解 项目功能 和 类功能;以下,分别使用Android和iOS两个例子进行说明。背景介绍本文举例的项目源码在这两个GitHub项目上:polyv-ios-cloudClass-sdk-demo、 polyv-android-cloudClass-sdk-demo Demo项目是一个直播项目,包括两个页面,第一个是登录页,第二个是观看页。运行项目,会先进入登录页,登录成功后,会进入观看页。2.1 iOS的例子好的项目结构(如下图) 不好的项目结构(如下图) 好的项目结构,能够不看具体代码,而是能够 随着项目结构的逐层展开 直接获取到如下信息:在项目中,有 Login(登录)和 Watch(观看)两个模块;在 Login 模块 的主页面是 PLVLoginViewController(登录页);在 Watch 模块 的页面包括 PLVLiveViewController(直播观看页) 和 PLVVodViewController(点播观看页);在 Watch 模块有两个子模块,分别是 Media(视频区)和Charroom(聊天室);在 Media(视频区)模块中,看到有三种 MediaViewController;看命名差异,可以发现是有两个维度划分的,分别是 Normal / PPT 、Live / Vod ;在 Base 文件夹中,看到 PLVBaseMediaViewController ,猜测是三种 MediaViewController 的父类;在 Base 文件夹中,看到 PPT 和 Live 两个文件夹,结合其中的 PLVBaseMediaViewController+PPT 和 PLVBaseMediaViewController+Live 两个catagory,可以猜测是在 父类 PLVBaseMediaViewController 的基础上增加 PPT 和 Live 两个维度的功能扩展;一些建议把 功能模块所使用的resource 放在 功能模块目录 下,是一个好的处理; ...

June 19, 2019 · 1 min · jiezi

通熟易懂的设计模式二

组合模式(Composite pattern)组合模式看起来就像对象组的树形结构,一个对象里面包含一个或一组其他的对象。它是属于结构型模式。例如,一个公司包括很多个部门,每个部门又包括很多人,这个用数据结构来表示就是树形结构,实际上也是用到来组合模式,多个人组成一个部门,多个部门组成一个公司。 例如,我们用下面这个公司、部门、员工的例子来更好的理解组合模式。 class Company { private String name; private List<Dept> depts;}class Dept { private String name; private List<User> users;}class User { private String name;}装饰模式(Decorator pattern)装饰器设计模式允许我们动态地向对象添加功能和行为,而不会影响同一类中其他现有对象的行为。并且可以根据我们的要求和选择将此自定义功能应用于单个对象。假如使用继承来扩展类的行为,这发生在编译期,该类的所有实例都获得扩展行为。 装饰器设计模式的特点:它允许我们在运行时向对象(而不是类)添加功能。它是一种结构模式,它为现有类提供了一个包装器。它使用抽象类或接口与组合来实现包装器。它创建装饰器类,它包装原始类并通过保持类方法的签名不变来提供其他功能。它最常用于应用单一责任原则,因为我们将功能划分为具有独特关注区域的类。 例如,我们用下面这个画图形的例子来更好的理解装饰模式。 //定义一个形状的接口public interface Shape { void draw(); void resize();}//一个画圆的实现public class Circle implements Shape { @Override public void draw() { System.out.println("Drawing Circle"); } @Override public void resize() { System.out.println("Resizing Circle"); }}//一个画矩形的实现public class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing Rectangle"); } @Override public void resize() { System.out.println("Resizing Rectangle"); }}//定义一个形状的装饰器抽象类,并用组合模式定义一个形状的属性public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape) { super(); this.decoratedShape = decoratedShape; }}//颜色的枚举public enum Color { RED, GREEN, BLUE}//线条样式的枚举public enum LineStyle { SOLID, DASH, DOT}//定义一个填充颜色的实现类实现装饰器,并重写 draw() 方法,resize() 方法我们可以保持不变,也可以自定义,看使用场景public class FillColorDecorator extends ShapeDecorator { protected Color color; public FillColorDecorator(Shape decoratedShape, Color color) { super(decoratedShape); this.color = color; } @Override public void draw() { decoratedShape.draw(); System.out.println("Fill Color: " + color); } @Override public void resize() { decoratedShape.resize(); }}//定义一个线条样式的实现类实现装饰器,并重写 draw() 方法,resize() 方法我们可以保持不变,也可以自定义,看使用场景public class LineStyleDecorator extends ShapeDecorator { protected LineStyle style; public LineStyleDecorator(Shape decoratedShape, LineStyle style) { super(decoratedShape); this.style = style; } @Override public void draw() { decoratedShape.draw(); System.out.println("Line Style: " + style); } // @Override public void resize() { decoratedShape.resize(); }}//使用装饰器模式public class Client { public static void main(String[] args) { //在使用时可以任意组装,提升代码灵活性和扩展性。 Shape circle = new FillColorDecorator(new LineStyleDecorator(new Circle(), LineStyle.DASH), Color.RED); circle.draw(); }}外观模式(Facade Pattern)它提供了一个可以访问系统的接口,这个接口里面的实现可能很复杂,调用了其他多个接口,我们并不知道它里面的具体实现,隐藏了系统的复杂性。它属于结构型模式。 ...

June 12, 2019 · 5 min · jiezi

通熟易懂的设计模式一

写在前面评判一个程序员是否优秀,就是 show me the code。优秀的代码可读性强,高内聚低耦合,可扩展。想要写优秀的代码,做个优秀的程序员,就需要多看看大牛写的开源框架,吸取其中的精华,多学学设计模式,除此之外,没有任何其他捷径。 设计模式主要分为创建型模式、结构型模式、行为型模式三种类型。 工厂方法(Factory method pattern)定义一个创建对象的接口,让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行,它属于创建型模式。 工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象。这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象。 工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。 维基百科工厂方法的例子 // 定义了 Button 如何创建public interface Button{}// 实现了 WinButton public class WinButton implements Button{}// 实现了 MacButton public class MacButton implements Button{}// 创建 Button 的工厂类public interface ButtonFactory { Button createButton();}// 真正创建 WinButton 的实现类,实现了 ButtonFactorypublic class WinButtonFactory implements ButtonFactory { @Override public static Button createButton(){ return new WinButton(); }}// 真正创建 MacButton的实现类,实现了 ButtonFactorypublic class MacButtonFactory implements ButtonFactory { @Override public static Button createButton(){ return new MacButton(); }}抽象工厂模式(Abstract factory pattern)将一组具有同一主题的单独的工厂封装起来。在使用中,使用方需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一方法的具体对象。它属于创建型模式。 ...

June 11, 2019 · 3 min · jiezi

ESLintPrettier代码规范实践

前提本文并不单独讲解 ESLint 和 Prettier 如何配置和运行。 问题想在团队中推行一定的代码规范,并给不符合规范的代码做检测和提示。 方案代码规范校验使用 ESLint,但是一开始 ESLint 只有检测告诉你哪里有问题,常常出现的情况就是一堆 warning,改起来很痛苦。后来 ESLint 提供了 $ ESLint filename --fix 的命令可以自动帮你修复一些不符合规范的代码。Prettier 是一个代码格式化工具,可以帮你把代码格式化成可读性更好的格式,最典型的就是一行代码过长的问题。 Lint和prettier区别那 ESLint 和 Prettier 的区别是什么呢?eslint(包括其他一些 lint 工具)的主要功能包含代码格式的校验,代码质量的校验。而 Prettier 只是代码格式的校验(并格式化代码),不会对代码质量进行校验。代码格式问题通常指的是:单行代码长度、tab长度、空格、逗号表达式等问题。而代码质量问题指的是:未使用变量、三等号、全局变量声明等问题。 Lint和Prettier配合使用为什么要两者配合使用?因为,第一在 ESLint 推出 --fix 参数前,ESLint 并没有自动化格式代码的功能,要对一些格式问题做批量格式化只能用 Prettier 这样的工具。第二 ESLint 的规则并不能完全包含 Prettier 的规则,两者不是简单的谁替代谁的问题。但是在 ESLint 推出 --fix 命令行参数之后,如果你觉得 ESLint 提供的格式化代码够用了,也可以不使用 Prettier。 ESLint 和 Prettier 相互合作的时候有一些问题,对于他们交集的部分规则,ESLint 和 Prettier 格式化后的代码格式不一致。导致的问题是:当你用 Prettier 格式化代码后再用 ESLint 去检测,会出现一些因为格式化导致的 warning。这个时候有两个解决方案: 运行 Prettier 之后,再使用 eslint --fix 格式化一把,这样把冲突的部分以 ESLint 的格式为标准覆盖掉,剩下的 warning 就都是代码质量问题了。在配置 ESLint 的校验规则时候把和 Prettier 冲突的规则 disable 掉,然后再使用 Prettier 的规则作为校验规则。那么使用 Prettier 格式化后,使用 ESLint 校验就不会出现对前者的 warning。为什么不能先使用 ESLint 再使用 Prettier。针对方案1,如果你后使用 Prettier,那么格式化后提交的代码在下一次或者别人 checkout 代码后是通不过 lint 校验的。针对方案2,其实是可以的,但是本人在实践中看社区方案的时候有提到某些情况下 eslint --fix 和 prettier 混用会出现格式问题。所以保险起见还是先用 perttier 格式化,再用 eslint 命令校验,而不用 eslint --fix 命令去格式化。 ...

June 4, 2019 · 2 min · jiezi

Angular代码风格

写在前面自身的良好编码风格只能律己,而无法律人;我喜欢 Angular 其中主要一个因素是有一整套的工具及风格指南,它可以极大的简化团队开发沟通成本,但是有些小缺失例如在编码风格上官方只提供 TypeScript 的部分,对于其他文件并没有一套指南以及智能化。 VSCode 是我开发 Angular 应用的首选,本文也将以此 IDE 为基准;任何提到的扩展都可以通过市场来获取。 Angular 应用是由组件树组成,一个组件从文件来看包含:TypeScript、HTML、Less(或其他 CSS 预处理器),其中 HTML 可能被包含至 ts 文件里。 当然除此之外还包含一些 JSON 文件、Bash 文件等,当此部分不在本文讨论内。TSLintAngular 创建后就已经包含 tslint.json(它是 TSLint 的配置文件),并且所有默认规则都按官方风格指南具体践行。 而 TSLint 的配置文件,默认使用内置预设 tslint:recommended 版本,并在此基础上加入 Angular 质量检查工具 codelyzer,所有这些规则你可以通过 tslint rules、codelyzer 找到每项规则的说明。 规则的写法要么是 boolean 类型,或者使用数组对该规则指定额外参数。运行 ng lint 命令时,当你某个字符串变量使用双引号,它会提示: ERROR: /src/app/app.component.ts[9, 16]: " should be '我们也可以安装 TSLint 扩展让这个触发机制放在正在编码过程中实时反馈: 当有不符合风格指南会出现一个绿色的波浪线,按 command+. > Fix: " Should be '通过终端 PROBLEMS 面板查看所有已打开文件且不符合风格指南的明细嗯,让你按五次 command+. 快捷键,我一定会疯掉;TSLint 扩展支持在保存文件时自动修复,只需要在项目根目录 .vscode/settings.json 配置: ...

May 29, 2019 · 3 min · jiezi

使用GrumPHP来纠正代码毛病

前言我一生的文章都会放在这里,我的博客,我希望每一行代码,每一段文字都能帮助你。https://github.com/CrazyCodes...嗨,我是CrazyCodes,小时候做错事,长辈有没有训斥过你呢?今天让我们看看PHP的监护者,愤怒的老头- - grumphp GrumPHPGrumPHP 是通过挂在git hook上的一款PHP代码检测工具,他可以通过编码人员提交git时进行检查,检查通过则提交成功,检查失败则终止提交。 安装通过composer直接安装即可,不推荐其他安装方式 composer require --dev phpro/grumphp这类工具一定要放在dev内,在生产环境使用毫无意义,所以带参 --dev。 配置安装结束后会自动在项目根目录建立grumphp.yml,官方给出的demo如下 # grumphp.ymlparameters: bin_dir: "./vendor/bin" git_dir: "." hooks_dir: ~ hooks_preset: local git_hook_variables: VAGRANT_HOST_DIR: . VAGRANT_PROJECT_DIR: /var/www EXEC_GRUMPHP_COMMAND: exec stop_on_failure: false ignore_unstaged_changes: false hide_circumvention_tip: false process_async_limit: 10 process_async_wait: 1000 process_timeout: 60 ascii: failed: grumphp-grumpy.txt succeeded: grumphp-happy.txt tasks: ant: ~ atoum: ~ behat: ~ brunch: ~ clover_coverage: ~ codeception: ~ composer: ~ composer_normalize: ~ composer_require_checker: ~ composer_script: ~ deptrac: ~ doctrine_orm: ~ file_size: ~ gherkin: ~ git_blacklist: ~ git_branch_name: ~ git_commit_message: ~ grunt: ~ gulp: ~ infection: ~ jsonlint: ~ kahlan: ~ make: ~ npm_script: ~ paratest: ~ phan: ~ phing: ~ php7cc: ~ phpcpd: ~ phpcs: ~ phpcsfixer: ~ phpcsfixer2: ~ phplint: ~ phpmd: ~ phpmnd: ~ phpparser: ~ phpspec: ~ phpstan: ~ phpunit: ~ phpunitbridge: ~ phpversion: ~ progpilot: ~ psalm: ~ robo: ~ securitychecker: ~ shell: ~ twigcs: ~ xmllint: ~ yamllint: ~ testsuites: [] extensions: []参数说明参数名默认值注释bin_dir./vendor/bin方便找到phpcs这类检测工具的外部命令,一般不需要修改git_dir.默认git目录,正常都在根目录的吧hooks_dirnull设置钩子文件夹,默认会直接找 resources/hookstasks 用于加载代码检测的库实战是不是太多了,忽略上面,咱一步一步看。下面是安装完成后自动生成的配置文件 ...

May 29, 2019 · 2 min · jiezi

代码规范箭头函数的四种写法

在JS中箭头函数根据是否书写大小括号可分为以下四种情况。 // 不省略const fun = (value) => { return value;};// 省略小括号const fun = value => { return value;};// 省略大括号const fun = (value) => value;// 省略大括号与小括号const fun = value => value;airbnb-javascript关于箭头函数的检查如果函数体没有副作用的结构,省略大括号,否则使用大括号。参考这里的副作用结构是指函数内的代码影响了函数外的代码。 const even = [];[1, 2, 3, 4].forEach((num) => { if (num % 2 === 0) { even.push(num); }};注意:airbnb文档没写,函数内代码块复杂时也需要大括号。 如果参数为一个,省略小括号,否则使用小括号。参考《Google JavaScript Style Guide》中箭头函数的提议大括号可有可无,建议始终写小括号。参考 个人看法针对不同的函数结构选择是否使用括号的方式会带来两个问题: 代码不一致:就像一个PPT中不应该一会左对齐一会右对齐一会居中对齐。省略括号不易扩展:单个参数变多个参数要加小括号,直接返回代码变为多行计算后再返回代码需要增加大括号我认为有这种争议时应该选择兼容性更强的不省略大括号与小括号,在配置种关闭了对这四种写法的检查,但是遵循约定大于配置的原则,始终按照一种风格书写。 eslint的配置根据文档,在eslint中以下两个模块控制以上四种情况的书写,可对其进行配置(代码如下) arrow-parensarrow-body-style// .eslintrc.jsmodule.exports = { extends: 'airbnb', rules: { 'arrow-parens': 'off', 'arrow-body-style': 'off', },};

May 24, 2019 · 1 min · jiezi

优化你的PHP代码从现在做起

前言我一生的文章都会放在这里,我的博客,我希望每一行代码,每一段文字都能帮助你。https://github.com/CrazyCodes...大家好,我是CrazyCodes ,今天我们不聊工具、规范等等等等的辅助,就聊一下该如何写一段“好”的代码,本文以我的职业生涯碰到的代码为例,如有出入请在评论区提出异议,谢谢。 搜索功能搜索很常见,复杂的搜索大多出行在后台,举个栗子,大概需求是这样的 这是一个后台用户列表的搜索功能 搜索条件可否并行是否必填用户名可以否手机号码可以否是否已认证可以是用户性别可以否最近登录时间可以否账户余额可以否初学者代码看到这些例子你是否不由的一颤,又要开始造轮子的是不是?以原生的例子为例,开始你可能会这样写(以下为伪代码) if (IS_POST) { $like = ''; if (isset($_POST['username'])) { $username = $_POST['username']; $like .= "username like '%" . $username . "%' and "; } if (isset($_POST['phone'])) { $phone = $_POST['phone']; $like .= "phone like '%" . $phone . "%' and"; } if ($_POST['is_auth']) { $isAuth = $_POST['is_auth']; $like .= "is_auth like '%" . $isAuth . "%' and"; } if ($_POST['sex']) { $sex = $_POST['sex']; $like .= "sex like '%" . $sex . "%' and"; } if ($_POST['time']) { $time = $_POST['time']; $like .= "time like '%" . $time . "%' and"; } if ($_POST['wallet']) { $wallet = $_POST['wallet']; $like .= "wallet like '%" . $wallet . "%' and"; } $like = rtrim($like, 'and'); $sql = "SELECT * FROM `user` WHERE {$like}";} else { return view('user');}封装恩...,还不错,结构清晰,传统的初学者条型代码,接下来我们先封装一下几块代码。 ...

May 23, 2019 · 3 min · jiezi

JavaScript代码整洁之道

JavaScript代码整洁之道整洁的代码不仅仅是让人看起来舒服,更重要的是遵循一些规范能够让你的代码更容易维护,同时降低bug几率。原文clean-code-javascript,这里总结摘录出个人觉得有帮助的地方,也加入了一些自己的理解(有些文字我感觉保留原文更好,所以直接copy了),其他还有很多点没有列出来,感兴趣可以去看原文。另外这不是强制的代码规范,就像原文中说的,These are guidelines and nothing more。1. 用命名的变量代替数组下标// badconst address = “One Infinite Loop, Cupertino 95014”;const cityZipCodeRegex = /^[^,\]+[,\\s]+(.+?)\s*(\d{5})?$/;saveCityZipCode( // 下标1,2不易于理解 address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);// goodconst address = “One Infinite Loop, Cupertino 95014”;const cityZipCodeRegex = /^[^,\]+[,\\s]+(.+?)\s*(\d{5})?$/;// 使用数组解构更好的命名变量const [, city, zipCode] = address.match(cityZipCodeRegex) || [];saveCityZipCode(city, zipCode);2. 函数的参数最好<=2个,尽量避免3个。如果有很多参数就利用object传递,并使用解构。注意object array这些引用类型的值是mutable的。3. 一个函数只做一件事。好处在于compose, test, and reason about。4. 不要自行扩展原型如果想扩展原型,可以先继承再添加方法,防止污染。// badArray.prototype.diff = function diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem));};// goodclass SuperArray extends Array { diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); }}5. 用多态来代替条件语句// badif (type === ’text’) { // do something} else if (type === ‘select’) { // do something else}我个人写这种代码的一种常用方式是:const control = { text: { mapper() {}, restore(){}, name: ’this is a text field’, }, select: { mapper() {}, restore(){}, name: ’this is a select field’, }}control[type].mapper();实际上就是多态(polymorphism),也可以考虑用class的方式,大概这样:class Field { …}class TextField extends Field { mapper(){} restore(){} name = ’this is a text field’;}class SelectField extends Field { mapper(){} restore(){} name = ’this is a select field’;}6. 使用getter和setter函数。// badfunction makeBankAccount() { // … return { balance: 0 // … };}const account = makeBankAccount();account.balance = 100;// goodfunction makeBankAccount() { // this one is private let balance = 0; // a “getter”, made public via the returned object below function getBalance() { return balance; } // a “setter”, made public via the returned object below function setBalance(amount) { // … validate before updating the balance balance = amount; } return { // … getBalance, setBalance };}const account = makeBankAccount();account.setBalance(100);你可以在getter和setter里面做很多事情而不需要修改每一个.balance的地方。7. Prefer composition over inheritance尽量用组合来代替继承,什么情况下用继承:Your inheritance represents an “is-a” relationship and not a “has-a” relationship (Human->Animal vs. User->UserDetails).You can reuse code from the base classes (Humans can move like all animals).You want to make global changes to derived classes by changing a base class. (Change the caloric expenditure of all animals when they move).8. SOLIDSingle Responsibility Principle 单一职责原则There should never be more than one reason for a class to change,一个类被改变的原因数量应该尽可能降低。如果一个类中功能太多,当你修改其中一点时会无法估量任何引用该类的模块所受到的影响。Open/Closed Principle 开放封闭原则用户可以在不修改内部实现的前提下自行扩展功能。例如有一个Http模块,内部会根据环境判断用哪个adaptor。如果用户要添加adaptor就必须修改Http模块。// badclass AjaxAdapter extends Adapter { constructor() { super(); this.name = “ajaxAdapter”; }}class NodeAdapter extends Adapter { constructor() { super(); this.name = “nodeAdapter”; }}class HttpRequester { constructor(adapter) { this.adapter = adapter; } fetch(url) { if (this.adapter.name === “ajaxAdapter”) { return makeAjaxCall(url).then(response => { // transform response and return }); } else if (this.adapter.name === “nodeAdapter”) { return makeHttpCall(url).then(response => { // transform response and return }); } }}function makeAjaxCall(url) { // request and return promise}function makeHttpCall(url) { // request and return promise}// goodclass AjaxAdapter extends Adapter { constructor() { super(); this.name = “ajaxAdapter”; } request(url) { // request and return promise }}class NodeAdapter extends Adapter { constructor() { super(); this.name = “nodeAdapter”; } request(url) { // request and return promise }}class HttpRequester { constructor(adapter) { this.adapter = adapter; } fetch(url) { return this.adapter.request(url).then(response => { // transform response and return }); }}Liskov Substitution Principle 里式替换原则父类和子类应该可以被交换使用而不会出错。// badclass Rectangle { constructor() { this.width = 0; this.height = 0; } setColor(color) { // … } render(area) { // … } setWidth(width) { this.width = width; } setHeight(height) { this.height = height; } getArea() { return this.width * this.height; }}class Square extends Rectangle { setWidth(width) { this.width = width; this.height = width; } setHeight(height) { this.width = height; this.height = height; }}function renderLargeRectangles(rectangles) { rectangles.forEach(rectangle => { rectangle.setWidth(4); rectangle.setHeight(5); const area = rectangle.getArea(); // BAD: Returns 25 for Square. Should be 20. rectangle.render(area); });}const rectangles = [new Rectangle(), new Rectangle(), new Square()];renderLargeRectangles(rectangles);上面的Rectangle不能直接替换Square,因为会导致计算面积错误,考虑将计算面积的方法抽象出来:class Shape { setColor(color) { // … } render(area) { // … }}class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } getArea() { return this.width * this.height; }}class Square extends Shape { constructor(length) { super(); this.length = length; } getArea() { return this.length * this.length; }}function renderLargeShapes(shapes) { shapes.forEach(shape => { const area = shape.getArea(); shape.render(area); });}const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];renderLargeShapes(shapes);Interface Segregation Principle 接口隔离原则Clients should not be forced to depend upon interfaces that they do not use。举例来说,一个功能模块需要设计必须传的参数和可选参数,不应该强迫用户使用可选参数。Dependency Inversion Principle 依赖注入原则原文:High-level modules should not depend on low-level modules. Both should depend on abstractions.Abstractions should not depend upon details. Details should depend on abstractions.// badclass InventoryRequester { constructor() { this.REQ_METHODS = [“HTTP”]; } requestItem(item) { // … }}class InventoryTracker { constructor(items) { this.items = items; // BAD: We have created a dependency on a specific request implementation. // We should just have requestItems depend on a request method: request this.requester = new InventoryRequester(); } requestItems() { this.items.forEach(item => { this.requester.requestItem(item); }); }}const inventoryTracker = new InventoryTracker([“apples”, “bananas”]);inventoryTracker.requestItems();上面例子在于,InventoryTracker内部实例化了InventoryRequester,也就意味着high-level的模块需要知道low-level模块的细节(比如实例化InventoryRequester需要知道它的构造参数等,或者说需要import该模块,造成耦合)。// goodclass InventoryTracker { constructor(items, requester) { this.items = items; this.requester = requester; } requestItems() { this.items.forEach(item => { this.requester.requestItem(item); }); }}class InventoryRequesterV1 { constructor() { this.REQ_METHODS = [“HTTP”]; } requestItem(item) { // … }}class InventoryRequesterV2 { constructor() { this.REQ_METHODS = [“WS”]; } requestItem(item) { // … }}// By constructing our dependencies externally and injecting them, we can easily// substitute our request module for a fancy new one that uses WebSockets.const inventoryTracker = new InventoryTracker( [“apples”, “bananas”], new InventoryRequesterV2());inventoryTracker.requestItems();直接传入low-level的实例而不需要考虑它是如何被实例化的,high-level只需要依赖抽象的接口就可以完成对子模块的调用。9. 注释Comments are an apology, not a requirement. Good code mostly documents itself. 好的代码是自解释的。参考:clean-code-javascript ...

March 28, 2019 · 4 min · jiezi

上下文切换,你确定了解吗?

本文由云+社区发表作者:cocoding前言听到上下文切换,大家第一反应肯定是:一定要减少这货出现的次数。确实上下文切换对性能的影响显而易见,但有时又无法完全避免,这就要求我们对上下文性能损耗了然于胸,才能更准确地评估系统性能。另外,现在云厂商提供的机器种类如此之多,虚拟机在这方面是否有区别。以上都需要有科学的方法来衡量上下文的耗时,进而帮助系统评估以及机型选择。本文将从这以下两个方面来展开上下文切换有哪些类型以及可能出现的场景衡量各场景上下文切换耗时1, 上下文切换类型及场景上下文大体上可以分为两类进程上下文中断上下文进程上下文具体包括:(1)用户级上下文: 正文、数据、用户堆栈以及共享存储区;(2)寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);(3)系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。中断上下文具体包括:(1)硬件传递过来的参数因此上下文切换可以分为以下几类:(1)进程之间的上下文切换:A进程切换到B进程(2)进程和中断之间的上下文切换:进程A被中断打断(3)中断之间的上下文切换:低级别中断被高级别中断打断其中第一种上下文切换最为常见,第二种次之,第三种最少见,因此本文接下来主要讨论前面两种上下文切换的耗时。模式切换这是要说一种特殊的上下文切换:模式切换,即进程A从用户态因为系统调用进入内核态,这种切换之所以特殊,是因为它并没有经过完整的上下文切换,只是寄存器上下文进行了切换,所以模式切换的耗时相对完整进程上下文更低。虽然模式切换较完整上下文切换耗少,但仍不能小觑,在物理机上,一次系统调用(以SYS_gettid为例)在5060ns。(本文所有数据均是Intel(R) Xeon(R) V4和V5 CPU上得到)而在虚拟机上,一次系统调用更是可能达到240ns ,从perf来看,system_call_after_swapgs函数消耗CPU较物理机多很多,网上有人说可能是为了解决Spectre漏洞,在每次系统调 用返回用户空间时,会清理一次BTB(branch target buffer),需要进一步确认。1.png因此,我们在代码里面也要尽量减少系统调用,常见的优化方法有:每次读写磁盘时,使用buffer减少read/write调用次数等。2,上下文切换性能评估测试上下文切换性能的工具有unixbenchtsuna/contextswitch两个工具的原理类似,都是创建两个进程,然后互相唤醒:(1) unixbench是创建两个进程,两个进程之间创建两个管道(pipe),通过管道来互相读写数据,结果是10s内完成的切换次数。(2) contextswitch同样是创建两个进程,通过futex(快速用户区互斥)来互相唤醒,结果是循环500000次的耗时进程之间的上下文切换使用这两个工具在测试进程上下文时,需要注意一点:把两个进程绑定到同一个核上运行,否则可能测试的就不仅仅是进程上下文切换了,下面会介绍不绑核的情况。unixbenchtaskset -c 1 ./Run -c 1 context1对于contextswitchtaskset -c 1 ./timectxsw或者直接运行make或者./cpubench.sh2.png从上图可以看到,一次ctx的耗时在10121263ns ,但其实perf看,绑核情况下,运行timectxsw实际的ctx是在300w次(这里一次循环需要6次ctx),所以实际的ctx应该是674842ns3.png进程和中断上下文切换上文提到如果要测试进程上下文切换耗时就一定要绑核,否则测试的很可能会包含进程和中断上下文切换的耗时,因为默认内核会把测试程序产生的进程调度到不同的核上,进程之间的唤醒,需要先发送IPI中断,对方CPU在收到IPI中断之后,会完成一次中断上下文切换,执行中断函数,进而再唤醒相应进程。所以在不绑核的情况下,测试的就包含了进程-中断上下文以及中断处理函数的耗时。4.pngunixbench 如果使用unixbench在腾讯云上,默认调度到1个核上,这样就测试的进程上下文切换,所以需要手动修改代码绑核,或者用git上的unixbench-fix,强制将两个进程放到不同的核上5.pngcontextswitch contextswitch这里还增加了在同一个NUMA上的测试,从测试数据看,两个进程如果调度到同一个NUMA上时,耗时会更短。6.png从测试数据看:如果两个进程跨NUMA,一次上下文切换的耗时在2500ns如果两个进程在同NUMA,一次上下文切换的耗时在1500ns在虚拟机里面,跨核的上下文切换会更大,因为vcpu无法处理IPI中断,需要退出的宿主机上处理,从而增加了上下文切换的耗时,总体上虚拟机跨核ctx的耗时是宿主机的23倍。下一篇文章我们会对IPI中断的测试方法以及虚拟化之后可能的优化方法进行介绍,欢迎订阅,及时查看。此文已由腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号

March 12, 2019 · 1 min · jiezi

配置eslint规范项目代码风格

为什么要使用eslint你在接手一个项目的维护迭代任务,阅读代码的时候是否会因为项目中充斥着各种风格的代码而感到头疼?没错,eslint就是为了解决这类问题eslint能做什么?1.代码风格错误提示配置好eslint后,如果代码风格与配置描述的不符,eslint会提示代码中存在的风格问题;一般提示的情形有:1.编辑器内,大多数编辑器配置好后能读取eslint配置文件并在文件中进行相应提示2.eslint-loader配合webpack-dev-server能在页面中弹出相应错误内容3.eslint通过命令号对代码进行风格检查2.修复相应风格问题eslint –fix 命令能修复一部分代码风格问题;能修复的范围见https://cn.eslint.org/docs/ru…常见问题如何在局部禁用eslint/* eslint-disable no-alert, no-console /alert(‘foo’);console.log(‘bar’);/ eslint-enable no-alert, no-console */以下是详细配置{ root: true,// 直接在根目录读取配置文件,能提高eslint性能 “env”: { “node”: true,// 允许使用nodejs相关的变量,下同 “es6”: true, “browser”: true, “commonjs”: true }, “extends”: “standard”, // 继承eslint-config-standard中的配置,可以在rules中覆盖 “parser”: “babel-eslint”, // 为eslint制定parser,默认的Esprima只允许已纳入es标准的内容 “plugins”: “vue”,// 使用eslint-plugin-vue,使eslint能对vue语法进行处理,相应rules见https://eslint.vuejs.org/rules/ “rules”: { “no-alert”: 2, “indent”: [“error”, 4, { “SwitchCase”: 1, “VariableDeclarator”: 1, “outerIIFEBody”: 1, “MemberExpression”: 1, “FunctionDeclaration”: { “parameters”: 1, “body”: 1 }, “FunctionExpression”: { “parameters”: 1, “body”: 1 }, “CallExpression”: { “arguments”: 1 }, “ArrayExpression”: 1, “ObjectExpression”: 1, “ImportDeclaration”: 1, “flatTernaryExpressions”: false, “ignoreComments”: false }] }} ...

March 10, 2019 · 1 min · jiezi

有了这些你们团队的代码也很规范

最近重构项目组件,看到项目中存在一些命名和方法分块方面存在一些问题,结合平时经验和 Apple官方代码规范 在此整理出 iOS 工程规范。提出第一个版本,如果后期觉得有不完善的地方,继续提出来不断完善,文档在此记录的目的就是为了大家的代码可读性较好,后来的人或者团队里面的其他人看到代码可以不会因为代码风格和可读性上面造成较大时间的开销。软件的生命周期贯穿产品的开发,测试,生产,用户使用,版本升级和后期维护等过程,只有易读,易维护的软件代码才具有生命力。一些原则长的,描述性的方法和变量命名是好的。不要使用简写,除非是一些大家都知道的场景比如 VIP。不要使用 bgView,推荐使用 backgroundView见名知意。含义清楚,做好不加注释代码自我表述能力强。(前提是代码足够规范)不要过分追求技巧,降低代码可读性删除没必要的代码。比如我们新建一个控制器,里面会有一些不会用到的代码,或者注释起来的代码,如果这些代码不需要,那就删除它,留着偷懒吗?下次需要自己手写在方法内部不要重复计算某个值,适当的情况下可以将计算结果缓存起来尽量减少单例的使用。提供一个统一的数据管理入口,不管是 MVC、MVVM、MVP 模块内提供一个统一的数据管理入口会使得代码变得更容易管理和维护。除了 .m 文件中方法,其他的地方"{“不需要另起一行。- (void)getGooodsList{ // …}- (void)doHomework{ if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over;}变量一个变量最好只有一个作用,切勿为了节省代码行数,觉得一个变量可以做多个用途。(单一原则)方法内部如果有局部变量,那么局部变量应该靠近在使用的地方,而不是全部在顶部声明全部的局部变量。运算符1元运算符和变量之间不需要空格。例如:++n2元运算符与变量之间需要空格隔开。例如: containerWidth = 0.3 * Screen_Width当有多个运算符的时候需要使用括号来明确正确的顺序,可读性较好。例如: 2 << (1 + 2 * 3 - 4)条件表达式当有条件过多、过长的时候需要换行,为了代码看起来整齐些//goodif (condition1() && condition2() && condition3() && condition4()) { // Do something}//badif (condition1() && condition2() && condition3() && condition4()) { // Do something }在一个代码块里面有个可能的情况时善于使用 return 来结束异常的情况。- (void)doHomework{ if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over;}每个分支的实现都必须使用 {} 包含。// badif (self.hungry) self.eat() // goodif (self.hungry) { self.eat()}条件判断的时候应该是变量在左,条件在右。 if ( currentCursor == 2 ) { //… }switch 语句后面的每个分支都需要用大括号括起来。switch 语句后面的 default 分支必须存在,除非是在对枚举进行 switch。switch (menuType) { case menuTypeLeft: { // … break; } case menuTypeRight: { // … break; } case menuTypeTop: { // … break; } case menuTypeBottom: { // … break; }}类名大写驼峰式命名。每个单词首字母大写。比如「申请记录控制器」ApplyRecordsViewController每个类型的命名以该类型结尾。ViewController:使用 ViewController 结尾。例子:ApplyRecordsViewControllerView:使用 View 结尾。例子:分界线:boundaryViewNSArray:使用 s 结尾。比如商品分类数据源。categoriesUITableViewCell:使用 Cell 结尾。比如 MyProfileCellProtocol:使用 Delegate 或者 Datasource 结尾。比如 XQScanViewDelegateTool:工具类代理类:DelegateService 类:Service类的注释有时候我们需要为我们创建的类设置一些注释。我们可以在类的下面添加。枚举枚举的命名和类的命名相近。typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) { UIControlContentVerticalAlignmentCenter = 0, UIControlContentVerticalAlignmentTop = 1, UIControlContentVerticalAlignmentBottom = 2, UIControlContentVerticalAlignmentFill = 3,};宏全部大写,单词与单词之间用 _ 连接。以 K 开头。后面遵循大写驼峰命名。「不带参数」#define HOME_PAGE_DID_SCROLL @“com.xq.home.page.tableview.did.scroll”#define KHomePageDidScroll @“com.xq.home.page.tableview.did.scroll"属性书写规则,基本上就是 @property 之后空一格,括号,里面的 线程修饰词、内存修饰词、读写修饰词,空一格 类 对象名称根据不同的场景选择合适的修饰符。@property (nonatomic, strong) UITableView *tableView;@property (nonatomic, assign, readonly) BOOL loading; @property (nonatomic, weak) id<#delegate#> delegate;@property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);单例单例适合全局管理状态或者事件的场景。一旦创建,对象的指针保存在静态区,单例对象在堆内存中分配的内存空间只有程序销毁的时候才会释放。基于这种特点,那么我们类似 UIApplication 对象,需要全局访问唯一一个对象的情况才适合单例,或者访问频次较高的情况。我们的功能模块的生命周期肯定小于 App 的生命周期,如果多个单例对象的话,势必 App 的开销会很大,糟糕的情况系统会杀死 App。如果觉得非要用单例比较好,那么注意需要在合适的场合 tearDown 掉。单例的使用场景概括如下:控制资源的使用,通过线程同步来控制资源的并发访问。控制实例的产生,以达到节约资源的目的。控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。+ (instancetype)sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //because has rewrited allocWithZone use NULL avoid endless loop lol. _sharedInstance = [[super allocWithZone:NULL] init]; }); return _sharedInstance;}+ (id)allocWithZone:(struct _NSZone *)zone{ return [TestNSObject sharedInstance];}+ (instancetype)alloc{ return [TestNSObject sharedInstance];}- (id)copy{ return self;}- (id)mutableCopy{ return self;}- (id)copyWithZone:(struct _NSZone *)zone{ return self;}私有变量推荐以 _ 开头,写在 .m 文件中。例如 NSString * _somePrivateVariable代理方法类的实例必须作为方法的参数之一。对于一些连续的状态的,可以加一些 will(将要)、did(已经)以类的名称开头- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;方法方法与方法之间间隔一行大量的方法尽量要以组的形式放在一起,比如生命周期函数、公有方法、私有方法、setter && getter、代理方法..方法最后面的括号需要另起一行。遵循 Apple 的规范对于其他场景的括号,括号不需要单独换行。比如 if 后面的括号。如果方法参数过多过长,建议多行书写。用冒号进行对齐。一个方法内的代码最好保持在50行以内,一般经验来看如果一个方法里面的代码行数过多,代码的阅读体验就很差(别问为什么,做过重构代码行数很长的人都有类似的心情)一个函数只做一个事情,做到单一原则。所有的类、方法设计好后就可以类似搭积木一样实现一个系统。对于有返回值的函数,且函数内有分支情况。确保每个分支都有返回值。函数如果有多个参数,外部传入的参数需要检验参数的非空、数据类型的合法性,参数错误做一些措施:立即返回、断言。多个函数如果有逻辑重复的代码,建议将重复的部分抽取出来,成为独立的函数进行调用- (instancetype)init{ self = [super init]; if (self) { <#statements#> } return self;}- (void)doHomework:(NSString *)name period:(NSInteger)second score:(NSInteger)score;方法如果有多个参数的情况下需要注意是否需要介词和连词。很多时候在不知道如何抉择测时候思考下苹果的一些 API 的方法命名。//good- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;//bad- (instancetype)initWithAge:(NSInteger)age andName:(NSString *)name;- (void)tableView:(UITableView *)tableView :(NSIndexPath )indexPath;.m 文件中的私有方法需要在顶部进行声明方法组之间也有个顺序问题。在文件最顶部实现属性的声明、私有方法的声明(很多人省去这一步,问题不大,但是蛮多第三方的库都写了,看起来还是会很方便,建议书写)。在生命周期的方法里面,比如 viewDidLoad 里面只做界面的添加,而不是做界面的初始化,所有的 view 初始化建议放在 getter 里面去做。往往 view 的初始化的代码长度会比较长、且一般会有多个 view 所以 getter 和 setter 一般建议放在最下面,这样子顶部就可以很清楚的看到代码的主要逻辑。所有button、gestureRecognizer 的响应事件都放在这个区域里面,不要到处乱放。文件基本上就是#import “ViewController.h”/ViewController//View&&Util//model//NetWork InterFace//Vender/@interface ViewController ()@end@implementation ViewController#pragma mark - life cycle- (void)viewWillAppear:(BOOL)animated{ [super viewDidAppear:animated];}- (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; }- (void)viewDidLoad{ [super viewDidLoad]; self.title = @“标准模版”;}- (void)viewWillDisappear:(BOOL)animated{ [super viewDidAppear:animated]; }- (void)viewDidDisappear:(BOOL)animated{ [super viewDidAppear:animated]; }- (void)dealloc{ NSLog(@"%s”,func);}#pragma mark - public Method#pragma mark - private method#pragma mark - event response#pragma mark - UITableViewDelegate#pragma mark - UITableViewDataSource//…(多个代理方法依次往下写)#pragma mark - getters and setters@end图片资源单个文件的命名 文件资源的命名也需要一定的规范,形式为:功能模块名_类别_功能_状态@nx.png Setting_Button_search_selected@2x.png、Setting_Button_search_selected@3x.png Setting_Button_search_unselected@2x.png、Setting_Button_search_unselected@3x.png资源的文件夹命名最好也参考 App 按照功能模块建立对应的实体文件夹目录,最后到对应的目录下添加相应的资源文件。注释对于类的注释写在当前类文件的顶部对于属性的注释需要写在属性后面的地方。 //<userId/对于 .h 文件中方法的注释,一律按快捷键 command+option+/。三个快捷键解决。按需在旁边对方法进行说明解释、返回值、参数的说明和解释对于 .m 文件中的方法的注释,在方法的旁边添加 //。注释符和注释内容需要间隔一个空格。 例如: // fetch goods list版本规范采用 A.B.C 三位数字命名,比如:1.0.2,当有更新的情况下按照下面的依据版本号右说明对齐标题示例A.b.c属于重大内容的更新1.0.2 -> 2.0.0a.B.c属于小部分内容的更新1.0.2 -> 1.1.1a.b.C属于补丁更新1.0.2 -> 1.0.3改进我们知道了平时在使用 Xcode 开发的过程中使用的系统提供的代码块所在的地址和新建控制器、模型、view等的文件模版的存放文件夹地址后,我们就可以设想下我们是否可以定制自己团队风格的控制器模版、是否可以打造和维护自己团队的高频使用的代码块?答案是可以的。Xcode 代码块的存放地址:~/Library/Developer/Xcode/UserData/CodeSnippetsXcode 文件模版的存放地址:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/代码块的改造我们可以将属性、控制器生命周期方法、单例构造一个对象的方法、代理方法、block、GCD、UITableView 懒加载、UITableViewCell 注册、UITableView 代理方法的实现、UICollectionVIew 懒加载、UICollectionVIewCell 注册、UICollectionView 的代理方法实现等等组织为 codesnippets思考封装好 codesnippets 之后团队除了你编写这个项目的人如何使用?如何知道是否有这个代码块?方案:先在团队内召开代码规范会议,大家都统一知道这个事情在。之后大家共同维护 codesnippets。用法见下属性:通过 Property_类型 开头,回车键自动补全。比如 Strong 类型,编写代码通过 Property_Strong 回车键自动补全成如下格式@property (nonatomic, strong) <#Class#> *<#object#>;方法:以 Method_关键词 回车键确认,自动补全。比如 Method_UIScrollViewDelegate 回车键自动补全成 如下格式#pragma mark - UIScrollViewDelegate- (void)scrollViewDidScroll:(UIScrollView *)scrollView {}各种常见的 Mark:以 Mark_关键词 回车确认,自动补全。比如 Method_MethodsGroup 回车键自动补全成 如下格式#pragma mark - life cycle #pragma mark - public Method #pragma mark - private method #pragma mark - event response #pragma mark - UITableViewDelegate #pragma mark - UITableViewDataSource #pragma mark - getters and setters- 封装好 codesnippets 之后团队内如何统一?想到一个方案,可以将团队内的 codesnippets 共享到 git,团队内的其他成员再从云端拉取同步。这样的话团队内的每个成员都可以使用最新的 codesnippets 来编码。编写 shell 脚本。几个关键步骤:1. 给系统文件夹授权2. 在脚本所在文件夹新建存放代码块的文件夹3. 将系统文件夹下面的代码块复制到步骤2创建的文件夹下面4. 将当前的所有文件提交到 Git 仓库## 文件模版的改造我们观察系统文件模版的特点,和在 Xcode 新建文件模版对应。所以我们新建 Custom 文件夹,将系统 Source 文件夹下面的 Cocoa Touch Class.xctemplate 复制到 Custom 文件夹下。重命名为我们需要的名字,我这里以“Power”为例进入 PowerViewController.xctemplate/PowerViewControllerObjective-C修改 ___FILEBASENAME___.h 和 ___FILEBASENAME___.m 文件内容在替换 .h 文件内容的时候后面改为 UIViewController,不然其他开发者新建文件模版的时候出现的不是 UIViewController 而是我们的 PowerViewController 修改 TemplateInfo.plist思考:- 如何使用商量好一个标识(“Power”)。比如我新建了单例、控制器、Model、UIView4个模版,都以为 Power 开头。- 如何共享以 shell 脚本为工具。使用脚本将 git 云端的代码模版同步到本地 Xcode 文件夹对应的位置就可以使用了。关键步骤:1. git clone 代码到脚本所在文件夹2. 进入存放 codesnippets 的文件夹将内容复制到系统存放 codesnippets 的地方3. 进入存放 file template 的文件夹将内容复制到系统存放 file template 的地方## 使用./syncSnippets.sh // 同步git云端代码块和文件模版到本地./uploadMySnippets.sh //将本地的代码块和文件模版同步到云端## PS目前新建了大概30个代码段和4个类文件模版(UIViewController控制器带有方法组、模型、线程安全的单例模版、带有布局方法的UIView模版)shell 脚本基本有每个函数和关键步骤的代码注释,想学习 shell 的人可以看看代码。代码传送门———- ...

March 4, 2019 · 3 min · jiezi

30秒的PHP代码片段(1)数组 - Array

本文来自GitHub开源项目点我跳转30秒的PHP代码片段精选的有用PHP片段集合,您可以在30秒或更短的时间内理解这些片段。排列all如果所提供的函数返回 true 的数量等于数组中成员数量的总和,则函数返回 true,否则返回 false。function all($items, $func){ return count(array_filter($items, $func)) === count($items);}Examplesall([2, 3, 4, 5], function ($item) { return $item > 1;}); // trueany如果提供的函数对数组中的至少一个元素返回true,则返回true,否则返回false。function any($items, $func){ return count(array_filter($items, $func)) > 0;}Examplesany([1, 2, 3, 4], function ($item) { return $item < 2;}); // truedeepFlatten(深度平铺数组)将多维数组转为一维数组function deepFlatten($items){ $result = []; foreach ($items as $item) { if (!is_array($item)) { $result[] = $item; } else { $result = array_merge($result, deepFlatten($item)); } } return $result;}ExamplesdeepFlatten([1, [2], [[3], 4], 5]); // [1, 2, 3, 4, 5]drop返回一个新数组,并从左侧弹出n个元素。function drop($items, $n = 1){ return array_slice($items, $n);}Examplesdrop([1, 2, 3]); // [2,3]drop([1, 2, 3], 2); // [3]findLast返回所提供的函数为其返回的有效值(即过滤后的值)的最后一个元素的键值(value)。function findLast($items, $func){ $filteredItems = array_filter($items, $func); return array_pop($filteredItems);}ExamplesfindLast([1, 2, 3, 4], function ($n) { return ($n % 2) === 1;});// 3findLastIndex返回所提供的函数为其返回的有效值(即过滤后的值)的最后一个元素的键名(key)。function findLastIndex($items, $func){ $keys = array_keys(array_filter($items, $func)); return array_pop($keys);}ExamplesfindLastIndex([1, 2, 3, 4], function ($n) { return ($n % 2) === 1;});// 2flatten(平铺数组)将数组降为一维数组function flatten($items){ $result = []; foreach ($items as $item) { if (!is_array($item)) { $result[] = $item; } else { $result = array_merge($result, array_values($item)); } } return $result;}Examplesflatten([1, [2], 3, 4]); // [1, 2, 3, 4]groupBy根据给定的函数对数组的元素进行分组。function groupBy($items, $func){ $group = []; foreach ($items as $item) { if ((!is_string($func) && is_callable($func)) || function_exists($func)) { $key = call_user_func($func, $item); $group[$key][] = $item; } elseif (is_object($item)) { $group[$item->{$func}][] = $item; } elseif (isset($item[$func])) { $group[$item[$func]][] = $item; } } return $group;}ExamplesgroupBy([‘one’, ’two’, ’three’], ‘strlen’); // [3 => [‘one’, ’two’], 5 => [’three’]]hasDuplicates(查重)检查数组中的重复值。如果存在重复值,则返回true;如果所有值都是唯一的,则返回false。function hasDuplicates($items){ return count($items) > count(array_unique($items));}ExampleshasDuplicates([1, 2, 3, 4, 5, 5]); // truehead返回数组中的第一个元素。function head($items){ return reset($items);}Exampleshead([1, 2, 3]); // 1last返回数组中的最后一个元素。function head($items){ return reset($items);}Exampleslast([1, 2, 3]); // 3pluck检索给定键名的所有键值function pluck($items, $key){ return array_map( function($item) use ($key) { return is_object($item) ? $item->$key : $item[$key]; }, $items);}Examplespluck([ [‘product_id’ => ‘prod-100’, ’name’ => ‘Desk’], [‘product_id’ => ‘prod-200’, ’name’ => ‘Chair’],], ’name’);// [‘Desk’, ‘Chair’]pull修改原始数组以过滤掉指定的值。function pull(&$items, …$params){ $items = array_values(array_diff($items, $params)); return $items;}Examples$items = [‘a’, ‘b’, ‘c’, ‘a’, ‘b’, ‘c’];pull($items, ‘a’, ‘c’); // $items will be [‘b’, ‘b’]reject使用给定的回调筛选数组。function reject($items, $func){ return array_values(array_diff($items, array_filter($items, $func)));}Examplesreject([‘Apple’, ‘Pear’, ‘Kiwi’, ‘Banana’], function ($item) { return strlen($item) > 4;}); // [‘Pear’, ‘Kiwi’]remove从给定函数返回false的数组中删除元素。function remove($items, $func){ $filtered = array_filter($items, $func); return array_diff_key($items, $filtered);}Examplesremove([1, 2, 3, 4], function ($n) { return ($n % 2) === 0;});// [0 => 1, 2 => 3]tail返回数组中的所有元素,第一个元素除外。function tail($items){ return count($items) > 1 ? array_slice($items, 1) : $items;}Examplestail([1, 2, 3]); // [2, 3]take返回一个数组,其中从开头删除了n个元素。function take($items, $n = 1){ return array_slice($items, 0, $n);}Examplestake([1, 2, 3], 5); // [1, 2, 3]take([1, 2, 3, 4, 5], 2); // [1, 2]without筛选出给定值之外的数组元素。function without($items, …$params){ return array_values(array_diff($items, $params));}Exampleswithout([2, 1, 2, 3, 5, 8], 1, 2, 8); // [3, 5]orderBy按键名对数组或对象的集合进行排序。function orderBy($items, $attr, $order){ $sortedItems = []; foreach ($items as $item) { $key = is_object($item) ? $item->{$attr} : $item[$attr]; $sortedItems[$key] = $item; } if ($order === ‘desc’) { krsort($sortedItems); } else { ksort($sortedItems); } return array_values($sortedItems);}ExamplesorderBy( [ [‘id’ => 2, ’name’ => ‘Joy’], [‘id’ => 3, ’name’ => ‘Khaja’], [‘id’ => 1, ’name’ => ‘Raja’] ], ‘id’, ‘desc’); // [[‘id’ => 3, ’name’ => ‘Khaja’], [‘id’ => 2, ’name’ => ‘Joy’], [‘id’ => 1, ’name’ => ‘Raja’]] ...

February 13, 2019 · 3 min · jiezi

代码重构那些事儿

大家好,这是我今天演讲的目录,分Java,JavaScript,ABAP三门编程语言来讲述。Java•JAD•javap•Java Decompiler•Source Monitor•Visual VM•Refactor Menu in EclipseABAP•Code inspector•Refactor feature in AIE•Code coverageJavaScript•ESLint for Fiori Apps•Check Jenkins build log•JSlint for Sublime Text 2•Code check in WebIDE•Profile in Chrome在方法里引入一个布尔类型的参数控制方法的行为,这种做法正确吗?看看stackoverflow上是怎么说的。Java里定义常量的最佳实践:http://developer.51cto.com/ar…Java里这两种定义常量的方法,哪种更好?package one;public interface Constants { String NAME = “孙悟空”; int BP = 10000;}或package two;public class Constants { public static final String NAME = “贝吉塔”; public static final int BP = 9000;}为什么我们不应该在Java 接口中使用Array:https://eclipsesource.com/blo…避免Array的原因之一:Array若使用不当,会造成性能问题避免Array的原因之一:Array若使用不当,会造成性能问题避免Array的原因之二:Array是面向过程编程领域的概念,使用Java面向对象的集合类,比如List,而不是Array看个具体例子:String[] array = { “乔布斯”, “张小龙” };List list = Arrays.asList( array );System.out.println( list );// 打印输出 [乔布斯, 张小龙]System.out.println( array );// -> [Ljava.lang.String;@6f548414list.equals( Arrays.asList( “乔布斯”, “张小龙” ) )// -> truearray.equals( new String[] { “乔布斯”, “张小龙” } )// -> false看出差距了吧?Arrays不是类型安全的!下面的代码能通过编译,但是运行时会报ArrayStoreException的异常:Number[] numbers = new Integer[10];numbers[0] = Long.valueOf( 0 ); 而使用JDK的集合类比如List,就能在编译器即检测出这类错误。Javascript里有趣的逗号function a() { console.log(“I was called!”); return “Jerry”;}var b = a(), a;然后执行下面的代码:console.log(b);会打印出Jerry再看这段代码:var d = (function c(){ return a(),a;})();console.log(d);会打印出:I was called!function a() { console.log(“I was called!”); return “Jerry”;}再看这段代码呢?(function() { var e = f = 1;})();直接报错:Uncaught ReferenceError: f is not definedJavaScript里有趣的分号var b = function(para) { return { doSomething: function() { console.log(“hello: " + para); return para; } }}var a = 1, x = 3, y = 4, ss = a + b(x + y).doSomething() // 打印出 hello: 7console.log(s) // 打印出 8function test(i){ var result = i++; return result}console.log(“test: " + test(3)) // 打印出undefined继续看这段代码s = function(x){ console.log(“called: " + x ); return x}(1 + 2).toString()s = function(x){ console.log(“called: " + x ); return x}(1 + 2).toString()// 打印出 called: 3小技巧 - 如何把您自己增强逻辑植入到legacy遗留代码中var bigFunction = function() { // big logic console.log(“big logic”); // 这句话模拟我们在一段很冗长的遗留代码里植入自己的新逻辑}// 下面这种解决方案不会直接修改遗留函数本身,显得比较优雅var _old = bigFunction;bigFunction = function() { if ( _old ) { _old(); } console.log(“our own enhancement”);}bigFunction();// 第三种解决方案采用了面向切片编程思想,显得更加高级var bigFunction = function() { // big logic console.log(“big logic”);}bigFunction = ( bigFunction || function() {} ).after( function() { console.log(“our own logic”);});bigFunction();如何优雅的在一个函数里增添性能测试统计的工具代码var append_doms = function() { var d = new Date(); // dirty code - nothing to do with application logic!!! for( var i = 0; i < 100000; i++) { var div = document.createElement( “div”); document.body.appendChild(div); } // dirty code - nothing to do with application logic!!! console.log(” time consumed: " + ( new Date() - d));};function test() { append_doms();}传统方案:在充满了业务逻辑的函数体里强行加入红色标准的搜集性能测试的工具代码,这个实现显得很丑陋:再看看采用面向切片编程思路的解决方案:AOP - Aspect Oriented Programmingvar append_doms = function() { for( var i = 0; i < 100000; i++) { var div = document.createElement( “div”); document.body.appendChild(div); }};var log_time = function( func, log_name) { return func = ( function() { var d; return func.before( function(){ d = new Date(); }).after( function(){ console.log( log_name + ( new Date() - d)); }); })(); };function test() { log_time(append_doms, “consumed time: “)();}如何避免代码中大量的IF - ELSE 检查在调用真正的OData API之前,系统有大量的IF ELSE对API的输入参宿进行检查:var send = function() { var value = input.value; if( value.length === ’’ ) { return false; } else if( value.length > MAX_LENGTH) { return false; } … // lots of else else { // call OData API }}更优雅的解决方案:把这些不同的检查规则封装到一个个JavaScript函数里,再把这些函数作为一个规则对象的属性:var valid_rules = { not_empty: function( value ) { return value.length !== ‘’; }, max_length: function( value ) { return value.length <= MAX_LENGTH ; } }实现一个新的检查函数,变量检查对象的属性,执行校验逻辑:var valid_check = function() { for( var i in valid_rules ) { if ( vali_rules[i].apply( this, arguments) === false ) { return false; } }}现在的OData调用函数非常优雅了:var send = function( value ) { if ( valid_check( value ) === false ) { return; } // call OData API}通过这种方式消除了IF ELSE。另一种通过职责链 Chain of Responsibility 的设计模式 design pattern消除IF ELSE分支的代码重构方式:先看传统方式的实现:// Priority: ActiveX > HTML5 > Flash > Form(default)function isActiveXSupported(){ //… return false;}function isHTML5Supported(){ //… return false;}function isFlashSupported(){ //… return false;}好多的IF -ELSE啊:var uploadAPI;if ( isActiveXSupported()) { // lots of initialization work uploadAPI = { “name”: “ActiveX”};}else if( isHTML5Supported()) { // lots of initialization work uploadAPI = { “name”: “HTML5”};}else if( isFlashSupported()) { // lots of initialization work uploadAPI = { “name”: “Flash”};}else { // lots of initialization work uploadAPI = { “name”: “Form”};}console.log(uploadAPI);再看职责链设计模式的实现:Chain of Responsibilityvar getActiveX = function() { try { // lots of initialization work return { “name”: “ActiveX”}; } catch (e) { return null; }}var getHTML5 = function() { try { // lots of initialization work return { “name”: “HTML5”}; } catch (e) { return null; }}代码整洁优雅:var uploadAPI = getActiveX.after(getHTML5).after(getFlash).after(getForm)();console.log(uploadAPI);Java中的Stringpublic class stringTest {public static void main(String[] args) { String userName = “Jerry”; String skill = “JS”; String job = “Developer”; String info = userName + skill + job; System.out.println(info);}}用javap将上面的Hello World程序反编译出来学习:要获取更多Jerry的原创文章,请关注公众号"汪子熙”: ...

February 3, 2019 · 4 min · jiezi

开发者生存技能 - 代码规范篇

团队项目,良好的代码习惯非常重要。以下为本人开发项目中的代码习惯,或许对你有所帮助WHY?团队项目不是一个人在写代码,自己写代码爽了,也要让别人看着清晰减少bug处理,方便bug查找解决,提高开发效率,减少不必要的精力消耗方便后期维护HOW?基本准则代码缩进严格统一,要么都是2空格,要么都是4空格,禁止一切空格交叉使用导致代码不对齐,看着头痛的情况出现禁止代码断层(完整代码块内出现多余的空行)注释必须写非工程化项目中css禁止在html代码中书写注销无用的代码一律删掉便于开发的代码,例如console.log()或alert()在开发完成后一律删掉HTML写注释如果代码量少还看的清楚,但是代码量多了,看大量没有注释的代码就没那么轻松,所以注释要写上<!– yes –><!– 下一步 –><div class=“btn-group df-jcc”> <button class=“next-step cp”>下一步</button> <button class=“submit cp”>提交</button> <button class=“exit cp”>退出</button></div><!– 提示 –><div class=“prompt-layer”> <div class=“title df-aic df-jcc”> <h3>温馨提示</h3> </div> <div class=“prompt-content”> <img src=“xxx.png” alt=“xxx”> <p class=“ac”></p> </div></div><!– no –><div class=“btn-group df-jcc”> <button class=“next-step cp”>下一步</button> <button class=“submit cp”>提交</button> <button class=“exit cp”>退出</button></div><div class=“prompt-layer”> <div class=“title df-aic df-jcc”> <h3>温馨提示</h3> </div> <div class=“prompt-content”> <img src=“xxx.png” alt=“xxx”> <p class=“ac”></p> </div></div>标签合理使用<!– 头部 –><header></header><!– 主内容 –><main></main><!– 尾部 –><footer></footer><!– 按钮 –><button></button><!– 导航 –><nav></nav><!– 标题 h1-h6 –><h3></h3>……<!– yes –><button class=“btn”></button><!– no –><div class=“btn”></div>标签class或id命名语义化头部:class=“header"尾部:footer导航:nav侧边栏:sidebar标签页:tab菜单:menu……<!– yes –><div class=“sidebar”></div><!– no –><div class=“left”></div>标签属性值使用"“包裹,不要使用’’<!– yes –><footer class=“footer”></footer><!– no –><footer class=‘footer’></footer>标签属性书写顺序class id data-* src, type, href, valuetitle, alt<!– yes –><a class=”” id="" data-val="" href=""></a><!– no –><a id="" href="" class="" data-val=""></a>禁止代码断层,出现多余的空行造成代码可读性很差<!– yes –><div class=“point-type df bg-white mb-20 p-20-30 border-e5”> <div class=“text-title”> <h3></h3> </div> <nav class=“flex-1”> <ul class=“clearfix”></ul> </nav></div><!– very poor –><div class=“point-type df bg-white mb-20 p-20-30 border-e5”> <div class=“text-title”> <h3></h3> </div> <nav class=“flex-1”> <ul class=“clearfix”></ul> </nav></div>CSS项目初始化样式reset.css*{-webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { margin:0; padding:0;}body { color:rgba(51,51,51,0.8); font-size:14px; font-family: “Arial”,“Microsoft YaHei”,“黑体”,“宋体”,sans-serif; }td,th,caption { font-size:14px; }h1, h2, h3, h4, h5, h6 { font-weight:normal; font-size:100%; }address, caption, cite, code, dfn, em, strong, th, var { font-style:normal; font-weight:normal;}a { color:#555; text-decoration:none; }a:hover { text-decoration: none; }img { border:none; vertical-align: middle}ol,ul,li { list-style:none; }i{font-style: normal;}input, textarea, select, button { font:14px “Arial”,“Microsoft YaHei”,“黑体”,“宋体”,sans-serif;}input,button{border: none; outline: none;}input[type=checkbox], input[type=radio]{margin: 0;}table { border-collapse:collapse; }html {overflow-y: scroll;}p{margin: 0;}.clearfix:after {content: “.”; display: block; height:0; clear:both; visibility: hidden;}.clearfix { zoom:1; }/公共类/项目自定义公用样式统一放在某一指定css中(根据自身习惯决定,以下是我编写css习惯)将一些经常使用到的样式统一放到public.css文件中,避免重复书写 / * public.css / .fl { float: left; } .fr { float: right; } .ac { text-align: center; } .ar { text-align: right; } .df { display: -webkit-flex; display: flex; } .df-aic { display: -webkit-flex; display: flex; align-items: center; } .df-jcc { display: -webkit-flex; display: flex; justify-content: center; } .flex-1 { flex: 1; } .bs { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .cp { cursor: pointer; } .bg-white { background-color: #fff; } .w100 { width: 100%; } .h100 { height: 100%; } .mb-20 { margin-bottom: 20px; } ……其他公用样式统一放到base.css中 / * base.css * 凡是多个页面会同时使用到的样式全部放入该文件中 / body { background-color: #f9f9fb; } .container { width: 1280px; margin: auto; padding: 0 15px; } / 头部 / header {} / 主内容 / main {} / 尾部 / footer {} / 搜索 / .search {} / checkbox / input[type=“checkbox”] { width: 20px; height: 20px; -webkit-appearance:none; background: url(“xxx.png”) no-repeat center; } input[type=“checkbox”]:checked { background: url(“xxx.png”) no-repeat center; } ……写注释某一区块代码的样式写好注释,比如header,footer,列表,搜索,返回顶部 …/ yes // header /header {}/ footer /footer {}/ 返回顶部 /.go-top {}/ no /header {}footer {}.go-top {}css书写顺序文本位置样式float,position,left,top,display,z-index…文本宽高,边距width,height,padding,margin…文本内容颜色,大小color,line-height,font-size,text-align…文本背景,边框background,border…其他border-radius,transform,transiton…/ yes /nav ul li { float: left; width: 90px; height: 32px; margin: 10px; padding: 0 20px 0 10px; font-size: 18px; text-align: right; border: 1px solid #eee; border-radius: 4px;}/ no /nav ul li { margin: 10px; text-align: right; border: 1px solid #eee; width: 90px; height: 32px; padding: 0 20px 0 10px; float: left; font-size: 18px; border-radius: 4px;}padding margin写法/ 只有一个值的情况 /.title { margin-left: 10px;}/ 多值情况 // yes /.title { margin: 0 20px 10px;}/ no /.title { margin-top: 0; margin-right: 20px; margin-left: 20px; margin-bottom: 10px;}css选择器两边各保留一个空格/ yes /label + input { margin-left: 10px;}nav > ul > li { margin-left: 10px;}/ no /label+input { margin-left: 10px;}nav>ul>li { margin-left: 10px;}JavaScript写注释整功能模块注释 /* * 列表筛选 * @param {Array} xxxxx 保存所选省份 * @param {String} xxxxxxxxxx 保存所选年代 * @method xxxx 保存所选部分,用于筛选 * @method xxxx 删除筛选中所选条件 * …… /整功能模块内部小功能代码注释也需要写// 列表分页xxxx// 重置筛选条件xxxx驼峰命名/ yes /let searchVal = ‘’;function getUserInfo() {}/ no /let searchval = ‘’;function getuserinfo() {}……加空格让代码更优雅= == === > < % + * / , …/ yes /const name = ‘yuci’;const userArr = [‘a’, ‘b’, ‘c’];if (i === 0) { // do}for (let i = 0, len = arr.length; i < len; i++) { // do}/ no /const name=‘yuci’;const userArr=[‘a’,‘b’,‘c’];if(i===0){ // do}for(let i=0,len=arr.length;i<len;i++){ // do}……if else for while switch try catch function …/ yes /if (i === 0) { // do} else { // do}try { // do} catch { // do}switch (dataSort) { // do}for (let i = 0, len = arr.length; i < len; i++) { // do}const fn = username => { // do}function fn() { // do}/ no /if(i===0){ // do}else{ // do}for(let i=0,len=arr.length;i<len;i++){ // do}switch(dataSort){ // do}const fn=username=>{ // do}function fn(){ // do}……对象 : 右边加上一个空格/ yes /const user = { name: ‘xxx’, age: ‘xxx’}this.state = { username: ‘’}this.setState({ username: ‘yucihent’})/ no /const user = { name:‘xxx’, age:‘xxx’}……禁止代码断层(可读性非常差)/ yes /let fetchData = async (url, method, data) => { let options; let dataStr = ‘’; const headers = { ‘Accept’: ‘application/json’, ‘Content-Type’: ‘application/x-www-form-urlencoded’ }; // get 请求 if (method === ‘get’) { if (typeof data === ‘object’) { Object.keys(data).forEach(key => { dataStr += ${key}=${data[key]}&amp; }); if (dataStr) { dataStr = dataStr.substring(0, dataStr.length - 1) }; url = ${url}?${dataStr}; } options = { method: ‘GET’, headers, } } else { let formData = new FormData(); for (let key in data) { formData.append(key, data[key]) } options = { method: ‘POST’, body: formData } } let response = await fetch(url, options); let res = await response.json(); return res;}/ very poor very poor very poor /let fetchData = async (url, method, data) => { let options; let dataStr = ‘’; const headers = { ‘Accept’: ‘application/json’, ‘Content-Type’: ‘application/x-www-form-urlencoded’ }; // get 请求 if (method === ‘get’) { if (typeof data === ‘object’) { Object.keys(data).forEach(key => { dataStr += ${key}=${data[key]}&amp; }); if (dataStr) { dataStr = dataStr.substring(0, dataStr.length - 1) }; url = ${url}?${dataStr}; } options = { method: ‘GET’, headers, } } else { let formData = new FormData(); for (let key in data) { formData.append(key, data[key]) } options = { method: ‘POST’, body: formData } } let response = await fetch(url, options); let res = await response.json(); return res;}一行代码不要过多/ yes /import { List, InputItem, WingBlank, WhiteSpace, Button, Radio, Toast} from ‘antd-mobile’/ no /import { List, InputItem, WingBlank, WhiteSpace, Button, Radio, Toast } from ‘antd-mobile’使用’’,而非""/ yes /import HelloWorld from ‘./components/HelloWorld’methods: { delItem(index) { this.$emit(‘delItem’, index) }}/ no /import HelloWorld from “./components/HelloWorld"methods: { delItem(index) { this.$emit(“delItem”, index) }}简洁清晰模板字符串替代 ++ 字符串拼接结构赋值/ yes /this.state = { name: ‘xxx’, age: ‘xxx’}const { name, age } = this.state;/ no /const name = this.state.name;const age = this.state.age;属性名属性值相同简写/ yes /components: { Header, Footer}/ no /components: { Header: Header, Footer: Footer}函数/ yes /methods: { delItem(index) { this.$emit(‘delItem’, index) }}/ no */methods: { delItem: function(index) { this.$emit(‘delItem’, index) }}……结束语上述内容为我在项目中遇到过的代码规范问题以及本人编码习惯的总结,不可能适用每位开发者,但大部分编码风格应该是合大众口味,希望能帮助到大家唠叨一句团队合作的一个黄金定则:你看别人的代码就像看自己代码一样,良好的代码习惯 非常重要 非常重要 非常重要 ...

January 25, 2019 · 5 min · jiezi

如何编写高质量代码

更多文章什么是高质量代码?高质量代码具有以下几个特点:可读性高结构清晰可扩展(方便维护)代码风格统一低复杂性简练编写高质量代码主要遵循以下几点:代码规范代码规范的好处规范的代码可以促进团队合作规范的代码可以降低维护成本规范的代码有助于代码审查养成代码规范的习惯,有助于程序员自身的成长每个程序员最烦的就是修改别人的代码,无论代码好坏。因为第一眼看上去没有熟悉感,下意识就会排斥。所以当团队的成员都严格按照代码规范来写代码时,可以保证每个人的代码看起来都像是一个人写的,看别人的代码就像是在看自己的代码。重要的是我们能够认识到规范的重要性,并坚持规范的开发习惯。 接下来,你要做的事就是找一份良好的代码规范并一直坚持使用,直到形成习惯。前端代码规范推荐百度前端代码规范feross/standard · GitHubAirbnb JavaScript Style Guide提前设计在接到一个需求时,千万不要看完需求就马上写代码,以免造成返工或误解需求的现象。在这个阶段一定要多问,看完需求后,在脑里过一下,把可能会涉及的情况都要问清楚。一名好的程序员不仅仅是一名程序员,还要懂需求、业务。在把情况都了解清楚后,如果项目规模不是很大,就可以开始写大纲了。例如这样:class Car { run(){}, stop(){},}然后再开始实现细节。如果项目规模比较大,可以通过思维导图或其他工具写一个项目的原型(当然这种活一般都会由项目经理或产品来负责),再细分到不同的程序模块来一一实现。“磨刀不误砍柴功”,千万不要为了求快而直接写代码。具体流程阅读文档,分析需求画原型图或草图(方便自己理解整体架构)写大纲或伪代码(如果项目比较大还要细分模块)实现细节重构没有程序员能一次就写出完美的代码,而是需要通过不停的重构来完善代码,提升质量。重构就是在不改变软件系统外部行为的前提下,改善它的内部结构。重构可以使软件更容易地被修改和被理解。通过不断地改进软件设计以达到简单设计的目标,减少由于设计与业务的不匹配带来的架构与设计腐化。重构能改善软件设计重构使软件更易理解重构有助于找到Bug重构有助于提高自我编程能力重构有助于加深理解代码重构能适应需求变更推荐阅读:重构代码要求不要编写大段代码重复代码封装成函数在编写代码的过程中养成不断重构的习惯添加必要的注释留下可扩展的空间测试无论是单元测试、自测或者是其它测试,最重要的目的都是为了找出尽可能多的BUG,保证产品的质量。好的东西都是迭代改出来的,比如好的产品,好的架构,代码也不例外,写的好的代码都是经历了作者不停地 review 和修改。测试的过程本身就是一个自我 code review 的过程,在这个过程中,可以发现一些设计上的问题(比如代码设计的不可测试),代码编写方面的问题(比如一些边界条件的处理不当)等,做到及时发现及时修正,不需要等到测试阶段甚至上线之后再发现再修改。自我要求个人认为这一点是最重要的,好的程序员都是有强迫症的,他们会严格要求自己,通过不断的学习来提升自己的技术最终成为大神级别的程序员。如果你不能以高标准来要求自己,即使你看再多的如何写出高质量代码,懂再多的代码规范,也是没有用,最终还是写出低质量代码。但是,提高自我要求是一种改变,一般来说,改变都不是一蹴而就的,需要一步一步来。所以,改变最好从小事做起,慢慢积累,最终蜕变。建议先从代码规范开始,熟悉代码规范,遵循规范写代码,直到成为习惯,然后再学习其它方法,最终写出高质量代码。参考资料https://kdboy.iteye.com/blog/…https://www.jianshu.com/p/71a…

January 9, 2019 · 1 min · jiezi

前端代码风格自动化系列(五)之共同出击

我们在前面的四篇中介绍了husky、commitlint、lint-staged、prettier这些工具,可以完成以最小的代价在Git提交到远程仓库前,格式化为统一风格的代码,eslint大家都很熟悉这里就不列举了。下面举一个配置。{ “devDependencies”: { “babel-eslint”: “^10.0.1”, “eslint”: “^5.4.0”, “eslint-config-airbnb”: “^17.0.0”, “eslint-config-prettier”: “^3.0.1”, “eslint-plugin-babel”: “^5.1.0”, “eslint-plugin-compat”: “^2.6.2”, “eslint-plugin-import”: “^2.14.0”, “eslint-plugin-jsx-a11y”: “^6.1.2”, “eslint-plugin-markdown”: “^1.0.0-beta.6”, “eslint-plugin-react”: “^7.11.1”, “husky”: “^1.1.2”, “lint-staged”: “^8.0.4”, “prettier”: “1.14.3”, “stylelint”: “^9.4.0”, “stylelint-config-prettier”: “^4.0.0”, “stylelint-config-standard”: “^18.0.0”, “tslint”: “^5.10.0”, “tslint-config-prettier”: “^1.10.0”, “tslint-react”: “^3.6.0”, }, “lint-staged”: { “/*.{js,jsx,less}”: [ “prettier –write”, “git add” ], “/.{js,jsx}”: “npm run lint-staged:js”, “**/.less”: “stylelint –syntax less” }, “husky”: { “hooks”: { “pre-commit”: “npm run lint-staged”, “commit-msg”: “commitlint -e $HUSKY_GIT_PARAMS” } }}这里对于项目里ts、js、jsx、less分别做了提交前格式化操作,对于提交规范做了校验。 ...

January 7, 2019 · 1 min · jiezi

前端代码风格自动化系列(一)之Husky

代码风格和性格一样,每个程序员都有自己的特点,但对于大家协同开发的项目,还是需要力求代码风格的一致性,以减少Bug,方便互相修改,短时间内能上手,在这条路上诞生了许许多多的工具。本系列主要介绍目前主流的前端代码格式化的工具。本篇主要介绍代码提交钩子Husky的用法,在代码被提交到Git仓库之前,我们可以在这里做一些预检查或者格式化,需要做这些操作,我们需要一个Git的提交钩子,简单说就是使用Git命令会触发的函数。安装npm install husky –save-dev配置// package.json{ “husky”: { “hooks”: { “pre-commit”: “npm run test”, “pre-push”: “npm run test”, “…”: “…” } }}在1.0.0之后的版本支持了使用.huskyrc,.huskyrc.json,.huskyrc.js配置文件,可以不放在package.json中。Husky支持的Git hooks还是很全面的,如常用的pre-commit、pre-push。这样我们就能再一些特定的时间点做一些事情。

January 7, 2019 · 1 min · jiezi

编程--代码规范

代码规范1.作用1).提高可读性2).统领全局,促进团队协助3).有助于知识传递,加快工作交接4).减少名字增生,降低维护成本5).强调变量之间关系,降低缺陷引入的机会6).提高程序员个人能力2.规范1).命名空间2).代码风格 A).花括号不允许省略 B).不允许省略访问修饰符 C).类型默认是密封的 D).不允许公开字段 E).使用括号强调运算优先级3).命名规范(Pascal(大驼峰)、Camel(小驼峰)) A).类、结构和接口命名 a).使用名词或名词短语 b).使用Pascal方式(增加识别和可读性) c).在接口名称前加上前缀I d).考虑在派生类末尾使用基类的名称 e).如果该类仅仅为了实现某个接口,保持其与接口命名的统一 B).成员命名 a).方法(Pascal公开、Camel私有) 用动词或动词短语命名 b).属性(Pascal) 用名词、名词短语或形容词来命名(复数/布尔) c).事件(Pascal) 用动词或动词短语来命名事件(现在时/过去时) d).字段(Camel私有) 用名词、名词短语或形容词来命名 C).参数命名 a).Camel风格 b).要使用left和right来命名重载的二元操作符的参数 如果参数没有具体的含义 c).要使用value来命名重载的一元操作符的参数 如果参数没有具体的含义 d).不要在参数中使用数字编号 e).尽量使用描述性的名字命名泛类型参数,并在前面使用T前缀 D).常量、变量命名 a).常量 所有单词大写用下划线分隔 b).局部变量 Camel风格 E).枚举命名 a).Pascal风格 b).使用名词的复述形势来命名标记枚举 c).不要添加ENUM或Flag后缀 d).不要给枚举类型值的名称加前缀 F).资源命名 a).Pascal风格 b).仅使用字母、数字和下划线 c).在命名异常信息的资源时,资源标识符应该是异常类型名加上简短的异常标识符 d).不要给枚举类型值的名称加前缀 G).数据库命名 a).表 模块名_表名 b).字段 布尔类型用Is、Can、Has等表示;日期类型命名必须包含Date;时间类型必须包含Time c).存储过程 使用proc_前缀 d).视图 使用view_前缀 e).触发器 使用trig_前缀 H).XML命名 a).节点 Pascal风格 b).属性 Camel风格4).注释 A).对接口和复杂代码块必须进行注释 B).修改代码时保持注释同步 C).未完成的功能使用TODO标记 D).修改他人代码时要先注释对方代码,并写明修改原因,不允许随便删除他人代码 E).发布前移除无用注释5).异常处理 A).四种异常类型 a).InvalidOperationException 无效操作 b).ArgumentException 参数无效 c).ArgumentNullException 参数值不能为NULL d).ArgumentOutOfRangeException 参数越界 B).在自定义异常时,必须使用VS提供的代码模板来创建自定义异常 ...

December 26, 2018 · 1 min · jiezi

如何做好SQLite 使用质量检测,让事故消灭在摇篮里

本文由云+社区发表SQLite 在移动端开发中广泛使用,其使用质量直接影响到产品的体验。常见的 SQLite 质量监控一般都是依赖上线后反馈的机制,比如耗时监控或者用户反馈。这种方式问题是:事后发现,负面影响已经发生。关注的只是没这么差。eg. 监控阈值为 500ms ,那么一条可优化为 20ms 而平均耗时只有 490ms 的 sql 就被忽略了。能否在上线前就进行SQLite使用质量的监控?于是我们尝试开发了一个工具: SQLiteLint 。虽然名带 “lint ” ,但并不是代码的静态检查,而是在 APP 运行时对 sql 语句、执行序列、表信息等进行分析检测。而和 “lint” 有点类似的是:在开发阶段就介入,并运用一些最佳实践的规则来检测,从而发现潜在的、可疑的 SQLite 使用问题。本文会介绍 SQLiteLint 的思路,也算是 SQLite 使用经验的分享,希望对大家有所帮助。简述SQLiteLint 在 APP 运行时进行检测,而且大部分检测算法与数据量无关即不依赖线上的数据状态。只要你触发了某条 sql 语句的执行,SQLiteLint 就会帮助你 review 这条语句是否写得有问题。而这在开发、测试或者灰度阶段就可以进行。检测流程十分简单:1. 收集 APP 运行时的 sql 执行信息 包括执行语句、创建的表信息等。其中表相关信息可以通过 pragma 命令得到。对于执行语句,有两种情况: a)DB 框架提供了回调接口。比如微信使用的是 WCDB ,很容易就可以通过MMDataBase.setSQLiteTrace 注册回调拿到这些信息。 b) 若使用 Android 默认的 DB 框架,SQLiteLint 提供了一种无侵入的获取到执行的sql语句及耗时等信息的方式。通过hook的技巧,向 SQLite3 C 层的 api sqlite3_profile 方法注册回调,也能拿到分析所需的信息,从而无需开发者额外的打点统计代码。2. 预处理 包括生成对应的 sql 语法树,生成不带实参的 sql ,判断是否 select* 语句等,为后面的分析做准备。预处理和后面的算法调度都在一个单独的处理线程。3. 调度具体检测算法执行 checker 就是各种检测算法,也支持扩展。并且检测算法都是以 C++ 实现,方便支持多平台。而调度的时机包括:最近未分析 sql 语句调度,抽样调度,初始化调度,每条 sql 语句调度。4. 发布问题 上报问题或者弹框提示。可以看到重点在第 3 步,下面具体讨论下 SQLiteLint 目前所关注的质量问题检测。检测问题简介一、检测索引使用问题索引的使用问题是数据库最常见的问题,也是最直接影响性能的问题。SQLiteLint 的分析主要基于 SQLite3 的 “explain query plan” ,即 sql 的查询计划。先简单说下查询计划的最常见的几个关键字:SCAN TABLE: 全表扫描,遍历数据表查找结果集,复杂度 O(n) SEARCH TABLE: 利用索引查找,一般除了 without rowid 表或覆盖索引等,会对索引树先一次 Binary Search 找到 rowid ,然后根据得到 rowid 去数据表做一次 Binary Search 得到目标结果集,复杂度为 O(logn) USE TEMP B-TREE: 对结果集临时建树排序,额外需要空间和时间。比如有 Order By 关键字,就有可能出现这样查询计划通过分析查询计划,SQLiteLint 目前主要检查以下几个索引问题:1. 未建索引导致的全表扫描(对应查询计划的 SCAN TABLE… )虽然建立索引是最基本优化技巧,但实际开发中,很多同学因为意识不够或者需求太紧急,而疏漏了建立合适的索引,SQLiteLint 帮助提醒这种疏漏。问题虽小,解决也简单,但最普遍存在。 这里也顺带讨论下一般不适合建立索引的情况:写多读少以及表行数很小。但对于客户端而言,写多读少的表应该不常见。而表行数很小的情况,建索引是有可能导致查询更慢的(因为索引的载入需要的时间可能大过全表扫描了),但是这个差别是微乎其微的。所以这里认为一般情况下,客户端的查询还是尽量使用索引优化,如果确定预估表数量很小或者写多读少,也可以将这个表加到不检测的白名单。解决这类问题,当然是建立对应的索引。2. 索引未生效导致的全表扫描(对应查询计划的 SCAN TABLE… )有些情况即便建立了索引,但依然可能不生效,而这种情况有时候是可以通过优化 sql 语句去用上索引的。举个例子:以上看到,即便已建立了索引,但实际没有使用索引来查询。 如对于这个 case ,可以把 like 变成不等式的比较:这里看到已经是使用索引来 SEARCH TABLE ,避免了全表扫描。但值得注意的是并不是所有 like 的情况都可以这样优化,如 like ‘%lo’ 或 like ‘%lo%’ ,不等式就做不到了。再看个位操作导致索引不生效的例子:位操作是最常见的导致索引不生效的语句之一。但有些时候也是有些技巧的利用上索引的,假如这个 case 里 flag 的业务取值只有 0x1,0x2,0x4,0x8 ,那么这条语句就可以通过穷举值的方式等效:以上看到,把位操作转成 in 穷举就能利用索引了。解决这类索引未生效导致的全表扫描 的问题,需要结合实际业务好好优化sql语句,甚至使用一些比较trick的技巧。也有可能没办法优化,这时需要添加到白名单。3. 不必要的临时建树排序(对应查询计划的 USE TEMP B-TREE… )。比如sql语句中 order by 、distinct 、group by 等就有可能引起对结果集临时额外建树排序,当然很多情况都是可以通过建立恰当的索引去优化的。举个例子:以上看到,即便id和mark都分别建立了索引,即便只需要一行结果,依然会引起重新建树排序( USE TEMP B-TREE FOR ORDER BY )。当然这个case非常简单,不过如果对 SQLite 的索引不熟悉或者开发时松懈了,确实很容易发生这样的问题。同样这个问题也很容易优化:这样就避免了重新建树排序,这对于数据量大的表查询,优化效果是立竿见影的好。解决这类问题,一般就是建立合适的索引。4. 不足够的索引组合这个主要指已经建立了索引,但索引组合的列并没有覆盖足够 where 子句的条件式中的列。SQLiteLint 检测出这种问题,建议先关注该 sql 语句是否有性能问题,再决定是否建立一个更长的索引。举个例子:以上看到,确实是利用了索引 genderIndex 来查询,但看到where子句里还有一个 mark=60 的条件,所以还有一次遍历判断操作才能得到最终需要的结果集。尤其对于这个 case,gender 也就是性别,那么最多 3 种情况,这个时候单独的 gender 索引的优化效果的已经不明显了。而同样,优化也是很容易的:解决这类问题,一般就是建立一个更大的组合索引。5. 怎么降低误报现在看到 SQLiteLint 主要根据查询计划的某些关键字去发现这些问题,但SQLite支持的查询语法是非常复杂的,而对应的查询计划也是无穷变化的。所以对查询计划自动且正确的分析,不是一件容易的事。SQLiteLint 很大的功夫也在这件事情上所以对查询计划自动且正确的分析,不是一件容易的事。SQLiteLint 很大的功夫也在这件事情上。SQLiteLint 这里主要对输出的查询计划重新构建了一棵有一定的特点的分析树,并结合sql语句的语法树,依据一定的算法及规则进行分析检测。建分析树的过程会使用到每条查询计划前面如 “0|1|0” 的数字,这里不具体展开了。 举个例子:是不是所有带有 “SCAN TABLE” 前缀的查询计划,都认为是需要优化的呢?明显不是。具体看个 case :这是一个联表查询,在 SQLite 的实现里一般就是嵌套循环。在这个语句中里, t3.id 列建了索引,并且在第二层循环中用上了,但第一层循环的 SCAN TABLE是无法优化的。比如尝试给t4的id列也建立索引:可以看出,依然无法避免 SCAN TABLE 。对于这种 SCAN TABLE 无法优化的情况,SQLiteLint 不应该误报。前面提到,会对查询计划组织成树的结构。比如对于这个 case ,最后构建的查询计划分析树为:分析树,有个主要的特点:叶子节点有兄弟节点的是联表查询,其循环顺序对应从左往右,而无兄弟节点是单表查询。而最后的分析会落地到叶子节点的分析。遍历叶子节点时,有一条规则(不完整描述)是:叶子节点有兄弟节点的,且是最左节点即第一层循环,且 where 子句中不含有相关常量条件表达式时,SCAN TABLE 不认为是质量问题。这里有两个条件必须同时满足,SCAN TABLE 才不报问题:第一层循环 & 无相关常量表达式。第一层循环前面已经描述,这里再解释下后面一个条件。由上看到,当select子句中出现常量条件表达式 “t4.id=666” , 若 t3.id,t4.id 都建了索引,是可以优化成没有 SCAN TABLE 。而把 t4.id 的索引删除后,又出现了 SCAN TABLE 。而这种 SCAN TABLE 的情况,不满足规则里的的第二个条件,SQLiteLint 就会报出可以使用索引优化了。这里介绍了一个较简单语句的查询计划的分析,当然还有更复杂的语句,还有子查询、组合等等,这里不展开讨论了。巨大的复杂性,无疑对准确率有很大的挑战,需要对分析规则不断地迭代完善。当前 SQLiteLint 的分析算法依然不足够严谨,还有很大的优化空间。 这里还有另一个思路去应对准确性的问题:对所有上报的问题,结合耗时、是否主线程、问题等级等信息,进行优先级排序。这个“曲线救国”来降低误报的策略也适用本文介绍的所有检测问题。二、检测冗余索引问题SQLiteLint 会在应用启动后对所有的表检测一次是否存在冗余索引,并建议保留最大那个索引组合。先定义什么是冗余索引:如对于某个表,如果索引组合 index1,index2 是另一个索引组合 index3 的前缀,那么一般情况下 index3 可以替代掉 index1 和 index2 的作用,所以 index1,index2 就冗余了。而多余的索引就会有多余的插入消耗和空间消耗,一般就建议只保留索引 index3 。 看个例子:以上看到,如果已经有一个 length 和 type 的组合索引,就已经满足了单 length 列条件式的查询,没必要再为 length 再建一个索引。三、检测 select * 问题SQLiteLint这里通过扫描 sql 语法树,若发现 select 子句,就会报问题,建议尽量避免使用 select ,而是按需 select 对应的列。select * 是SQLite最常用的语句之一,也非常方便,为什么还认为是问题的呢?这里有必要辩驳一下:对于 select ,SQLite 底层依然存在一步把 展开成表的全部列。select * 也减少了可以使用覆盖索引的机会。覆盖索引指索引包含的列已经覆盖了 select 所需要的列,而使用上覆盖索引就可以减少一次数据表的查询。对于 Android 平台而言,select * 就会投射所有的列,那么每行结果占据的内存就会相对更大,那么 CursorWindow(缓冲区)的容纳条数就变少,那么 SQLiteQuery.fillWindow 的次数就可能变多,这也有一定的性能影响。基于以上原因,出于 SQLiteLint 目标最佳实践的原则,这里依然报问题。四、检测 Autoincrement 问题SQLiteLint 在应用启动后会检测一次所有表的创建语句,发现 AUTOINCREMENT 关键字,就会报问题,建议避免使用 Autoincrement 。这里看下为什么要检测这个问题,下面引用 SQLite 的官方文档:The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.可以看出 Auto Increment 确实不是个好东西。 ps. 我这里补充说明一下 strictly needed 是什么是意思,也就是为什么它不必要。通常 AUTOINCREMENT 用于修饰 INTEGER PRIMARY KEY 列,后简称IPK 列。而 IPK 列等同于 rowid 别名,本身也具有自增属性,但会复用删除的 rowid 号。比如当前有 4 行,最大的rowid是 4,这时把第 4 行删掉,再插入一行,新插入行的 rowid 取值是比当前最大的 rowid 加 1,也就 3+1=4 ,所以复用了 rowid 号 4 。而如果加以 AUTOINCREMENT 修饰就是阻止了复用,在这个情况,rowid 号是 5 。也就是说,AUTOINCREMENT 可以保证了历史自增的唯一性,但对于客户端应用有多少这样的场景呢?五、检测建议使用 prepared statementSQLiteLint 会以抽样的时机去检测这个问题,比如每 50 条执行语句,分析一次执行序列,如果发现连续执行次数超过一定阈值的相同的(当然实参可以不同)而未使用 prepared statement 的 sql 语句,就报问题,建议使用 prepared statement 优化。 如阈值是 3 ,那么连续执行下面的语句,就会报问题:使用 prepared statement 优化的好处有两个:对于相同(实参不同)的 sql 语句多次执行,会有性能提升如果参数是不可信或不可控输入,还防止了注入问题六、检测建议使用 without rowid 特性SQLiteLint 会在应用启动后检测一次所有表的创建语句,发现未使用 without rowid 技巧且根据表信息判断适合使用 without rowid 优化的表,就报问题,建议使用 without rowid 优化。 这是 SQLiteLint 的另一个思路,就是发现是否可以应用上一些 SQLite 的高级特性。without rowid 在某些情况下可以同时带来空间以及时间上将近一半的优化。简单说下原理,如:对于这个含有 rowid 的表( rowid 是自动生成的),这时这里涉及到两次查询,一次在 name 的索引树上找到对应的 rowid ,一次是用这个 rowid 在数据树上查询到 mark 列。 而使用 without rowid 来建表:数据树构建是以 name 为 key ,mark 为 data 的,并且是以普通 B-tree 的方式存储。这样对于刚刚同样的查询,就需要只有一次数据树的查询就得到了 mark 列,所以算法复杂度上已经省了一个 O(logn)。另外又少维护了一个 name 的索引树,插入消耗和空间上也有了节省。当然 withou rowid 不是处处适用的,不然肯定是默认属性了。SQLiteLint 判断如果同时满足以下两个条件,就建议使用 without rowid :表含有 non-integer or composite (multi-column) PRIMARY KEY表每行数据大小不大,一个比较好的标准是行数据大小小于二十分之一的page size 。ps.默认 page size SQLite 版本3.12.0以后(对应 Android O 以上)是 4096 bytes ,以前是 1024 。而由于行数据大小业务相关,为了降低误报,SQLiteLint 使用更严格的判定标准:表不含有 BLOB 列且不含有非 PRIMARY KEY TEXT 列。简单说下原因: 对于1,假如没有 PRIMARY KEY ,无法使用 without rowid 特性;假如有 INTEGER PRIMARY KEY ,前面也说过,这时也已经等同于 rowid 。 对于 2,小于 20 分之一 pagesize 是官方给出的建议。 这里说下我理解的原因。page 是 SQLite 一般的读写单位(实际上磁盘的读写 block 更关键,而磁盘的消耗更多在定位上,更多的page就有可能需要更多的定位)。without rowid 的表是以普通 B-Tree 存储的,而这时数据也存储在所有树结点上,那么假如数据比较大,一个 page 存储的结点变少,那么查找的过程就需要读更多的 page ,从而查找的消耗更大。当然这是相对 rowid 表 B*-Tree 的存储来说的,因为这时数据都在叶子结点,搜索路径上的结点只有 KEY ,那么一个page能存的结点就多了很多,查找磁盘消耗变小。这里注意的是,不要以纯内存的算法复杂度去考量这个问题。以上是推论不一定正确,欢迎指教。引申一下,这也就是为什么 SQLite 的索引树以 B-Tree 组织,而 rowid 表树以 B-Tree 组织,因为索引树每个结点的存主要是索引列和 rowid ,往往没这么大,相对 B-Tree 优势就在于不用一直查找到叶子结点就能结束查找。与 without rowid 同样的限制,不建议用大 String 作为索引列,这当然也可以加入到 SQLiteLint 的检测。小结这里介绍了一个在开发、测试或者灰度阶段进行 SQLite 使用质量检测的工具,这个思路的好处是:上线前发现问题关注最佳实践本文的较大篇幅其实是对 SQLite 最佳实践的讨论,因为 SQLiteLint 的思路就是对最佳实践的自动化检测。当然检查可以覆盖更广的范围,准确性也是挑战,这里还有很大的空间。 此文已由作者授权腾讯云+社区发布搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包! ...

December 18, 2018 · 3 min · jiezi

iOS开发手册

1.工程文件结构所有的文件应放在工程中的项目目录下。项目文件和物理文件需保持一致。Xcode创建的任何组(group)都必须在文件系统中有映射。项目文件不仅可以按照业务类型分组,也可以根据功能分组。2.代码格式规范2.1 代码注释格式文件注释:采用Xcode自动生成的注释格式。//// AppDelegate.h// 项目名称//// Created by 开发者姓名 on 2018/6/8.// Copyright © 2018年 公司名称. All rights reserved.//import注释:如果有一个以上的import语句,对这些语句进行分组,每个分组的注释是可选的。// Framework#import <UIKit/UIKit.h>// Model#import “WTUser.h”// View#import “WTView.h"方法注释:Xcode8之后快捷键自动生成(option + command + /)。/**<#Description#>@param application <#application description#>@param launchOptions <#launchOptions description#>@return <#return value description#>*/- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;代码块注释:单行的用 “// + 空格” 开头, 多行用“/ /”。2.2 代码结构与排版声明文件:方法顺序和实现文件的顺序保持一致,根据需要用”#pragma mark -“将方法分组。实现文件:必须用”#pragma mark -“将方法分组。分组前后优先级:Lifecycle方法 > Public方法 > UI方法 > Data方法 > Event方法 > Private方法(逻辑处理等) > Delegate方法 > 部分Override方法 > Setter方法 > Getter方法。#pragma mark - Lifecycle- (instancetype)init {}- (void)viewDidLoad {}- (void)viewWillAppear:(BOOL)animated {}- (void)viewDidAppear:(BOOL)animated {}- (void)viewWillDisappear:(BOOL)animated {}- (void)viewDidDisappear:(BOOL)animated {}- (void)didReceiveMemoryWarning {}- (void)dealloc {}#pragma mark - Public- (void)refreshData {}#pragma mark - UI- (void)initSubViews {}#pragma mark - Data- (void)initData {}- (void)constructData {}#pragma mark - Event- (void)clickButton:(UIButton *)button {}#pragma mark - Private- (CGFloat)calculateHeight {}#pragma mark - UIScrollViewDelegate- (void)scrollViewDidScroll:(UIScrollView *)scrollView {}#pragma mark - Override- (BOOL)needNavigationBar {}#pragma mark - Setter- (void)setWindow:(UIWindow *)window {}#pragma mark - Getter- (UIWindow *)window {}变量:优先使用属性声明而非变量声明,注意属性修饰符、变量类型、变量之间的间隔。@property (strong, nonatomic) UIWindow *window;点语法:应始终使用点语法来访问和修改属性。间距要求如下:一个缩进使用四个空格。在”-“或者”+“号之后应该有一个空格,方法的大括号和其它大括号始终和声明在同一行开始,在新的一行结束,另外方法之间应该空一行。- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary )launchOptions { if (door.isClosed) { // Do something } else { // Do something } return YES;}长度要求如下:每行代码的长度不应该超过100个字符。单个函数或方法的实现代码控制在50行以内。单个文件里的代码行数控制在500600行之内。3.代码命名规范3.1 代码命名基础最好是既清晰又简短,但不要为简短丧失清晰性,并使用驼峰命名法。名称通常不缩写,即使名称很长也要拼写完全(禁止拼音),然而可使用少数非常常见的缩写,部分举例如下:常用缩写词含义常用缩写词含义appapplicationmaxmaximumaltalternateminminimumcalccalculatemsgmessageallocallocterectrectangledeallocdealloctemsgmessageinitinitializetemptemporaryintintegerfuncfunction由于Cocoa(Objective-C)没有C++一样的命名空间机制,需添加前缀(公司名首字母)防止命名冲突,前缀使用2个字符(以下统称项目前缀)。常见的单词略写:ASCII,PDF,HTTP,XML,URL,JPG,GIF,PNG,RGB等3.2 类和协议命名类名应明确该类的功能,并且要有项目前缀防止命名冲突。协议组合一组方法作为一个类的部分接口使用, 用类名作为协议名,例如:NSObject。协议仅仅组合一组方法而不关联具体类,这种协议的命名应采用动名词形式(ing)。委托形式的协议命名为类名加上Delegate,例如:UIScrollViewDelegate。3.3 变量和属性命名变量名应前置下划线“”,属性名没有下划线。属性本质上是存取方法setter/getter,可进行重写(注意内存管理)。@property (strong, nonatomic) UIWindow *window;- (void)setWindow:(UIWindow *)window;- (UIWindow *)window;可以适当的对setter/getter进行别名设置。@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled;3.4 方法和函数命名方法名和函数名一般不需要前缀,但函数(C语言形式)作为全局作用域的时候最好加上项目前缀。 表示行为的方法名称以动词开头,但不要使用do/does等无实际意义的助动词。参数前面的单词要能够描述该参数,并且参数名最好能用描述该参数的单词命名。- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;方法中多个参数可以使用适当的介词进行连接。// 后续多个参数使用with- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;// 添加适当介词能够使方法的含义更明确- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;// 第一个参数用了with,后面的参数不使用with- (instancetype)initWithImage:(nullable UIImage *)image highlightedImage:(nullable UIImage *)highlightedImage;只有在方法返回多个值的时候使用get单词进行明确。- (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase;方法返回某个对象实例。// 类方法创建对象+ (instancetype)buttonWithType:(UIButtonType)buttonType;// 单例命名+ (UIApplication *)sharedApplication; 委托或代理方法命名第一个参数最好能相关某个对象。- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;私有方法不要以下划线““开头,因为系统私有方法保留此方式。自定义方法和系统方法重名,建议在方法开头加前缀”xx_methodName“。3.5 常量和宏的命名const常量外部声明:在Objective-C文件中优先采用FOUNDATION_EXTERN和UIKIT_EXTERN,而非C语言中的extern。const常量采用驼峰命名原则。const常量根据作用域适当加上前缀(含项目前缀):可供外部使用需加上相应的类名或者模块前缀,仅文件内部使用需要加上小写字母“k”.宏定义每个字母采用大写,单词之间用下划线“”间隔。宏定义也可根据作用范围加上适当前缀,避免命名冲突。3.6 枚举的命名使用枚举来定义一组相关的整数常量,增强代码的可读性。枚举可根据作用域添加前缀(含项目前缀),格式:[相关类名或功能模块名] + [描述] + [状态]。建议优先采用Objective-C的声明NS_ENUM和NS_OPTIONS,少采用C语言形式的enum等枚举声明.枚举定义时需指定None状态,并且其rawValue一般为起始值0。// NS_ENUMtypedef NS_ENUM(NSInteger, UIStatusBarAnimation) { UIStatusBarAnimationNone = 0, UIStatusBarAnimationFade = 1, UIStatusBarAnimationSlide = 2,}typedef NS_OPTIONS(NSUInteger, UIRemoteNotificationType) { UIRemoteNotificationTypeNone = 0, UIRemoteNotificationTypeBadge = 1 << 0, UIRemoteNotificationTypeSound = 1 << 1, UIRemoteNotificationTypeAlert = 1 << 2, UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,}3.7 通知命名外部声明:在Objective-C文件中优先采用FOUNDATION_EXTERN和UIKIT_EXTERN,而非C语言中的extern。通知的命名一般都是跨文件使用的,需添加项目前缀。// [相关联类名或者功能模块名] + [will/Did](可选) + [描述] + NotificationUIApplicationDidEnterBackgroundNotification UIApplicationWillEnterForegroundNotification 3.8 类型别名命名根据作用域添加前缀(含项目前缀),格式:[类名或功能模块名] + [描述]。4.文件资源命名规范资源文件命名也需加上项目前缀。资源文件名全小写,单词之间用下划线“”间隔。资源文件命名格式:[项目前缀] + [业务] + [文件名]图片文件命名格式:[项目前缀] + [业务] + [类型] + [状态]。// 常见类型:logol,icon,img// 常见状态:normal,selected,highlightUIImage *image = [UIImage imageNamed:@“wt_setting_icon_normal”];5.代码警告处理注意警告问题的隐蔽性,因此最好修复警告。警告类型的查看步骤:选中警告 -> 右键Reveal in Log(不编译Reveal in Log是灰色的,因此先编译) ->查看方括号的内容如果需要忽略警告,建议优先代码push或者pop处理。#pragma clang diagnostic push#pragma clang diagnostic ignored “-Warc-retain-cycles”// 造成警告的代码#pragma clang diagnostic pop如果警告数量过大,检查警告类型以及必要性,可xcode配置忽略此类型警告。步骤:选中工程 -> TARGETS -> Build Settings -> Other Warning Flags。忽略单个和全局配置稍有差别,如下举例:push/pop Other Warning Flags-Wformat —-> -Wno-format -Wunused-variable —-> -Wno-unused-variable -Wundeclared-selector —-> -Wno-undeclared-selector -Wint-conversion —-> -Wno-int-conversion也可以在pch等大范围作用域的头文件中添加代码来忽略后续警告:#pragma clang diagnostic ignored “警告名称” 。6.外部库文件引入库文件引入最好把警告处理掉。库文件引入优先采用CocoaPods引入,并且指定版本号。源文件方式需引入文件到工程目录下。源文件方式需注意有无版本说明信息(可能在README文件中,也可能在某个.h头文件中,又或者有Version文件)没有时需在库文件目录下新增版本说明文件,7.代码版本管理版本管理工具:svn 或 git。svn文件管理配置:目录/.subversion打开config文件配置global-ignore。git文件管理配置:.gitignore文件记录了被git忽略的文件,作用于本仓库,常见语法如下:井号(#)用来添加注释用的,比如 “#注释”。build/ : 星号()是通配符,build/则是要说明要忽略 build 文件夹下的所有内容。.pbxuser : 表示要忽略后缀名为.pbxuser的文件。!default.pbxuser : 感叹号(!)是取反的意思,.pbxuser 表示忽略所有后缀名为.pbxuser的文件,如果加上!default.pbxuser则表示,除了default.pbxuse忽略其它后缀名为pbxuse的文件。提交信息规范:BUG类型为“Fix + [BUG编号] + [BUG描述]”。任务类型为“Done + [任务编号] + [任务描述]”。任务中间态为“Doing + [任务编号] + [任务描述]”。引入类库为“import + [类库名]”。8.构建和分发手动构建:Xcode界面化构建注、xcodebuild终端命令构建。自动化构建:Jenkins+Fastlane、xcodebuild脚本执行 。内测分发渠道:fir.im、蒲公英等。线上分发渠道:AppStore。 ...

October 23, 2018 · 2 min · jiezi

测试工程师的福利!各远程移动测试平台对比分析

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯移动品质中心TMQ发表于云+社区专栏背景随着移动设备和系统的碎片化程度越来越高以及复杂的移动网络情况, 兼容性测试以及远程真机测试的重要性越来越突出。根据远程测试机/人员与开发者间的合作方式,可以分为以下几种服务:云测试服务、内测服务以及众测服务,相应的平台支持如下图。云测试平台云测试平台提供了远程租用真机的服务,通常是利用自动化框架来实现真机上的脚本自动化运行,或远程租用真机人工测试,或真人真机测试。由于Android端设备的种类众多,云测试服务在Android端应用广泛。国内外都提供了多种云测试平台。1、Pefectohttp://PerfectoMobile.comPefecto将真实移动设备放到cloud端 , 并提供通过web/Eclipse插件的形式进行访问与测试。同时,Pefecto开放了基于selenium的第三方API:MobileDriver,支持自动化测试人员通过Eclipse访问Perfecto上的真机设备,通过MobileDriver远程识别与调用被测应用,快速实现自动化,并与 RQM结合实现对devops的支持。测试脚本可以跨平台(Android/iOS/Blackberry…)执行。2、LessPainful http://lesspainful.com/LessPainful提供了一个多设备平台自动化测试的服务。用户上传应用(.apk)和用Cucumber编写的测试文件,选择测试运行需要的设备配置,最后测试将自动执行并生成测试报告。它支持的设备包括Garmin Asus,几款HTC,LG,Samsung Galaxy,Sony Xperia和Motorola Motodefy。3、TestDroidhttp://testdroid.com/Testdroid是由Bitbar公司推出的手机应用测试的云端服务。TestDroid云端提供了200多种机型,你可以选择你需要的测试机型进行适配测试。 通过Testdriod的测试,还能收集CPU运转以及内存使用情况,从而帮助工程师们提高应用的表现性能,和以防内存被过多占用。此外,用户还可以选择测试机型的语言测试环境,避免由于跨语言导致的潜在漏洞。Testdriod还有一项app爬虫功能,类似于网页爬虫,对你的应用高频次地查看并同时进行图像输出,来模拟真实的浏览过程。TestDroid应用了Robotium /MonkeyRunner生成系列工具,但需要有被测应用的源代码。4、Testinhttp://www.testin.cn/Testin云测试平台是一个基于真实终端设备环境,基于自动化测试技术的7x24云端服务。Testin在云端部署了300多款1000多部测试终端,并开放这些智能终端给全球移动开发者进行测试,开发者只需在Testin平台提交自己的App应用,选择需要测试的网络、机型,便可进行在线的自动化测试,无须人工干预,自动输出含错误、报警等测试日志、UI截图、内存/CPU/启动时间等在内的标准测试报告。支持Android与iOS,业务较为全面。5、百度MTChttp://mtc.baidu.com/MTC是百度云面向移动和web开发者提供的服务,能够满足一般的测试需求,包括当前的热门机型,还支持云端客户端回放。它还提供一个云众测服务,就是开放者上传App,百度提供给用户下载测试,然后将反馈收集返回给开发者。6、腾讯优测http://utest.qq.com/腾讯优测试专业化的移动云测试平台,为广大开发者提供移动应用一站式测试服务与解决方案。提供缺陷分析、应用测试、云手机等主要功能,用户通过平台上传安装包,就可进行全面的兼容性和性能测试,还并可以在线使用多台云端真机,满足更多开发和测试需要。腾讯优测真机实验室目前已配备上千款手机,覆盖市面98%主流机型,724小时在线运行,覆盖亿级用户。构建的数万个适配问题特征库,可以快速准确定位问题。7、阿里MQChttps://mqc.aliyun.com/MQC是阿里移动质量中心推出的真机测试服务的云平台,拥有大量热门机型,提供7x24全天候服务。MQC可以涵盖Android、iOS、YunOS、H5等不同的平台体系,主要服务阿里系和阿里内部如手淘、天猫、聚划算、支付宝等App。8、易测云http://www.yiceyun.com/易测云由国内知名软件公司东软出品,是一个专业为移动APP产品提供适配测试、性能测试、遍历测试、功能测试等多种服务的真机自动化云测试平台,主要为所有移动APP产品的开发者和测试者、以及需要定制化服务的企业级用户,提供安全、专业、高效、易用的自动化云测试服务;强大的录制脚本插件;详细实用的测试报告;以及简单人性化的操作体验。关于云测试平台对比分析的文章已经很多,这里不作赘述。众测平台众测的目的是利用大众的测试能力和测试资源,在短时间内完成大工作量的产品体验,第一时间将体验结果反馈至平台,再由平台管理人员将信息搜集,交给开发人员;同时是从最前端用户拿到的第一手信息,就能从用户角度出发,改善产品质量。1、uTesthttps://www.utest.comuTest是一家来自以色列的创业公司,该公司主要的业务是通过自己构建的一个全球测试员网络为开发人员和技术公司提供软件测试以帮助这些开发人员更好的找到并解决软件中的问题。拥有来自200多个地域国家超过15万专业测试人员。根据测试人员数量的不同,收费也各异,最低499美元,最高可达1999美元。uTest提供了uTest课堂提供了专业软件测试者授权课程的学习使用方法,还提供了工具平台供测试人员提交测试工具或对已有工具评分。总之,uTest给专业测试人员提供了一个社区的氛围。很多大公司都在使用uTest的服务,包括谷歌、微软、Groupon、AOL和BBC等。要想参与uTest测试任务,需要注册并提供详细的测试环境,比如测试机型、测试工作经验、软硬件环境等信息,便于uTest高效分配任务。2、腾讯teslyhttp://tesly.qq.com/腾讯众测是腾讯公司开发的一款基于众包概念的平台。支持应用、游戏、H5混合应用等。多种产品形态,具有Bug探索、产品调研、数据收集和产品评测四种业务模式。3、百度众测http://test.baidu.com.cn/crow…百度众测也是众包模式的典型应用,它将企业产品的相关测试工作交由网络社区大众来完成。百度众测是百度公司开发的众包在软件和产品测试上面的延伸。百度众测“隶属”百度质量部,是一个使广大的互联网用户能够第一时间体验到百度的新产品,从用户体验的角度出发,对百度的新产品提出改进建议,以及各种bug反馈,以便于百度公司及时地改善产品质量。目前,百度众测包括“外部用户测试平台”,“内部员工测试平台”和“开发者平台云众测”。注册用户达到1500万。4、testinhttp://zc.testin.cn/ http://www.mtestin.com/为开发者提供一种完全开箱即用、按需付费的SaaS服务,不仅提供了测试规划、功能测试、兼容性测试、可用性测试、Beta测试等测试服务,开发者还可以直接使用Testin众测平台的Bug管理、用例管理、项目管理、崩溃监控等在线工具,帮助中小开发者无需招聘专业的测试团队也可以轻松将应用质量管理好。5、乌云众测http://ce.wooyun.org/乌云众测是另一种众测类型,是在专业性很强的领域——安全领域深入的一种众测模式,它对众测人员的专业性要求很高,俗称“白帽子”。在乌云众测,企业可在短时间内组建虚拟的安全团队,通过邀请顶尖白帽子模拟黑客对网站、系统或产品进行测试,企业可迅速排查各种安全隐患。同类型的众测公司还有漏洞盒子、Sobug白帽众测,他们是目前国内最大的三家安全众测平台。众测平台总结:众测平台可以分为三种类型, 一种是大众任务型, 主要利用数量来收集数据或模拟特殊情境,如不同网络环境等, 百度众测和腾讯bugly都属于这一类; 第二类是以具有专业知识的测试人员来定向完成任务的模式, 这类的代表是国外的uTest和国内的Testin;第三类是应用于对测试人员专业度要求更高的某类业务——目前主要是安全业务——的模式, 著名的乌云众测、漏洞盒子、Sobug白帽众测就是利用白帽子的“攻”的水平来实现“防”的目的的。内测平台内测平台允许开发者选择合适的测试人员,并允许其与测试人员进行沟通。IOS应用分发多采用这种方式,以苹果收购的TestFlight为代表。这种模式操作起来稍微繁琐,如果是iOS应用的话需要制作特殊的内测版本,获取内测设备的UDID并制作证书,并且有100人的人数限制。1、TestFlighthttps://developer.apple.com/t…TestFlight提供了iOS App测试分发服务,它主要解决的是iOS应用测试分发困难问题,可向指定的人分发应用,双方需要注册TestFlight账号,以及下载TestFlight App,即可在App里测试应用。TestFlight已被苹果收购,因此其UDID证书限制人数可达到1000人。2、HockeyApphttps://www.hockeyapp.netHockeyApp是以TestFlight的替代者的身份出现的,其集成了TestFlight的所有优点,同时增加了自己的一些亮点功能,比如支持更多的平台,服务稳定性也比TestFlight高,并且能够通过SDK方式帮助开发者获取必要的测试信息。HockeyApp被微软收购,是收费应用。 3、Fir.imhttp://fir.im/Fir.im全名Fly It Remotely ,是一个为移动开发者服务,针对应用开发内测阶段,提供应用托管分发,崩溃分析以及反馈收集等一系列帮助开发者提高开发测试效率服务的平台。它提供了开放API,开发者可以将fir.im集成到开发流程中。此外,fir.im还提供了指令工具CLI, 日志查看工具LogGuru、崩溃分析工具BugHD和网速测试等工具。Android端还提供了AndroidStudio插件,方便Android开发者上传应用。4、蒲公英https://www.pgyer.com/蒲公英也提供了面向IOS和Android平台的内测托管和任务分发服务,同样提供开放API。 它提供了移动端SDK用于应用内测数据收集分析、版本更形提示、数据分析统计等多种功能。除此之外,它还提供了专家测试的选项,提供人工遍历测试,IOS审核加速等服务。并且,蒲公英提供了测试管理的平台,使得开发者在单平台上做到收集内测用户问题并得到问题分析。5、Bugly http://bugly.qq.com/Bugly 是腾讯对外开放使用的移动应用崩溃检测服务,同时支持iOS和Android平台。移动开发者在自己的App中接入Bugly的SDK后,就能在应用崩溃后获得信息上报。目前还推出了内测分发服务,但还没有提供收集用户测试结果的方法。内测平台总结:国内的内测平台都还属于起步阶段,更多应用场景在于帮助IOS应用快速发布。远程移动测试平台正在向综合云测、众测、内测甚至远程数据收集工具的方向发展,比如国内领先的Testin平台,在云测、众测攻占城池之后,也推出了内测平台https://pre.im/。蒲公英平台则在内测的基础之上,将bug管理融入平台。读者互动环节你工作中还有用到其他测试平台吗,期待你能给大家分享一下。问答如何并发JUnit测试?相关阅读Android单元测试kafka安装与测试性能测试知识总结 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

October 9, 2018 · 1 min · jiezi

Python 工匠:善用变量来改善代码质量

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由鹅厂优文发表于云+社区专栏作者:朱雷 | 腾讯IEG高级工程师『Python 工匠』是什么?我一直觉得编程某种意义上是一门『手艺』,因为优雅而高效的代码,就如同完美的手工艺品一样让人赏心悦目。在雕琢代码的过程中,有大工程:比如应该用什么架构、哪种设计模式。也有更多的小细节,比如何时使用异常(Exceptions)、或怎么给变量起名。那些真正优秀的代码,正是由无数优秀的细节造就的。『Python 工匠』这个系列文章,是我的一次小小尝试。它专注于分享 Python 编程中的一些偏『小』的东西。希望能够帮到每一位编程路上的匠人。变量和代码质量作为『Python 工匠』系列文章的第一篇,我想先谈谈 『变量(Variables)』。因为如何定义和使用变量,一直都是学习任何一门编程语言最先要掌握的技能之一。变量用的好或不好,和代码质量有着非常重要的联系。在关于变量的诸多问题中,为变量起一个好名字尤其重要。如何为变量起名在计算机科学领域,有一句著名的格言(俏皮话):There are only two hard things in Computer Science: cache invalidation and naming things. 在计算机科学领域只有两件难事:缓存过期 和 给东西起名字 – Phil Karlton第一个『缓存过期问题』的难度不用多说,任何用过缓存的人都会懂。至于第二个『给东西起名字』这事的难度,我也是深有体会。在我的职业生涯里,度过的作为黑暗的下午之一,就是坐在显示器前抓耳挠腮为一个新项目起一个合适的名字。编程时起的最多的名字,还数各种变量。给变量起一个好名字很重要,因为好的变量命名可以极大提高代码的整体可读性。下面几点,是我总结的为变量起名时,最好遵守的基本原则。1. 变量名要有描述性,不能太宽泛在可接受的长度范围内,变量名能把它所指向的内容描述的越精确越好。所以,尽量不要用那些过于宽泛的词来作为你的变量名:BAD: day, host, cards, tempGOOD: day_of_week, hosts_to_reboot, expired_cards2. 变量名最好让人能猜出类型所有学习 Python 的人都知道,Python 是一门动态类型语言,它(至少在 PEP 484 出现前)没有变量类型声明。所以当你看到一个变量时,除了通过上下文猜测,没法轻易知道它是什么类型。不过,人们对于变量名和变量类型的关系,通常会有一些直觉上的约定,我把它们总结在了下面。『什么样的名字会被当成 bool 类型?』布尔类型变量的最大特点是:它只存在两个可能的值『是』 或 『不是』。所以,用 is、has 等非黑即白的词修饰的变量名,会是个不错的选择。原则就是:让读到变量名的人觉得这个变量只会有『是』或『不是』两种值。下面是几个不错的示例:is_superuser:『是否超级用户』,只会有两种值:是/不是has_error:『有没有错误』,只会有两种值:有/没有allow_vip:『是否允许 VIP』,只会有两种值:允许/不允许use_msgpack:『是否使用 msgpack』,只会有两种值:使用/不使用debug:『是否开启调试模式』,被当做 bool 主要是因为约定俗成『什么样的名字会被当成 int/float 类型?』人们看到和数字相关的名字,都会默认他们是 int/float 类型,下面这些是比较常见的:释义为数字的所有单词,比如:port(端口号)、age(年龄)、radius(半径) 等等使用 id 结尾的单词,比如:user_id、host_id使用 length/count 开头或者结尾的单词,比如: length_of_username、max_length、users_count注意:不要使用普通的复数来表示一个 int 类型变量,比如 apples、trips,最好用 number_of_apples、trips_count 来替代。其他类型对于 str、list、tuple、dict 这些复杂类型,很难有一个统一的规则让我们可以通过名字去猜测变量类型。比如 headers,既可能是一个头信息列表,也可能是包含头信息的 dict。对于这些类型的变量名,最推荐的方式,就是编写规范的文档,在函数和方法的 document string 中,使用 sphinx 格式(Python 官方文档使用的文档工具)来标注所有变量的类型。3. 适当使用『匈牙利命名法』第一次知道『匈牙利命名法』,是在 Joel on Software 的一篇博文中。简而言之,匈牙利命名法就是把变量的『类型』缩写,放到变量名的最前面。关键在于,这里说的变量『类型』,并非指传统意义上的 int/str/list 这种类型,而是指那些和你的代码业务逻辑相关的类型。比如,在你的代码中有两个变量:students 和 teachers,他们指向的内容都是一个包含 Person 对象的 list 。使用『匈牙利命名法』后,可以把这两个名字改写成这样:students -> pl_students teachers -> pl_teachers其中 pl 是 person list 的首字母缩写。当变量名被加上前缀后,如果你看到以 pl 打头的变量,就能知道它所指向的值类型了。很多情况下,使用『匈牙利命名法』是个不错的主意,因为它可以改善你的代码可读性,尤其在那些变量众多、同一类型多次出现时。注意不要滥用就好。4. 变量名尽量短,但是绝对不要太短在前面,我们提到要让变量名有描述性。如果不给这条原则加上任何限制,那么你很有可能写出这种描述性极强的变量名:how_much_points_need_for_level2。如果代码中充斥着这种过长的变量名,对于代码可读性来说是个灾难。一个好的变量名,长度应该控制在 两到三个单词左右。比如上面的名字,可以缩写为 points_level2。绝大多数情况下,都应该避免使用那些只有一两个字母的短名字,比如数组索引三剑客 i、j、k,用有明确含义的名字,比如 persion_index 来代替它们总是会更好一些。使用短名字的例外情况有时,上面的原则也存在一些例外。当一些意义明确但是较长的变量名重复出现时,为了让代码更简洁,使用短名字缩写是完全可以的。但是为了降低理解成本,同一段代码内最好不要使用太多这种短名字。比如在 Python 中导入模块时,就会经常用到短名字作为别名,像 Django i18n 翻译时常用的 gettext 方法通常会被缩写成 _ 来使用(from django.utils.translation import ugettext as _)5. 其他注意事项其他一些给变量命名的注意事项:同一段代码内不要使用过于相似的变量名,比如同时出现 users、users1、 user3 这种序列不要使用带否定含义的变量名,用 is_special 代替 is_not_normal更好的使用变量前面讲了如何为变量取一个好名字,下面我们谈谈在日常使用变量时,应该注意的一些小细节。1. 保持一致性如果你在一个方法内里面把图片变量叫做 photo,在其他的地方就不要把它改成 image,这样只会让代码的阅读者困惑:『image 和 photo 到底是不是同一个东西?』另外,虽然 Python 是动态类型语言,但那也不意味着你可以用同一个变量名一会表示 str 类型,过会又换成 list。同一个变量名指代的变量类型,也需要保持一致性。2. 尽量不要用 globals()/locals()也许你第一次发现 globals()/locals() 这对内建函数时很兴奋,迫不及待的写下下面这种极端『简洁』的代码:def render(request, user_id, trip_id): user = User.objects.get(id=user_id) trip = get_object_or_404(Trip, pk=trip_id) is_suggested = is_suggested(user, trip) # 利用 locals() 节约了三行代码,我是个天才! return render(request, ’trip.html’, locals())千万不要这么做,这样只会让读到这段代码的人(包括三个月后的你自己)痛恨你,因为他需要记住这个函数内定义的所有变量(想想这个函数增长到两百行会怎么样?),更别提 locals() 还会把一些不必要的变量传递出去。更何况, The Zen of Python(Python 之禅) 说的清清楚楚:Explicit is better than implicit.(显式优于隐式)。所以,还是老老实实把代码写成这样吧: return render(request, ’trip.html’, { ‘user’: user, ’trip’: trip, ‘is_suggested’: is_suggested })3. 变量定义尽量靠近使用这个原则属于老生常谈了。很多人(包括我)在刚开始学习编程时,会有一个习惯。就是把所有的变量定义写在一起,放在函数或方法的最前面。def generate_trip_png(trip): path = [] markers = [] photo_markers = [] text_markers = [] marker_count = 0 point_count = 0 … …这样做只会让你的代码『看上去很整洁』,但是对提高代码可读性没有任何帮助。更好的做法是,让变量定义尽量靠近使用。那样当你阅读代码时,可以更好的理解代码的逻辑,而不是费劲的去想这个变量到底是什么、哪里定义的?4. 合理使用 namedtuple/dict 来让函数返回多个值Python 的函数可以返回多个值:def latlon_to_address(lat, lon): return country, province, city# 利用多返回值一次解包定义多个变量country, province, city = latlon_to_address(lat, lon)但是,这样的用法会产生一个小问题:如果某一天, latlon_to_address 函数需要返回『城区(District)』时怎么办?如果是上面这种写法,你需要找到所有调用 latlon_to_address 的地方,补上多出来的这个变量,否则 ValueError: too many values to unpack 就会找上你:country, province, city, district = latlon_to_address(lat, lon)# 或者使用 _ 忽略多出来的返回值country, province, city, _ = latlon_to_address(lat, lon)对于这种可能变动的多返回值函数,使用 namedtuple/dict 会更方便一些。当你新增返回值时,不会对之前的函数调用产生任何破坏性的影响:# 1. 使用 dictdef latlon_to_address(lat, lon): return { ‘country’: country, ‘province’: province, ‘city’: city }addr_dict = latlon_to_address(lat, lon)# 2. 使用 namedtuplefrom collections import namedtupleAddress = namedtuple(“Address”, [‘country’, ‘province’, ‘city’])def latlon_to_address(lat, lon): return Address( country=country, province=province, city=city )addr = latlon_to_address(lat, lon)不过这样做也有坏处,因为代码对变更的兼容性虽然变好了,但是你不能继续用之前 x, y = f() 的方式一次解包定义多个变量了。取舍在于你自己。5. 控制单个函数内的变量数量人脑的能力是有限的,研究表明,人类的短期记忆只能同时记住不超过十个名字。所以,当你的某个函数过长(一般来说,超过一屏的的函数就会被认为有点过长了),包含了太多变量时。请及时把它拆分为多个小函数吧。6. 及时删掉那些没用的变量这条原则非常简单,也很容易做到。但是如果没有遵守,那它对你的代码质量的打击是毁灭级的。会让阅读你代码的人有一种被愚弄的感觉。def fancy_func(): # 读者心理:嗯,这里定义了一个 fancy_vars fancy_vars = get_fancy() … …(一大堆代码过后) # 读者心理:这里就结束了?之前的 fancy_vars 去哪了?被猫吃了吗? return result所以,请打开 IDE 的智能提示,及时清理掉那些定义了但是没有使用的变量吧。7. 能不定义变量就不定义有时候,我们定义变量时的心理活动是这样的:『嗯,这个值未来说不定会修改/二次使用』,让我们先把它定义成变量吧!def get_best_trip_by_user_id(user_id): user = get_user(user_id) trip = get_best_trip(user_id) result = { ‘user’: user, ’trip’: trip } return result其实,你所想的『未来』永远不会来,这段代码里的三个临时变量完全可以去掉,变成这样:def get_best_trip_by_user_id(user_id): return { ‘user’: get_user(user_id), ’trip’: get_best_trip(user_id) }没有必要为了那些可能出现的变动,牺牲代码当前的可读性。如果以后有定义变量的需求,那就以后再加吧。结语碎碎念了一大堆,不知道有多少人能够坚持到最后。变量作为程序语言的重要组成部分,值得我们在定义和使用它时,多花一丁点时间思考一下,那样会让你的代码变得更优秀。这是『Python 工匠』系列文章的第一篇,不知道看完文章的你,有没有什么想吐槽的?请留言告诉我吧。问答 如何从变量名中获取字符串?相关阅读鹅厂优文 | ReactJS一点通开发效率太低?您可能没看这篇文章用CSS画小猪佩奇,你就是下一个社会人! 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识 ...

September 29, 2018 · 2 min · jiezi