代码注释的艺术,优秀代码真的不需要注释吗?

前言

前天回家路上,有辆车强行插到前面的空位,司机大哥吐槽“加塞最可恶了”,我问“还有更可恶的吗”,司机大哥淡定说道“不让自己加塞的”。似乎和我们很类似,我们程序员届也有这2件相辅相成的事:最讨厌别人不写注释,更讨厌让自己写注释。 一段糟糕的代码,往往大家最低的预期是把注释写清楚,最合理的做法通常应该对代码做优化。如果我们将代码真正做到了优秀,我们是否还需要注释?

注释的意义

; **************************************************************************
; * RAMinit Release 2.0 *
; * Copyright (c) 1989-1994 by Yellow Rose Software Co. *
; * Written by Mr. Leijun *
; * Press HotKey to remove all TSR program after this program *
; **************************************************************************
; Removed Softwares by RI:
; SPDOS v6.0F, WPS v3.0F
; Game Busters III, IV
; NETX ( Novell 3.11 )
; PC-CACHE
; Norton Cache
; Microsoft SmartDrv
; SideKick 1.56A
; MOUSE Driver
; Crazy (Monochrome simulate CGA program)
; RAMBIOS v2.0
; 386MAX Version 6.01

注释是对代码的解释和说明,本质目的是为了增强程序的可读性与可解释性。注释会随着源代码,在进入预处理器或编译器处理后会被移除。这是雷布斯1994年写的一段MASM汇编代码,注释与代码整体结构都非常清晰。如果说代码是为了让机器读懂我们的指令,那注释完全就是为了让我们了解我们自己到底发出了哪些指令。

争议与分歧

注释的起源非常早,我们甚至已经查阅不到注释的由来,但现在任何一种语言,甚至几乎任何一种文本格式都支持各式各样的注释形式。 但如何使用注释,其实一直是一个备受争论的话题。当我们接手一段‘祖传代码’时,没有注释的感觉简直让人抓狂,我们总是希望别人能提供更多的注释。但软件届也有一段神话传说,叫做『我的代码像诗一样优雅』。有注释的代码都存在着一些瑕疵,认为足够完美的代码是不需要注释的。

坏代码的救命稻草

The proper use of comments is to compensate for our failure to express ourself in code. -- Robert C. Martin 《Clean Code》 译:注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败

Clean Code 的作者Robert C. Martin可以说是注释的极力否定者了,他认为注释是一种失败,当我们无法找到不用注释就能表达自我的方法时,才会使用注释,任何一次注释的使用,我们都应该意识到是自己表达能力上的失败。 PH&V的系统架构师和负责人Peter Vogel,同样也是一名坚定的注释否定着,他发表了一篇文章 why commenting code is still bad 来表述为代码添加注释在某种程度上可能是必要的,但确实没有价值。 事实上,我们也确实经历着非常多无价值的注释,以及完全应由代码来承担解释工作的“职能错位”的注释。

零注释

糟糕的代码加上完全不存在的注释,我喜欢称呼它们为『我和上帝之间的秘密』,当然过2个月后也可以称之为『上帝一个人的秘密』。 压垮程序员最后一根稻草的,往往都是零注释。可以没有文档,可以没有设计,但如果没有注释,我们每一次阅读都是灾难性的。当我们抱怨它一行注释都没有时,其实我们是在抱怨我们很难理解代码想要表达的含义,注释是直接原因,但根本原因是代码。 零注释往往和坏代码一起生活,“没有注释”的吐槽,其实本质上直击的是那堆歪七扭八的英文字母,到底它们想表达什么!

无用注释

/*** returns the last day of the month* @return the last day of the month*/
public Date getLastDayOfMonth(Date date) {Calendar calendar = new GregorianCalendar();calendar.setTime(date);calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));return calendar.getTime();
}

