关于代码优化:如何写出没有注释的代码dog

"If our programming languages were expressive enough, or if we had the talent to subtly wield those languages to express our intent, we would not need comments very much—perhaps not at all."-- Robert C.Martin 《Clean Code》若编程语言足够有表达力,或者咱们长于用这些语言来表白用意,那么咱们就不那么须要正文,甚至基本不须要。程序猿说要有代码,于是代码和正文就一起诞生了。有一句名言,每个程序员都会厌恶两件事件,浏览没有正文的代码,给代码写正文。 毕竟,人与人的悲欢并不相同,我只感觉你写的代码一团糟。如何一次解决程序猿的两大难题,不必写正文,也不会被别人吐槽没有正文呢? 为什么要缩小代码中的正文量呢? 正文的存在阐明以后的这段代码逻辑并不是特地清晰,没有额定阐明,别人就可能无奈了解用意。正文很难失去保护,一个工作开发完结后,散布在工作中的正文大概率就不会再被更新,随着工夫的推移,代码越来越简单,可能正文的信息早已不能精确反馈以后的逻辑了。缩小正文的过程也是一个从新扫视代码构造,精简代码的过程。那么蹩脚的正文有哪些,又有什么方法能够干掉这些正文呢?1.废话式正文后端不能信赖前端传入的任何信息,所以写代码的时候,也不能信赖旁边同学的任何能力。哪怕最简略的操作,也要减少一段正文来阐明操作的细节。 public void addInfo(Info info){ ... //向信息列表中追加信息内容 this.infoList.add(info); ...}置信你的同学的能力,常见的操作,即便没有正文,也可能通过上下文了解出你的用意的。 2.絮絮叨叨的正文代码逻辑太绕,为了避免它变成上帝的小机密,那就写上一段正文,这样就不会变成上帝的小机密了。 public void addInfos(List<Info> infos){ ... //如果Infos没有,就间接返回,如果Infos只有一个,那就删除数据库的信息,再写入。。。 ...}看似有了正文,再也不放心变成上帝的小机密了。然而一旦离正文较远的大量代码被批改,则会导致上帝从新独享这段代码的机密。 "Comments Do Not Make Up for Bad Code"-- Robert C.Martin 《Clean Code》正文并不能优化蹩脚的代码简单的正文阐明可能自身代码的逻辑是可能有问题的,整顿逻辑图并从新梳理状态机的模型,可能比写出简单的正文更有意义。从右边的七种可能的通路,多种执行的策略,到左边的清晰简略的二级判断+执行流程,状态及变动清晰简略。 3.代替代码分层的正文 ...

July 11, 2023 · 1 min · jiezi

关于代码优化:代码影响范围工具探索

作者:京东批发 田翻新、耿蕾 一、背景1.祖传代码不敢随便改变,影响范畴无奈评估。并且组内时常有因为批改了某块代码,导致其余业务受到影响,产生bug,影响生产。 2.研发提测实现后,测试进入测试后常常会向研发询问本次需要改变影响范畴,以此来确定测试用例,以达到精准测试,晋升整个需要的品质,缩短交付周期。 那么,如何能力躲避这种隐患?有没有一种工具可能帮助代码研发及review人员更加准确的判断以后代码改变影响范畴,有没有一种办法可能提供除了业务逻辑条件验证,针对代码作用范畴,给测试人员提供准确验证链路? 二、计划调研技术计划调研 通过各方材料查找及比对,最终咱们整顿了两个满足咱们需要的计划: 1.IDEA提供了显示调用指定Java办法向上的残缺调用链的性能,能够通过“Navigate -> Call Hierarchy”菜单(快捷键:control+option+H)应用,毛病是并没有向下的调用链生成。 2.开源框架调研:wala/soot动态代码剖析工具。 针对上述的调研,大抵确认了两种计划,集中剖析两种计划的优劣,来制订合乎咱们目前状况的计划: 工具名称劣势劣势是否合乎Call Hierarchy反对办法向上调用链性能比拟繁多,数据无操作性否wala/soot动态代码剖析可能欠缺的剖析Java中任何逻辑包含办法调用链,且满足咱们目前的需要臃肿,简单繁琐,性能过于宏大否通过后期的比拟以及相干工具的材料调研、工具功能分析,并思考到前期一些个性化性能定制开发,以上工具不太满足咱们目前的需要,所以决定本人入手,饥寒交迫,尝试从新开发一个可能满足咱们需要的工具,来帮助研发以及测试人员。 三、计划制订预期:工具尽量满足全自动化,研发只须要接入即可,缩小研发参加,晋升整个调用链展现和测试的效率。并且调用链路应该在研发打包的过程中触发,而后将数据上传至服务端,生成调用链路图。 上述计划制订实现后,须要进一步确认实现步骤。后期咱们确认了工具的大略的方向,并进行步骤合成,依据具体的性能将整个工具拆分成六个步骤 1.确认批改代码地位(行号)。与git代码治理关联,可能应用git命令,去提取研发最近一次提交代码的有变动的代码行数。 2.依据步骤1确认收集到影响的类+办法名+类变量。 3.依据2中确认的类+办法名称生成向上和向上的调用链。包含jar/aar包。 4.依据3中生成的调用链实现流程图的展现。 5.自定义正文标签Tag阐明以后业务,并提取Tag内容。 6.本地数据生成并上传服务端生成调用流程图。 整体流程图如下: 四、计划施行1.定位源代码批改地位行号。 首先咱们应用 git diff --unified=0 --diff-filter=d HEAD~1 HEAD命令 输入最近一次提交批改的内容,且已只git diff 会依照固定格局输入。 通过提交增、删、改的批改,执行git diff命令,对输入内容进行察看。 举例:某次提交批改了两个文件,如下 RecommendVideoManager.java ScrollDispatchHelper.java git diff命令执行后,输入以下内容: 技术计划: a.按行读取输入内容,读取到到diff 行,则辨认为一个新的文件,并用正则表达式提取文件名 : String[] lines = out.toString().split("\r?\n");Pattern pattern = Pattern.compile("^diff --git a/\S+ b/(\S+)");![]() b.用正则表达式提取 @@ -149 +148,0 @@ ,用来解析代码批改行数: Pattern pattern = Pattern.compile("^@@ -[0-9]+(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@");![]() ...

January 19, 2023 · 4 min · jiezi

关于代码优化:遗留代码处理技巧与案例演示

1 什么是遗留代码实质是一种技术债权,产生起因一方面是业务起因:如业务自身场景繁多、流程简单等;另一方面是技术起因:如代码不标准、设计不合理、祖传代码文档正文缺失等。它会影响咱们的程序很多方面:如可读性、可修改性、可复用性、可维护性、可测试性等。 2 遗留代码处理过程拆解划分为梳理->重构/重写->替换/验证三个阶段 2.1 梳理遗留代码的解决是一种逆向工程,从已有的代码+数据模型+文档倒推出业务模型、交互和规定,在保真的前提下再从新构建代码+数据模型+文档。 咱们这里能够参考下DDD畛域驱动设计里策略设计局部罕用的工具(事件风暴法)来进行这部分梳理工作。 事件风暴实质上是一种零碎建模的办法,与它处于对等地位的,会有“UML建模”、“事件驱动建模”等。事件风暴跟麻利开发里的一些理念(如用户故事)的产生背景相似,都是在感性思考无奈应答变动频繁且文字难以描述的状况下,通过一些辅助性的提醒卡片、视觉伎俩,辅以相干人员的集中、高频沟通来实现对于业务的精确把握和形象建模。 事件风暴的过程: 通过梳理业务流程,创立相应的畛域事件(Event)补充引发每个畛域事件的命令(Command)通过实体/聚合把命令和事件关联起来划分畛域边界及事件流动线条辨认用户操作所需的关联视图及其角色事件风暴的产物: 畛域对象 即实体/聚合。这里的畛域对象并非数据库模型, 而是与业务紧密联系的“对象”。因为事件风暴是一种面向对象的建模形式, 而不是面向数据库的建模形式。畛域事件 即对象在某些操作或特点时点下所产生的事件, 这些事件将决定之后多个聚合和限界上下文(BC)之间的通信形式。限界上下文 当所有的对象(实体/聚合)被梳理进去后,属于同一种“通用语言”的对象, 则会被纳入同一个限界上下文边界内;不属于同一种“通用语言”的对象, 则会被边界给宰割开,划入不同的子域或限界上下文。梳理后果示例: 2.2 重构/重写通过重构/重写对软件因素进行从新组织,使其不扭转内部行为的状况下,晋升代码的可读性或使其构造更正当。 针对不同档次的软件因素要做不同的解决和管制: 并且整个重构/重写过程有些须要遵循的准则: 繁多职责:能够将依赖归拢,对立行为和管制。权责明确,场景明确。繁多准则:打消反复的数据申明、行为;因为繁多所以保障了复用,统一标准 ,可拆卸性。封装准则:不须要适度关怀依赖类外部实现,最好一个.就能调用。归属准则:上帝的归上帝,凯撒的归凯撒。谁提供的数据更多,归属于谁。抽象层次:越高层的形象越稳固,越细节的货色越容易变动。举例:接口应传递职责而非实现细节。开闭准则:对批改敞开,对扩大凋谢。kiss准则: 好了解,好保护。清晰准则:只读小局部代码就能够晓得怎么改逻辑,做扩大。而不是要通读所有代码,能力理清。其中有两点落地细节咱们具体分析下: 业务逻辑的解决 业务代码和技术代码解耦 主流程代码和附加流程代码解耦 长链路的拆解编排关注点的拆散 双向依赖:上下文之间短少一层未被廓清的上下文,或者两个上下文其实可被合为一个; 循环依赖:任何一个上下文产生变更,依赖链条上的上下文均须要扭转; 过深的依赖:本身依赖的信息不能间接从依赖者获取到,须要通过依赖者从其依赖的上下文获取并传递,依赖链路过长,依赖链条上的任何一个上下文产生变更,其链条后的任何一个上下文均可能须要扭转;2.3 替换验证大略分为以下几个要点: 体会用意,抽取用例,减少可复测性减少可监测性分成小块,逐渐替换试点、看到功效可借助过程管理工具如PDCA法进行治理 3 案例演示3.1 案例1:针对强耦合的实现做重构原始需要:案例为一个转账服务,用户能够通过银行网页转账给另一个账号,反对跨币种转账。同时因为监管和对账需要,须要记录本次转账流动。 原始架构:是一个传统的三层分层构造:UI层、业务层、和基础设施层。下层对于上层有间接的依赖关系,导致耦合度过高。在业务层中对于上层的基础设施有强依赖,耦合度高。咱们须要对这张图上的每个节点做形象和整顿,来升高对外部依赖的耦合度。 重构要害设计点: 重构后代码特色: 业务逻辑清晰,数据存储和业务逻辑齐全分隔。 Entity、Domain Primitive、Domain Service都是独立的对象,没有任何内部依赖,然而却蕴含了所有外围业务逻辑,能够独自残缺测试。 原有的转账服务不再包含任何计算逻辑,仅仅作为组件编排,所有逻辑均delegate到其余组件。 3.2 案例2:进步老代码的复用性原始需要:现有几个策略实现类,被很多代码应用。当初须要依据不同的业务方在每个策略执行前做不同的前置逻辑解决。 解法剖析:尽量避免把逻辑耦合到已有的实现类中。引入外部类进行管制反转。这里咱们应用访问者模式。 访问者模式把数据结构和作用于构造上的操作解耦合,使得操作汇合可绝对自在地演变。访问者模式实用于数据结构绝对稳固算法又易变动的零碎。因为访问者模式使得算法操作减少变得容易。若零碎数据结构对象易于变动,常常有新的数据对象减少进来,则不适宜应用访问者模式。访问者模式的长处是减少操作很容易,因为减少操作意味着减少新的访问者。访问者模式将无关行为集中到一个访问者对象中,其扭转不影响零碎数据结构。其毛病就是减少新的数据结构很艰难。 具体实现: 重构后代码特色: 能够通过访问者对老代码逻辑进行编排,将批改外置,缩小对老逻辑的影响 通过java8默认接口实现提供默认拜访行为,防止大量策略子类的感知,只须要须要提供本人实现行为的子类对默认实现进行覆写 4 总结遗留代码的解决能力一方面是对技术的要求,另一方面也是对业务把握的挑战。心愿咱们能够逾越荆棘、穿过迷雾,顺利达到胜利的此岸! 作者:冯鸿儒

November 9, 2022 · 1 min · jiezi

关于代码优化:海外低代码平台简析二ServiceNow是如何成为SaaS企业中的增长神话

海内低代码平台简析(二):ServiceNow是如何成为SaaS企业中的增长神话ServiceNow是一家以ITSM业务起家的美国SaaS企业,在2004年成立之后,一路高歌猛进,到2012年,仅用8年工夫就在纽交所上市;2016年时,ServiceNow已碾过IBM、BMC、惠普等一众巨头成为ITSM行业的相对龙头;2018年,投资机构预测ServiceNow的市值将在2023年达到1000亿美元,没想到仅仅两年的工夫,ServiceNow便将市值从2018年的320亿美元翻到了2020年的1073亿美元,截止2021年10月11日,其市值已超过1223亿美元,稳坐寰球TOP3 SaaS企业宝座。 ServiceNow在2013年之前,每年都放弃着100%以上的支出增速,在2015年收入达到10亿美元之后,仍然能放弃年均超过40%的增速。ServiceNow上市后仅用8年工夫,市值便跃升到1000亿美元,是美股中最快实现千亿市值的SaaS企业,神个别的增长速度令泛滥SaaS企业可望不可即。 ServiceNow为何能够增长得如此之快?本文将从创始人、市场抉择、业务流程布局、大客户获取能力、产品追加销售能力等五个方面,帮忙大家充沛理解ServiceNow。 01. 创始人在ITSM畛域经验丰富大型企业的业务流程复杂程度远不是一个标准化产品能够解决的,所以针对大型企业的SaaS产品很难做,须要对业务有十分粗浅的了解。ServiceNow的创始人Fred Luddy曾任Remedy的CEO十余年,Remedy一度成为过后ITSM畛域的龙头,能够说没人比Fred Luddy更懂技术和业务。凭借着Luddy的行业影响力和丰盛的教训,ServiceNow得以在后期倒退的蛟龙得水。 02. 正确的细分市场抉择,获得先发劣势ServiceNow在成立时就抉择了SaaS ITSM作为指标市场。过后ITSM畛域的竞争十分大,它的竞争对手包含IBM、Oracle、惠普、BMC等一众巨头。但他们的服务形式仍然是大型主机本地部署,能够说ServiceNow是第一家ITSM云服务企业。 2010年前后,随着互联网的爆发式倒退、Salesforce、Workday等SaaS企业的崛起,与企业越来越迫切的云转型需要,ServiceNow迎来了需要暴发期。SaaS模式与传统本地部署的用户体验差距,使得企业违心付出微小的替换成原本改善业务流程。于是,短短几年,ServiceNow凭借本人在SaaS ITSM畛域的先发劣势和技术积攒,疾速做到行业龙头并上市。   03. 围绕 ITSM逐步布局全业务流程治理ServiceNow以服务场景为导向,整合客户数据、资源,构建一个绝对残缺的IT服务场景,并非以一个IT流程审批的角度进行建设。ServiceNow的产品采纳的是多实例+多租户架构,相比于市场上的SaaS企业广泛应用多租户架构领有更强的定制化能力和安全性,这对于具备高个性化和独立数据库需要的大企业*更具吸引力。 ServiceNow领有寰球一流的业务流引擎,从ITSM业务起步,并以此为根底,将IT业务流能力延长到CRM、HR、风险管理、客户服务治理等畛域,逐步形成 “利用+平台” 的产品体系,使得ServiceNow可能一直地扩充业务范围,浸透垂直行业,推动产品体系丰盛欠缺,对标Salesforce,打造平台生态型SaaS企业。 04. 大客户是其支出外围不像Salesforce,通过大量的收买来疾速扩张支出和企业规模,也不像国内的一些SaaS企业有着夸大的客户基数,ServiceNow的增长外围是其获取大客户的能力, 次要为员工数超过 1000人、年收入超过 5 亿美元的企业提供服务。截止到2020年底,80%的世界500强企业,超过50%的世界2000强企业是其长期客户。大企业高粘性的特点使其续约率始终保持在96%--98%之间。 大客户为ServiceNow带来了高客单价的订单、稳固的现金流、疾速的技术和行业常识积攒和品牌力的晋升。2007年,仅3年工夫,ServiceNow就实现了正向的经营现金流。2020年,ServiceNow的均匀客单价达到了65.5万美元,ACV(均匀合同价值)大于100万美元的客户有1093个。尽管到当初ServiceNow的客户还不到7000个,但大客户的稳固、高粘性使得其不须要夸大的客户数量根底就能实现快速增长。 05. 追加销售是增长的重要根底ServiceNow获取新客户的外围产品是ITSM,一旦客户采纳,便有机会采购其余配套产品。尽管它的CRM、HR等产品起步较晚,但其功能性并不弱于Salesforce、Workday等大企业,而且跟自家ITSM零碎完满适配,省去了零碎转换的老本(应用其余公司产品会遇到系统集成问题)。依据年报披露,新增支出中,老客户奉献了80%;非IT类产品占比从2011年的5.5%增至2020年的38%。2018 年,ServiceNow组建了翻新业务部门 NowX,并争取每年推出一到两个新产品。另外,每年ServiceNow都在对产品进行升级换代,降级后的产品价格广泛比上一个版本高25%。随着产品组合的一直扩张和降级,产品追加销售的能力将成为驱动增长的次要能源。 结语ServiceNow在2020年收买AI企业Rupert Labs,2021年又收买智能RPA开发公司Intellibot。ServiceNow在无意放慢在其余畛域的开疆扩土,追寻科技趋势,以放弃增长空间。但近两年,ITSM市场趋近饱和,随着支出基数的增大,ServiceNow失去了厉害的增长速度。不知ServiceNow还是否持续发明“最快达成百亿营收SaaS企业”的奇观呢?一起期待下。 关注公众号:低代码LowCode,每周分享海内低代码畛域新技术、新观点和新风向!

November 12, 2021 · 1 min · jiezi

关于代码优化:代码安全无忧云效Codeup代码加密技术发展之路

简介:从代码服务及代码平安角度登程,看看云效代码加密技术如何解决这一问题 代码数据存在云端,如何保障它的平安? 局部企业管理者对于云端代码托管存在一丝放心:我的代码存在云端服务器,会不会被泄露? 接下来,咱们将从代码服务及代码平安角度登程,看看云效代码加密技术如何解决这一问题。 一、前言1. 代码托管服务什么是代码托管服务? 代码托管服务是运行在公共环境,提供软件版本控制治理的服务。 代码托管服务外围要解决的两个问题: • 存档:须要具备存档的能力,也就是,把咱们当前工作产出的某个正本保留下来,用于复制、追溯等等。• 合作:能够让不同的人,基于同一个对象内容进行工作,他们的成绩能够一起体现在这个内容之上。 Git 自诞生以来,就和“开源”、“共享”这些词紧紧地分割在一起,它之所以能疾速推广,并成为支流的软件版本控制工具,正是得益于它扭转了传统软件版本控制工具的合作形式,让软件奉献与合作变得更加高效与便捷。 2. 代码托管服务的两种状态代码托管服务通常有两种状态: • 应用开源产品或购买公有部署产品,架设在用户齐全可控的部署环境上来提供服务。• 应用云托管服务产品,只领有对服务的使用权,而不用关注服务的运维。 2.1 自建代码托管服务 代码资产作为企业资产的重要组成部分,始终备受器重。许多企业、机构都会有自运维的代码托管服务。无论是从齐全管制还是数据安全的心理上来说,私网服务仿佛更加可信与无懈可击,但随之而来的稳定性、可靠性的问题,却往往让中小企业焦头烂额。 企业倒退之初,兴许只须要一个服务器资源,搭建一个可用的代码托管服务,即可满足肯定的日常研发需要;但随着企业规模不断扩大,遇到的问题逐渐增多,开始须要投入专人来治理这个服务;而企业研发人员倒退到千人以上的规模,甚至须要投入一个小的团队,来负责代码托管服务的运维及定制化开发工作。这无疑是一笔不小的老本开销。 此外,因为自建服务配套不欠缺,很容易产生部分运维权限过大而引发平安危险,删库跑路等恶性事件,局部IT从业者能够仅凭一己之力蒸发公司上亿的市值,无时无刻在为咱们敲响警钟。 2.2 云代码托管服务而云代码托管服务,以云共享的形式,提供更大范畴的服务能力;同时,因为其背地往往都领有一支教训深厚的运维治理及产品团队,其可靠性远胜于企业自建的托管服务。 但相比较而言,因为云代码托管服务对用户而言只有使用权,无奈登录存储服务器,无奈感知其背地的存储和复制机制,又因为代码自身的敏感性,对云代码托管服务的信赖问题(如认为代码数据对服务提供方运维人员可见)始终是一些中大型企业的症结。 3. 代码托管服务的演进方向随着云计算一直演进,通过云原生技术理念的利用能够最大化享受云计算的技术红利,包含弹性伸缩、按量付费、无厂商绑定、高SLA等。而在实际云原生理念时,势必须要:• 采取DevOps畛域的最佳实际来治理研发和运维流程。• 通过CICD工具链做到利用的疾速迭代和继续交付。 GitOps、Iac(Infrastructure as code)当初越来越多地被泛滥企业所驳回,代码托管服务也逐步成为了一种具备软件版本控制能力与合作能力的存储基础设施,其在可靠性及跨地区拜访方面的能力,也逐步成为各大云代码托管服务的外围掂量指标。而这方面的能力,也正是自建代码托管服务所不能满足的中央。那么,如何打造云代码托管平安体系,来晋升用户的信任感呢? 4. 云代码托管平安体系为了更好地撑持代码托管服务的存档能力,云代码托管体系通常会依照以下四个方面来建设: 拜访平安:拜访平安包含但不限于认证、权限管制、数据传输等等,它次要解决用户的身份辨认,最小限度地赋予指定用户所需的正当权限,在事先最大水平保障代码资产的安全性,同时通过对传输过程数据加密(如常见的https、openssl加密)等伎俩,防止中间人截取或篡改用户的数据。 数据可信:在拜访平安的根底上,还须要通过一些额定的伎俩,确保代码提交及代码归属的可信度(如仅承受特定属主的代码,或要求必须对提交记录进行GPG签名),从而进一步升高因为账号泄露等导致的危险。 存储平安:作为云代码托管服务最外围的能力,存储平安岂但要保障服务的可靠性,数据资产不失落,更能够通过存储快照及备份等伎俩,升高用户应用过程中的危险。同时,如何保障存储于物理设施的数据,不产生数据泄露危险,也是用户最为关怀的问题。 审计风控:在事先及事中平安能力之外,在预先通过智能化危险辨认、主动防御等伎俩,进一步加固整个平安防护体系。 在拜访平安、数据可信、审计风控等不便,目前各云代码托管服务或多或少的都具备了一些这样的能力,但我认为,存储平安才是最外围的竞争力。在这其中,代码数据加密技术的摸索,也是最具备挑战的。 5. 数据加密技术通过对数据内容进行加密,并将关上这把锁的钥匙,交到用户手中,是当下泛滥云服务用于解决用户信赖问题的银弹。为此,具备云盘加密、云端加密能力的对象存储服务更容易被用户承受,众数据库服务厂商(如MySQL、Oracle、PostgreSQL等),也纷纷在自家产品上推出了TDE(Transparent Data Encryption)的能力。 那么,同样具备存储属性的代码托管服务,是否也能够引入数据加密的能力呢?在提供用户对代码资产的备份、删除能力之外,通过数据加密,让用户的数据资产仅对用户本人可见,从而达到对代码存储的近齐全可控的目标。 二、业界代码加密计划1. 客户端加密以开源软件 git-crypt 为代表的客户端加密办法,是针对敏感信息存储的不错抉择。用户生成一个数据密钥,用于对指标文件加密,将加密后的内容,提交到git仓库当中。 在这种模式下,加密的内容,仅提交人可见,而当你须要与别人共享时,能够通过获取别人的 PGP 公钥,对用于加密的数据密钥加密后,提交到代码仓库。对方在获取到数据密钥密文后,应用本人的PGP私钥解密,失去数据密钥,就能够解密数据了。 但这种形式的弊病也很显著,数据密钥获取一次,就能够重复应用,无奈解除受权;原有的文本文件加密后变成了二进制文件,也导致git无奈对增量批改创立delta,大量应用及频繁变更就会导致仓库体积迅速收缩。 2. 磁盘加密磁盘加密技术曾经十分成熟,仿佛也是一个很好的抉择计划。但磁盘加密仅解决物理设施层面的数据安全问题,在vm(虚拟机)层面,依然是明文拜访数据的。 3. 服务端闲时加密对于应用不频繁的代码仓库,闲时加密也不失为一种好的解决方案。在一个Git仓库不被拜访时,对其进行加密,而当其从新须要被拜访时,就须要期待解密实现,再凋谢拜访。 这种计划的通用性很高,也能够有很多种加密的计划能够抉择,实现的老本也不高,但毛病也很显著:仓库拜访须要一个预热的过程,仓库越大,预热工夫也相应越长;高频拜访的仓库,简直总是以非加密的状态存储在磁盘上,而这些热点仓库,也往往是用户最为关注,也最不冀望被泄露的。 4. 基于JGit、S3的云存储加密AWS的代码托管产品CodeCommit,提供了代码加密的能力,它基于JGit实现的代码托管服务,复用了原有JGit的存储模型,利用S3的存储加密能力。 JGit的社区活跃度大大低于Git的社区活跃度,并且在性能比照上,Git也是远胜于JGit,这也是各大支流代码托管服务均应用Git的起因。 三、云端代码托管的通明加密云代码托管服的通明加密,是一种服务端加密技术(Server-Side Encryption):它应用用户受权的密钥来实现对用户代码数据的加密;在用户拜访时,应用用户的密钥来对数据进行解密。整个加解密的过程对用户齐全通明,用户能够应用惯例的Git客户端来进行代码库拜访,或是浏览代码服务提供的页面服务;但用户保留对数据的齐全掌控,能够在必要时,通过勾销密钥受权,达到解冻代码数据的目标。 1. 云端通明加密的劣势Git TDE(Transparent Data Encryption)的劣势: • 不依赖文件系统。• 文件系统拜访的数据都是密文。• 可抉择仅加密一些敏感仓库来升高对性能的影响。 ...

May 13, 2021 · 1 min · jiezi

Spring-MVC-统一响应格式源码分析以及问题解决

快速上手一般我们在写服务的时候,会有统一的返回格式,在这篇文章中用RespMsg表示。 比如根据用户的id要获取用户的信息。 第一版代码如下 @PostMapping(value = "user/{id}")public RespMsg getUserById(@PathVariable Long id) { try { return RespMsg.success(userService.getUserById(id)); } catch (BusinessException e) { log.error(e.getMessage(), e); return RespMsg.failed(e.getErrCode(), e.getMessage()); }}看了上一篇你真的了解spring boot全局异常处理吗,就可以改写为第二版 @PostMapping(value = "user/{id}")public RespMsg getUserById(@PathVariable Long id) throws BusinessException { return RespMsg.success(userService.getUserById(id));}看了这篇,就可以改写为第三版 @PostMapping(value = "user/{id}")public User getUserById(@PathVariable Long id) throws BusinessException { return userService.getUserById(id);}实现方式也很简单,通过实现ResponseBodyAdvice搭配@ControllerAdvice即可 @ControllerAdvicepublic class ResponseWrapperAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { //如果已经是RespMsg类型的则直接返回 if (body instanceof RespMsg) { return body; } //如果不是,则封装 return RespMsg.success(body); }}supports方法用于判断是否支持,如果不支持则不会调用beforeBodyWrite。具体可见RequestResponseBodyAdviceChain的processBody方法。既然是统一,这里都返回true了。beforeBodyWrite方法用于改写响应。然后就大功告成了,so easy。 ...

November 3, 2019 · 2 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

从HelloWorld看Knative-Serving代码实现

摘要: Knative Serving以Kubernetes和Istio为基础,支持无服务器应用程序和函数的部署并提供服务。我们从部署一个HelloWorld示例入手来分析Knative Serving的代码细节。概念先知官方给出的这几个资源的关系图还是比较清晰的: 1.Service: 自动管理工作负载整个生命周期。负责创建route,configuration以及每个service更新的revision。通过Service可以指定路由流量使用最新的revision,还是固定的revision。2.Route:负责映射网络端点到一个或多个revision。可以通过多种方式管理流量。包括灰度流量和重命名路由。3.Configuration:负责保持deployment的期望状态,提供了代码和配置之间清晰的分离,并遵循应用开发的12要素。修改一次Configuration产生一个revision。4.Revision:Revision资源是对工作负载进行的每个修改的代码和配置的时间点快照。Revision是不可变对象,可以长期保留。 看一个简单的示例我们开始运行官方hello-world示例,看看会发生什么事情: apiVersion: serving.knative.dev/v1alpha1kind: Servicemetadata: name: helloworld-go namespace: defaultspec: runLatest: // RunLatest defines a simple Service. It will automatically configure a route that keeps the latest ready revision from the supplied configuration running. configuration: revisionTemplate: spec: container: image: registry.cn-shanghai.aliyuncs.com/larus/helloworld-go env: - name: TARGET value: "Go Sample v1"查看 knative-ingressgateway: kubectl get svc knative-ingressgateway -n istio-system 查看服务访问:DOMAIN kubectl get ksvc helloworld-go --output=custom-columns=NAME:.metadata.name,DOMAIN:.status.domain 这里直接使用cluster ip即可访问 ...

May 22, 2019 · 4 min · jiezi

30秒的PHP代码片段(3)字符串-String & 函数-Function

本文来自GitHub开源项目点我跳转30秒的PHP代码片段精选的有用PHP片段集合,您可以在30秒或更短的时间内理解这些片段。字符串endsWith判断字符串是否以指定后缀结尾,如果以指定后缀结尾返回true,否则返回false。function endsWith($haystack, $needle){ return strrpos($haystack, $needle) === (strlen($haystack) - strlen($needle));}ExamplesendsWith(‘Hi, this is me’, ‘me’); // truefirstStringBetween返回参数start和end中字符串之间的第一个字符串。function firstStringBetween($haystack, $start, $end){ return trim(strstr(strstr($haystack, $start), $end, true), $start . $end);}ExamplesfirstStringBetween(‘This is a [custom] string’, ‘[’, ‘]’); // customisAnagram检查一个字符串是否是另一个字符串的变位元(不区分大小写,忽略空格、标点符号和特殊字符)。就是所谓的字谜function isAnagram($string1, $string2){ return count_chars($string1, 1) === count_chars($string2, 1);}ExamplesisAnagram(‘fuck’, ‘fcuk’); // trueisAnagram(‘fuckme’, ‘fuckyou’); // falseisLowerCase如果给定字符串是小写的,则返回true,否则返回false。function isLowerCase($string){ return $string === strtolower($string);}ExamplesisLowerCase(‘Morning shows the day!’); // falseisLowerCase(‘hello’); // trueisLowerCase如果给定字符串为大写,则返回true,否则返回false。function isUpperCase($string){ return $string === strtoupper($string);}ExamplesisUpperCase(‘MORNING SHOWS THE DAY!’); // trueisUpperCase(‘qUick Fox’); // falsepalindrome如果给定字符串是回文,则返回true,否则返回false。回文,顾名思义,即从前往后读和从后往前读是相等的function palindrome($string){ return strrev($string) === (string) $string;}Examplespalindrome(‘racecar’); // truepalindrome(2221222); // truestartsWith检查字符串是否是以指定子字符串开头,如果是则返回true,否则返回false。function startsWith($haystack, $needle){ return strpos($haystack, $needle) === 0;}ExamplesstartsWith(‘Hi, this is me’, ‘Hi’); // truecountVowels返回给定字符串中的元音数。使用正则表达式来计算字符串中元音(A, E, I, O, U)的数量。function countVowels($string){ preg_match_all(’/[aeiou]/i’, $string, $matches); return count($matches[0]);}ExamplescountVowels(‘sampleInput’); // 4decapitalize使字符串的第一个字母去大写。对字符串的第一个字母进行无头化,然后将其与字符串的其他部分相加。省略upperRest参数以保持字符串的其余部分完整,或将其设置为true以转换为大写。function decapitalize($string, $upperRest = false){ return lcfirst($upperRest ? strtoupper($string) : $string);}Examplesdecapitalize(‘FooBar’); // ‘fooBar’isContains检查给定字符串输入中是否存在单词或者子字符串。使用strpos查找字符串中第一个出现的子字符串的位置。返回true或false。function isContains($string, $needle){ return strpos($string, $needle);}ExamplesisContains(‘This is an example string’, ’example’); // trueisContains(‘This is an example string’, ‘hello’); // false函数compose返回一个将多个函数组合成单个可调用函数的新函数。function compose(…$functions){ return array_reduce( $functions, function ($carry, $function) { return function ($x) use ($carry, $function) { return $function($carry($x)); }; }, function ($x) { return $x; } );}…为可变数量的参数,http://php.net/manual/zh/func…Examples$compose = compose( // add 2 function ($x) { return $x + 2; }, // multiply 4 function ($x) { return $x * 4; });$compose(3); // 20memoize创建一个会缓存func结果的函数,可以看做是全局函数。function memoize($func){ return function () use ($func) { static $cache = []; $args = func_get_args(); $key = serialize($args); $cached = true; if (!isset($cache[$key])) { $cache[$key] = $func(…$args); $cached = false; } return [‘result’ => $cache[$key], ‘cached’ => $cached]; };}Examples$memoizedAdd = memoize( function ($num) { return $num + 10; });var_dump($memoizedAdd(5)); // [‘result’ => 15, ‘cached’ => false]var_dump($memoizedAdd(6)); // [‘result’ => 16, ‘cached’ => false]var_dump($memoizedAdd(5)); // [‘result’ => 15, ‘cached’ => true]curry(柯里化)把函数与传递给他的参数相结合,产生一个新的函数。function curry($function){ $accumulator = function ($arguments) use ($function, &$accumulator) { return function (…$args) use ($function, $arguments, $accumulator) { $arguments = array_merge($arguments, $args); $reflection = new ReflectionFunction($function); $totalArguments = $reflection->getNumberOfRequiredParameters(); if ($totalArguments <= count($arguments)) { return $function(…$arguments); } return $accumulator($arguments); }; }; return $accumulator([]);}Examples$curriedAdd = curry( function ($a, $b) { return $a + $b; });$add10 = $curriedAdd(10);var_dump($add10(15)); // 25once只能调用一个函数一次。function once($function){ return function (…$args) use ($function) { static $called = false; if ($called) { return; } $called = true; return $function(…$args); };}Examples$add = function ($a, $b) { return $a + $b;};$once = once($add);var_dump($once(10, 5)); // 15var_dump($once(20, 10)); // nullvariadicFunction(变长参数函数)变长参数函数允许使用者捕获一个函数的可变数量的参数。函数接受任意数量的变量来执行代码。它使用for循环遍历参数。function variadicFunction($operands){ $sum = 0; foreach($operands as $singleOperand) { $sum += $singleOperand; } return $sum;}ExamplesvariadicFunction([1, 2]); // 3variadicFunction([1, 2, 3, 4]); // 10相关文章:30秒的PHP代码片段(1)数组 - Array30秒的PHP代码片段(2)数学 - Math ...

February 19, 2019 · 2 min · jiezi

30秒的PHP代码片段(2)数学 - Math

本文来自GitHub开源项目点我跳转30秒的PHP代码片段精选的有用PHP片段集合,您可以在30秒或更短的时间内理解这些片段。数学函数average返回两个或多个数字的平均值。function average(…$items){ $count = count($items); return $count === 0 ? 0 : array_sum($items) / $count;}Examplesaverage(1, 2, 3); // 2factorial(阶乘)计算一个数的阶乘。function factorial($n){ if ($n <= 1) { return 1; } return $n * factorial($n - 1);}Examplesfactorial(6); // 720fibonacci(斐波那契数列)生成包含斐波那契数列的数组,直到第n项。function fibonacci($n){ $sequence = [0, 1]; for ($i = 2; $i < $n; $i++) { $sequence[$i] = $sequence[$i-1] + $sequence[$i-2]; } return $sequence;}Examplesfibonacci(6); // [0, 1, 1, 2, 3, 5]GCD(最大公约数)计算两个或多个数之间的最大公约数。function gcd(…$numbers){ if (count($numbers) > 2) { return array_reduce($numbers, ‘gcd’); } $r = $numbers[0] % $numbers[1]; return $r === 0 ? abs($numbers[1]) : gcd($numbers[1], $r);}Examplesgcd(8, 36); // 4gcd(12, 8, 32); // 4isEven如果给定的数字是偶数,则返回true,否则返回false。function isEven($number){ return ($number % 2) === 0;}ExamplesisEven(4); // trueisPrime检查提供的整数是否是素数。function isPrime($number){ $boundary = floor(sqrt($number)); for ($i = 2; $i <= $boundary; $i++) { if ($number % $i === 0) { return false; } } return $number >= 2;}ExamplesisPrime(3); // truelcm返回两个或多个数字的最小公倍数。function lcm(…$numbers){ $ans = $numbers[0]; for ($i = 1, $max = count($numbers); $i < $max; $i++) { $ans = (($numbers[$i] * $ans) / gcd($numbers[$i], $ans)); } return $ans;}Exampleslcm(12, 7); // 84lcm(1, 3, 4, 5); // 60median返回数字数组的中间值。function median($numbers){ sort($numbers); $totalNumbers = count($numbers); $mid = floor($totalNumbers / 2); return ($totalNumbers % 2) === 0 ? ($numbers[$mid - 1] + $numbers[$mid]) / 2 : $numbers[$mid];}Examplesmedian([1, 3, 3, 6, 7, 8, 9]); // 6median([1, 2, 3, 6, 7, 9]); // 4.5maxN从提供的数组中返回最大的数的个数。function maxN($numbers){ $maxValue = max($numbers); $maxValueArray = array_filter($numbers, function ($value) use ($maxValue) { return $maxValue === $value; }); return count($maxValueArray);}ExamplesmaxN([1, 2, 3, 4, 5, 5]); // 2maxN([1, 2, 3, 4, 5]); // 1minN从提供的数组中返回最小的数的个数。function minN($numbers){ $minValue = min($numbers); $minValueArray = array_filter($numbers, function ($value) use ($minValue) { return $minValue === $value; }); return count($minValueArray);}ExamplesminN([1, 1, 2, 3, 4, 5, 5]); // 2minN([1, 2, 3, 4, 5]); // 1approximatelyEqual(约等于)检查两个数字是否近似相等。使用abs()将两个值的绝对值与进行比较。省略第三个参数,以便使用默认值0.001。function approximatelyEqual($number1, $number2, $epsilon = 0.001){ return abs($number1 - $number2) < $epsilon;}ExamplesapproximatelyEqual(10.0, 10.00001); // trueapproximatelyEqual(10.0, 10.01); // falseclampNumber将num放在边界值a和b指定的包含范围内。如果num在该范围内,则返回num。否则,返回该范围内最近的数字。function clampNumber($num, $a, $b){ return max(min($num, max($a, $b)), min($a, $b));}ExamplesclampNumber(2, 3, 5); // 3clampNumber(1, -1, -5); // -1相关文章:30秒的PHP代码片段(1)数组 - Array ...

February 18, 2019 · 2 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

12亿行代码,阿里巴巴这一年的技术报告和梦想报告

78年前,图灵用代码编译出的情报破解系统,让二战至少提前2年结束,挽救了2000万人的生命;50年前,登月科学家敲下的一行关键代码,启动了阿波罗号的着陆,成就了人类的一大步;30年前,蒂姆·伯纳斯·李利用代码创造了万维网,让普通人也能够通过互联网连接全世界……如同数字世界的艺术家、数字文明的建筑师,各个时代的工程师科学家们正在用一行行代码改变世界。阿里巴巴是这个时代的技术追梦人。2019年1月9日,阿里巴巴公布了其2018年度代码报告。报告显示,阿里工程师在2018年共写下了12亿行代码,总代码长度可绕地球4.49圈。代码是IT行业的根基和基础。人们熟悉的Windows操作系统,是有史以来最复杂的软件之一,其总代码数大约为5000万行。这意味着,阿里工程师一年写下的代码总数相当于24个Windows的开发量。在代码语言规范上的努力和对语言美感的追求是衡量一个科技公司对行业贡献的重要标准。通过两年多的努力,阿里巴巴已经在内部实现了代码规范的“书同文”,对外推出了《阿里巴巴Java开发规约》。杭州成了全球Java规范的策源地。阿里基于开发规约推出的编码插件在全球范围内被下载了110万次,帮助数千家企业解决了1亿多个代码的不规范问题。共同分享共同进步的开源精神是技术人和开发者的精神底色,阿里技术人坚持拥抱开源、回报开源。目前阿里巴巴已经有400多个开源项目,涉及中间件、框架、组件、数据库、存储等,包括滴滴、网易、Netflix、Uber在内的互联网公司都是阿里开源项目的使用者。有3600多位阿里工程师们成为了开源项目的贡献者,他们过去在开源社区里共获得了30多万个星星,在GitHub贡献排行榜上,阿里是唯一一家入围顶尖贡献名单的中国公司。因为阿里工程师的贡献,阿里巴巴在2018年还获邀加入Java全球管理组织Java Community Process (JCP)的最高执行委员会,这也是中国企业首次加入到Java全球标准的制定中,推动更多“中国标准”成为全球规范。12亿行代码背后是阿里工程师和科学家们的技术梦想和家国情怀。键盘间行云流水的代码最终变成了推动科技突破与社会发展的密码,是多个前沿科技领域科研水平的提速,是城市管理模式的日趋精细化,是中国制造业的整体转型升级,是社会民生难题的切实解决方案。2018年5月,阿里巴巴达摩院量子实验室的科学家利研发出当前世界最强的量子电路模拟器“太章”,率先成功模拟了81比特40层作为基准的谷歌随机量子电路。《连线》杂志认为,这一研究突破意味着,谷歌依靠72比特量子计算机问鼎量子霸权的计划或被推翻。(“太章”拟基于该模拟器模拟的随机量子电路规模(黑线)与当前硬件可以实现的规模(红线)比较)阿里工程师还联合天文学家们开启了向宇宙深处的探索。他们与耶鲁大学合作,对39.13光年外的一个恒星系统进行研究,那里或将发现适宜生命居住的“第二地球”。他们还开发了一个适用于分析卫星遥感数据的AI,每天能够完成对北京郊区近150万亩的耕地状况的实时分析,从中找出破坏农田的违法行为,成功守护了百万亩农田。2018年,阿里工程师们给海内外的20多座城市装上了大脑。在浙江杭州,城市大脑覆盖全城420平方公里,降低了3.5%城市交通拥堵,让杭州脱离堵城行列。同时,城市大脑的能力从交通领域延展至包括在消防、城建、环境在内的城市精细化管理。在人类最关心的生命健康问题上,阿里巴巴的工程师们开发的医疗AI已可准确地测量肝结节,对判断肝结节是否为恶性和临床医疗有促进作用。2018年,问题疫苗事件牵动无数国人,阿里健康的工程师,连夜开发了一个“疫苗查询”功能,用技术让国人追踪疫苗来源,获得社会各界赞扬。过去的一年,阿里巴巴的工程师们不仅在办公室里写代码,他们还深入到工厂车间,和工人师傅面对面交流。通过云计算、IoT、AI,阿里巴巴正在驱动中国制造业数字化转型,为世界工厂带来了一个个珍贵的“1%良品率”提升和一个个数字化转型成功案例。本文作者:阿里云头条阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 9, 2019 · 1 min · jiezi