这是典型的废话注释,读代码时代码本身就能很好的表达具体的含义,我们完全不需要看注释,并且注释也不会给我们提供更多有效的信息。无用注释或许是零注释的另一个极端,我们担心自己写的代码被人所吐槽,于是尽可能去补全注释,当你为 getLastDayOfMonth() 补一段 get last day of month 的注释时,恭喜你,你得到了双倍的代码。

代码优于注释

"Comments Do Not Make Up for Bad Code" -- Robert C.Martin 《Clean Code》 译:注释不能美化糟糕的代码

当需要为一段代码加上注释时,说明代码已经不能很好的表达意图,于是大家开始为这段代码添加注释。Robert C.Martin在 Clean Code 中提出一个观点:注释不能美化糟糕的代码。能用代码表达的直接用代码表达,不能用代码表达的,你再想想,如何能用代码表达。 复杂的代码最直接的表现就是不够直观、难以理解,加上注释后往往会清晰很多,但你是愿意看这段代码

// 判断是否活跃用户
if((customer.getLastLoginTime().after(dateUtils.minusDays(new Date(),15)) && customer.getCommentsLast30Days() > 5) || orderService.countRecentDaysByCustomer(customer,30) > 1)

还是这段代码?

if(customer.isActive())

糟糕代码的存在,通常是我们写注释的常见动机之一。这种试图粉饰可读性差的代码的注释称之为『拐杖式注释』,即使大名鼎鼎的JDK,也存在这样的拐杖式注释。

public synchronized void setFormatter(Formatter newFormatter) {checkPermission();// Check for a null pointernewFormatter.getClass();formatter = newFormatter;
}

这是取自JDK java.util.logging.Handler类的setFormatter方法,作者为了不让空指针异常下传,提前做一次空指针检查。没有这段注释我们完全不知道游离的这句 newFormatter.getClass() 到底要做什么,这段注释也充分表达了作者自己也知道这句代码难以理解,所以他加上了注释进行说明。但我们完全可以用 Objects.requireNonNull() 来进行替代。同样的代码作用,但可读性可理解性大不一样,JDK里的这段代码,确实让人遗憾。

注释否定论

"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》 译:若编程语言足够有表达力,或者我们长于用这些语言来表达意图,就不那么需要注释--也许根本不需要

通过代码进行阐述,是注释否定论的核心思想。当你花功夫来想如何写注释,让这段代码更好的表达含义时,我们更应该重构它,通过代码来解释我们的意图。每一次注释的编写,都是对我们代码表达能力上的差评,提升我们的归纳、表达、解释能力,更优于通过注释来解决问题。当代码足够优秀时,注释则是非必须的。并且需求在不断调整,代码一定会随之变动,但注释可能慢慢被人遗忘,当代码与注释不匹配时,将是更大的灾难。

软件设计的乌托邦

曾经我的确对优秀的代码不断钻研,对代码本身所蕴含的能量无比坚信。如同当科学代替鬼神论走上历史舞台时,即使存在有科学解释不了,我们依然坚信只是科学还需要发展。当代码别人无法理解时,我会认为是我表述不够精准,抽象不够合理,然后去重构去完善。 有一次给老板review代码,当时老板提出,“你的代码缺缺少注释”,我说不需要注释,代码就能自解释。于是老板现场读了一段代码,“query-customer-list 查询客户”、“
transfer-customer-to-sales 分发客户到销售”、“check-sales-capacity 检查销售库容”,每一个类每一个函数,一个单词一个单词往外蹦时,你会发现好像确实都能读懂,于是老板回了一个“好吧”。

美丽的乌托邦

"'good code is self-documenting' is a delicious myth" -- John Ousterhout《A Philosophy of Software Design》 译:‘好的代码自解释’是一个美丽的谎言

在软件设计中,总有一些软件工程师所坚信的诗和远方,有的是大洋彼岸的美好国度,有的或许是虚无缥缈的理想乌托邦。John Ousterhout教授在 A Philosophy of Software Design 中提到一个观念,‘好的代码自解释’是一个美丽的谎言。 我们可以通过选择更好的变量名,更准确的类与方法,更合理的继承与派生来减少注释,但尽快如此,我们还是有非常多的信息无法直接通过代码来表达。这里的信息,或许不单单只是业务逻辑与技术设计,可能还包括了我们的观感,我们的体验,我们的接纳程度以及第一印象带来的首因效应。

好代码的最佳僚机

You might think the purpose of commenting is to 'explain what the code does', but that is just a small part of it.The purpose of commenting is to help the reader know as much as the writer did. 译:你可能以为注释的目的是“解释代码做了什么”,但这只是其中很小一部分,注释的目的是尽量帮助读者了解得和作者一样多 -- Dustin Boswell《The Art of Readable Code》

如同John Ousterhout教授一样,The Art of Readable Code 的作者Dustin Boswell,也是一个坚定的注释支持者。与Robert C.Martin类似,Dustin Boswell同样认为我们不应该为那些从代码本身就能快速推断的事实写注释,并且他也反对拐杖式注释,注释不能美化代码。 但Dustin Boswell认为注释的目的不仅解释了代码在做什么,甚至这只是一小部分,注释最重要的目的是帮助读者了解得和作者一样多 。编写注释时,我们需要站在读者的角度,去想想他们知道什么,这是注释的核心。这里有非常多的空间是代码很难阐述或无法阐述的,配上注释的代码并非就是糟糕的代码,相反有些时候,注释还是好代码最棒的僚机。

更精准表述

There are only two hard things in Computer Science: cache invalidation and naming things. -- Phil Karlton 译:计算机科学中只有两个难题:缓存失效和命名

Martin Fowler在他的 TwoHardThings 文章中引用了Phil Karlton的一段话,命名一直都是一件非常难的事情,因为我们需要将所有含义浓缩到几个单词中表达。很早之前学Java,接触到很长的类名是
ClassPathXmlApplicationContext。可能有人认为只要能将含义准确地表达出来,名字长一些无所谓。那如果我们需要有一段处理有关“一带一路”的内容,那我们的代码可能是这样的

public class TheSilkRoadEconomicBeltAndThe21stCenturyMaritimeSilkRoad {}

他非常准确的表达了含义,但很明显这不是我们期望的代码。但如果我们辅以简单的注释,代码会非常清晰,说明了简称,也说明了全意,表述更精准。

/*** 一带一路* 丝绸之路经济带和21世纪海上丝绸之路*/
public class OneBeltOneRoad {}

代码层次切割

函数抽取是我们经常使用且成本最低的重构方法之一,但并非银弹。函数并非抽得越细越好,如同分布式系统中,并非无限的堆机器让每台机器处理的数据越少,整体就会越快。过深的嵌套封装,会加大我们的代码阅读成本,有时我们只需要有一定的层次与结构帮助我们理解就够了,盲目的抽取封装是无意义的。

/*** 客户列表查询*/
public List queryCustomerList(){// 查询参数准备UserInfo userInfo = context.getLoginContext().getUserInfo();if(userInfo == null || StringUtils.isBlank(userInfo.getUserId())){return Collections.emptyList();}LoginDTO loginDTO = userInfoConvertor.convertUserInfo2LoginDTO(userInfo);// 查询客户信息List<CustomerSearchVO> customerSearchList = customerRemoteQueryService.query(loginDTO);Iterable<CustomerSearchVO> it = customerSearchList.iterator();// 排除不合规客户while(it.hasNext()){CustomerSearchVO customerSearchVO = it.next(); if(isInBlackList(customerSearchVO) || isLowQuality(customerSearchVO)){it.remove();}}// 补充客户其他属性信息batchFillCustomerPositionInfo(customerSearchList);batchFillCustomerAddressInfo(customerSearchList);
}

其实细看每一处代码,都很容易让人理解。但如果是一版没有注释的代码,可能我们会有点头疼。缺少结构缺少分层,是让我们大脑第一感观觉得它很复杂,需要一次性消化多个内容。通过注释将代码层次进行切割,是一次抽象层次的划分。同时也不建议大家不断去抽象私有方法,这样代码会变得非常割裂,并且上下文的背景逻辑、参数的传递等等,都会带来额外的麻烦。

母语的力量

其实上述例子,我们更易阅读,还有一个重要的原因,那就是母语的力量。我们天然所经历的环境与我们每天所接触到的事物,让我们对中文与英文有完全不一样的感受。我们代码的编写本质上是一个将我们沟通中的“中文问题”,翻译成“英文代码”来实现的过程。而阅读代码的人在做得,是一件将“英文代码”翻译成“中文表述”的事情。而这之中经过的环节越多,意思变味越严重。

TaskDispatch taskDispatch = TaskDispatchBuilder.newBuilder().withExceptionIgnore().build();
taskDispatch// 外贸信息.join(new FillForeignTradeInfoTask(targetCustomer, sourceInfo))// 国民经济行业、电商平台、注册资本.join(new FillCustOutterInfoTask(targetCustomer, sourceInfo))// 客户信息.join(new FillCustomerOriginAndCategoryTask(targetCustomer, sourceInfo))// 客户扩展信息.join(new FillCustExtInfoTask(targetCustomer, sourceInfo))// 收藏屏蔽信息.join(new FillCollectStatusInfoTask(targetCustomer, sourceInfo, loginDTO()))// 详情页跳转需要的标签信息.join(new FillTagInstanceTask(targetCustomer, sourceInfo, loginDTO()))// 客户信息完整度分数.join(new FillCustomerScoreTask(targetCustomer, sourceInfo))// 潜客分层完整度.join(new FillCustomerSegmentationTask(targetCustomer, sourceInfo))// 填充操作信息.join(new FillOperationStatusTask(targetCustomer, sourceInfo, loginDTO))// 认证状态.join(new FillAvStatusTask(targetCustomer, loginDTO))// 客户地址和组织.join(new FillCompanyAddressTask(targetCustomer, loginDTO))// 违规信息.join(new FillPunishInfoTask(targetCustomer, sourceInfo))// 填充客户黑名单信息.join(new FillCustomerBlackStatusTask(targetCustomer, sourceInfo))// 填充客户意愿度.join(new FillCustIntentionLevelTask(targetCustomer, sourceInfo));// 执行.execute();

这是一段补齐客户全数据信息的代码,虽然每一个英文我们都看得懂,但我们永远只会第一眼去看注释,就因为它是中文。并且也因为有这些注释,这里非常复杂的业务逻辑,我们同样可以非常清晰的了解到它做了哪些,分哪几步,如果要优化应该如何处理。这里也建议大家写中文注释,注释是一种说明,越直观越好。

注释的真正归属

复杂的业务逻辑

// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (args != null) {// Delegation to parent with explicit args.return parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}
}

这是Spring中的一段获取bean的代码,spring作为容器管理,获取bean的逻辑也非常复杂。对于复杂的业务场景,配上必要的注释说明,可以更好的理解相应的业务场景与实现逻辑。 截取自:
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

晦涩的算法公式

/*** Returns the value obtained by reversing the order of the bits in the* two's complement binary representation of the specified {@code long}* value.*/
public static long reverse(long i) {// HD, Figure 7-1i = (i & 0x5555555555555555L) << 1 | (i >>> 1) & 0x5555555555555555L;i = (i & 0x3333333333333333L) << 2 | (i >>> 2) & 0x3333333333333333L;i = (i & 0x0f0f0f0f0f0f0f0fL) << 4 | (i >>> 4) & 0x0f0f0f0f0f0f0f0fL;i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;i = (i << 48) | ((i & 0xffff0000L) << 16) |((i >>> 16) & 0xffff0000L) | (i >>> 48);return i;
}

这是JDK中Long类中的一个方法,为reverse方法添加了足够多的注释。对于几乎没有改动且使用频繁的底层代码,性能的优先级会高于可读性。在保证高效的同时,注释帮助我们弥补了可读性的短板。 截取自java.lang.Long#reverse

不明所以的常量

/*** The bin count threshold for using a tree rather than list for a* bin.  Bins are converted to trees when adding an element to a* bin with at least this many nodes. The value must be greater* than 2 and should be at least 8 to mesh with assumptions in* tree removal about conversion back to plain bins upon* shrinkage.*/
static final int TREEIFY_THRESHOLD = 8;

这是JDK中HashMap的一个常量因子,记录由链表转向红黑树的链表长度阈值,超过该长度则链表转为红黑树。这里记录了一个8,不仅记录了该常量的用途,也记录了为什么我们定义这个值。经常我们会发现我们代码中存在一个常量等于3、等于4,有时我们不知道这些3和4是干什么的,有时我们不知道为什么是3和4。 截取自java.util.HashMap#TREEIFY_THRESHOLD

意料之外的行为

for (int i = 0; i < 3; i++) {// if task running, invoke only check result ready or notResult result = bigDataQueryService.queryBySQL(sql, token);if (SUCCESS.equals(result.getStatus())) {return result.getValue();}Thread.sleep(5000);
}

代码及注释所示为每5秒check一下是否有结果返回,远程服务将触发与获取放在了一个接口。没有注释我们可能认为这段代码有问题,代码表现的含义更像是每5秒调用一次,而非每5秒check一次。为意料之外的行为添加注释,可以减少对代码的误解读,并向读者说明必要的背景及逻辑信息。

接口对外API

/*** <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>* <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>* StringUtils.isBlank(null)      = true* StringUtils.isBlank("")        = true* StringUtils.isBlank(" ")       = true* StringUtils.isBlank("bob")     = false* StringUtils.isBlank("  bob  ") = false** @param cs  the CharSequence to check, may be null* @return {@code true} if the CharSequence is null, empty or whitespace only*/
public static boolean isBlank(final CharSequence cs) {final int strLen = length(cs);if (strLen == 0) {return true;}for (int i = 0; i < strLen; i++) {if (!Character.isWhitespace(cs.charAt(i))) {return false;}}return true;
}

我们经常使用的StringUtils工具类中的isBlank方法,写了非常详情的注释,不仅包括方法的逻辑,入参的含义,甚至还包括具体示例。我们平常定义的二方库中的HSF、HTTP接口定义,同样需要有清晰详尽的注释,这里的注释甚至经常会多过你的代码。 截取自
org.apache.commons.lang3.StringUtils#isBlank

法律文件信息

/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/

与法律相关的注释,在开源软件库中较经常遇到。涉及到一些版权及著作声明时,我们需要在源文件顶部放置法律相关注释。当然,我们不需要将所有法律信息写到注释中,如例子中的跳链,引用一份标准的外部文档,会是一个更好的选择。

写在最后

注释并不会妨碍你写出优雅简洁的代码,它只是程序固有的一部分而已。我们不用过分在意我们的代码是否可以脱离注释,也不需要强调因为我们的代码符合什么原则,满足什么约定,所以代码是优秀的注释是冗余的。代码是一门艺术,并不会因为满足三规九条它就一定完美,因为艺术,是不可衡量的。

参阅书籍

《A Philosophy of Software Design》:
https://www.amazon.com/-/zh/dp/173210221X/ref=sr_1_1 《Clean Code》:https://baike.baidu.com/item/代码整洁之道/9226259 《The Art of Readable Code》:https://github.com/niexiaolong/niexiaolong.github.io/blob/master/the-art-of-readable-code.pdf

作者 | 谦风

原文链接

本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/510739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DataProcess-VOC数据图像和标签一起进行Resize

VOC数据图像和标签一起进行Resize 参加检测比赛的时候&#xff0c;很多时候工业原始数据尺度都比较大&#xff0c;如果对数据不提前进行处理&#xff0c;会导致数据在加载进内存时花费大量的时间&#xff0c;所以在执行训练程序之前需要将图像提前进行预处理。对于目标检测的数…

元宇宙持续升温,金蝶推出数字员工破圈而来

作者 | 伍杏玲 “金小蝶&#xff0c;请分析今年企业销售事业部的业绩”。 话音刚落&#xff0c;大屏幕展开一张张账务报表&#xff0c;一位身着西装&#xff0c;举止大方得体的数字人条理清晰地回复&#xff1a;“截至今年10月&#xff0c;企业销售事业部在签单金额、新签收入…

阿里云易立:云原生如何破解企业降本提效难题?

2020年以来&#xff0c;新冠疫情改变了全球经济的运行与人们的生活。数字化的生产与生活方式成为后疫情时代的新常态。今天&#xff0c;云计算已经成为全社会的数字经济基础设施&#xff0c;而云原生技术正在深刻地改变企业上云和用云的方式。如何利用云原生技术帮助企业实现降…

Alibaba/IOC-golang 正式开源 ——打造服务于go开发者的IOC框架

IOC&#xff08;inversion of control&#xff09;即控制反转&#xff0c;是面向对象编程中的一种设计原则&#xff0c;可以用来减低计算机代码之间的耦合度。IOC-golang 是一款服务于Go语言开发者的依赖注入框架&#xff0c;基于控制反转思路&#xff0c;方便开发人员搭建任何…

开启安全测试评估赛道,永信至诚发布“数字风洞”产品体系

11月19日&#xff0c;永信至诚产品战略发布会上&#xff0c;面向安全测试评估领域的“数字风洞”产品体系战略发布&#xff0c;标志着永信至诚作为网络靶场和人才建设领军企业&#xff0c;再次以“产品乘服务”的价值体系&#xff0c;开启网络安全测试评估专业赛道。 数字化时代…

云上弹性高性能计算,支持生命科学产业高速发展、降本增效

随着云计算技术服务及实践的日趋成熟&#xff0c;越来越多的行业通过上云实现了整个产业的转型升级&#xff0c;正处于黄金时期的生命科学行业也不例外。 作为拥有高数据量和高计算量的行业&#xff0c;生命科学的研究也早已离不开高性能计算&#xff08;High Performance Comp…

为什么生命科学企业都在陆续上云?

生命科学行业正迎来发展的黄金时期。医学的发展和人们对健康的追求&#xff0c;正快速转换为生命科学整个产业链发展的新动能&#xff0c;高性能计算HPC在生命科学研究中扮演着十分重要的角色。同时&#xff0c;随着生命科学行业的快速发展&#xff0c;我们可以看到&#xff0c…

VMware Explore 2022 China,赋能中国企业加速实现云智能

全球领先的企业软件创新者VMware&#xff08;NYSE: VMW&#xff09;的年度技术盛会—— VMware Explore 2022 China于11月8日正式举行。本届大会以“探索多云宇宙”为主题&#xff0c;汇聚云计算领域的顶尖技术专家和创新者&#xff0c;通过150多场解决方案演讲、围绕云基础架构…

政企混合云技术架构的演进和发展

云计算经历十几年的发展&#xff0c;从被认为是“新瓶装旧洒”受到很多怀疑&#xff0c;到在消费互联网领域得到广泛应用&#xff0c;再到传统政企客户普遍认同&#xff0c;并在政务互联网业务领域快速推广&#xff0c;当下已进入到全面替换政企客户传统IT基础架构的攻坚阶段。…

多云管理产品组合VMware Aria,开启多云管理新篇章

今年8月份&#xff0c;VMware Explore美国大会上宣布了多云管理产品组合VMware Aria&#xff0c;宣布之后&#xff0c;市场上关注度非常高&#xff0c;而且受到了热捧。Aria这个名字动听且贴切&#xff0c;中文意思是 “咏叹调”&#xff0c;也就是说要用统一的、一致的曲调来歌…

DataWorks开发ODPS SQL开发生产环境自动补全ProjectName

一、场景描述 DataWorks标准模式下&#xff0c;支持开发环境和生产环境隔离&#xff0c;开发环境和生产环境的数据库表命名有所区别&#xff0c;如果需要在开发环境访问生产环境的数据库表或者跨项目空间A访问项目空间B的表&#xff0c;需要根据以下命名规范严格区分数据库表名…

送外卖也要“黑科技”?阿里移动感知技术应用揭秘

一 背景 作为本地生活的一个重要组成部分&#xff0c;外卖已经进入千千万万的家庭。相信很多小伙伴已经注意到&#xff0c;饿了么的每一个订单&#xff0c;我们都会及时向用户通知这一单现在所处的状态&#xff0c;比如“商户接单”&#xff0c;“骑手到店”&#xff0c;“骑手…

视频需求超平常数 10 倍,却节省了 60% 的 IT 成本投入是一种什么样的体验?

近年来&#xff0c;Serverless 一直在高速发展&#xff0c;并呈现出越来越大的影响力。主流的云服务商也在不断地丰富云产品体系&#xff0c;提供更好的开发工具&#xff0c;更高效的应用交付流水线&#xff0c;更好的可观测性&#xff0c;更细腻的产品间集成&#xff0c;但一切…

打好“三场仗”,数据库新晋厂商石原子胜券在握

纵观数字经济时代&#xff0c;数据规模呈爆发式增长&#xff0c;国产化替代加速发展。据中国信通院《数据库发展研究报告(2021年)》预测&#xff0c;预计到2025年&#xff0c;全球数据库市场规模将达到798亿美元&#xff0c;其中&#xff0c;中国数据库市场总规模将达到688亿元…

基于信通院 Serverless 工具链模型的实践:Serverless Devs

前言 2022 年 6 月 15 日&#xff0c;信通院在中国信通院云原生产业大会上发布《基于无服务器架构的工具链能力要求》标准&#xff0c;至此全球首个云原生 Serverless 开放工具链模型正式发布&#xff01;Serverless Devs [1]作为开源开放的开发者工具积极参与工具链模型建设&…

Serverless 架构落地实践及案例解析

互联网软件架构演进 我们先简单回顾下互联网软件架构的演进之路。 单机部署 在单机部署中&#xff0c;将所有的业务和数据库都部署在一台主机中。 此架构的优点是&#xff1a;开发、部署以及运维都非常简单。缺点是&#xff1a;一旦遇到流量过大或者机器故障&#xff0c;整个…

十年 Python 程序员,初次尝试 Rust:“非常优秀!”

摘要&#xff1a;Python 和 Rust&#xff0c;都是近几年深受开发者喜爱的编程语言&#xff0c;那么作为一个拥有十年 Python 编程经验的开发者来说&#xff0c;初次尝试 Rust 会有怎样的感受呢&#xff1f;链接&#xff1a;https://karimjedda.com/carefully-exploring-rust/声…

让阿根廷队“告吹”的三个球背后,2022 年世界杯暗藏哪些技术玄机?

整理 | 苏宓出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;「足球反着买&#xff0c;别墅靠大海」&#xff0c;昨晚 2022 年卡塔尔世界杯的一场小组赛上&#xff0c;最有看头的阿根廷球队出现惊天冷门&#xff0c;以 1:2 败北沙特阿拉伯队&#xff0c;为此&#x…

科学地花钱:基于端智能的在线红包分配方案

一、前言 本文是作者在1688进行新人红包发放的技术方案总结&#xff0c;基于该技术方案的论文《Spending Money Wisely: Online Electronic Coupon Allocation based on Real-Time User Intent Detection》已经被CIKM2020接收&#xff0c;欢迎交流指正&#xff01; 关于作者 …

为 Serverless Devs 插上 Terraform 的翅膀,实现企业级多环境部署(上)

前言 随着现代化应用的普及和企业上云的深入&#xff0c;项目中会涉及越来越多的云资源使用。企业上云过程中&#xff0c;往往会有平台&#xff08;Platform&#xff09;团队和基础设施&#xff08;Infra&#xff09;团队&#xff1a;平台团队关注业务&#xff0c;根据业务场景…