compat包

为什么向后兼容很重要 (Why backwards compatibility matters)

(If you're already convinced that API stability is a crucial concern, not the whim of a few conservative mummies, save yourself some time and rush to the following chapter.)

(如果您已经确信API的稳定性是至关重要的问题,而不是一些保守的木乃伊的一时兴起,请节省一些时间,并急于转至下一章。)

"WE DO NOT BREAK USERSPACE!"

“我们不会破坏用户空间!”

This famous rant of Linus Torvalds is, alas, more relevant than ever.

可惜的是, 莱纳斯·托瓦尔兹 ( Linus Torvalds )的这只名叫比以往任何时候都更重要。

If a change results in user programs breaking, it's a bug in the kernel. We never EVER blame the user programs. How hard can this be to understand?

如果更改导致用户程序中断,那就是内核中的错误。 我们永远不会责怪用户程序。 这有多难理解?

If applications didn't care about specific error values, then it wouldn't make sense to have more than one to begin with, and you shouldn't care which one that was. But since applications do care, and since we do have multiple error values, we stick to the old ones, unless there are some very good reasons not to. And those reasons really need to be very good, and spelled out and explained.

如果应用程序不关心特定的错误值,那么一开始就不应该涉及多个错误,也不必理会是哪个。 但是由于应用程序确实在意,并且因为我们确实有多个错误值,所以我们坚持使用旧的错误值,除非有非常好的理由不这样做。 这些原因确实需要很好地阐述,并加以说明。

Let's replace "kernel" by any framework/library, and "error value" by "API signature", and we get an invaluable commandment of good programming. We can live quite well with a few buglets and imperfect features, but when our applications deliver segfaults or lengthy tracebacks after a simple version upgrade, there is a problem. A real problem.

让我们用任何框架/库替换“内核”,并用“ API签名”替换“错误值”,这样我们就获得了良好编程的宝贵命令。 我们可以通过一些buglet和不完善的功能来过得很好,但是当我们的应用程序在简单的版本升级后出现段错误或冗长的追溯时,就会出现问题。 一个真正的问题。

And there is a paradox here. Regarding OS distributions, drivers, libc/gtk/Qt and other low-level, statically typed libraries, we expect - and are happy to experience - painless updates, bringing only new features and bugfixes. Whereas for our high-level web frameworks, mostly coded in dynamic languages, we have become resigned to the fact that each update could become a 3-days labor of understanding breakages, finding compatible versions of dependencies, and forking or monkey-patching until test suites are green again. Logically, shouldn't it be the other way round ? Why are most 1995 win32 freewares still working, why was the x32/x64 migration so transparent for most users, if a pluggable server app released 2 years ago is broken on multiple aspects?

这里有一个悖论。 关于操作系统发行版,驱动程序,libc / gtk / Qt和其他低级静态类型的库,我们期望并且很高兴体验到无痛苦的更新,仅带来新功能和错误修正。 而对于我们的高级Web框架(主要是用动态语言编码)而言,我们已经开始接受这样一个事实,即每次更新可能需要3天的时间来了解破损,查找兼容版本的依赖项以及进行分叉或猴子补丁直到测试套房再次变成绿色。 从逻辑上讲,不是应该反过来吗? 如果2年前发布的可插拔服务器应用程序在多个方面都有问题,为什么大多数1995年的win32免费软件仍然可以使用,为什么x32 / x64迁移对大多数用户如此透明?

I'll tell you why.

我告诉你为什么。

API stability was once a very praised commitment. Semantic versioning was a must-have. Projects like Qt proudly detailed the measures they took to ensure their C/C++ would evolve without breakage. Some even filled their function parameters with NULL values "reserved for future uses". And incompatible changes were only evocated when no solution could be found.

API稳定性曾经是一个广受赞誉的承诺。 语义版本控制是必须具备的。 像Qt这样的项目自豪地详细说明了他们为确保C / C ++不断发展而采取的措施。 有些甚至用“保留供将来使用”的NULL值填充其功能参数。 仅当找不到解决方案时,才引发不兼容的更改。

Luckily, this mindset is still valid in large areas of programming. But now a different philosophy has contaminated minds, especially in the web industry. This spartan way of thinking could be called "Walk or die", "No paradise for the weak", or "As long as I warn, I can shoot the bullet". Sometimes hiding behind cute concepts like "calendar versioning", or "evergreen applications", this way of thinking is actually crystal-clear: the most minor software upgrade may introduce breaking changes - documented or not, proudly assumed or not -  just deal with it.

幸运的是,这种思维方式在大范围编程中仍然有效。 但是现在,一种不同的哲学已经污染了人们的思想,尤其是在网络行业。 这种斯巴达式的思维方式可以被称为“走不走,死不了”,“弱者没有天堂”或“只要我警告,我就能发子弹”。 有时隐藏在诸如“日历版本控制”或“常青应用程序”之类的可爱概念之后,这种思维方式实际上是非常清晰的:最次要的软件升级可能会带来重大更改-无论是否记录在案,还是引以为傲的假设-应对之。

Why? Why not just let aliases, adapters, and other compatibility shims, when moving modules around, when renaming objects, when changing function signatures? With the dynamic and introspective nature of most modern languages,  isn't that a breeze? Sometimes development resources are so scarce that it's already too much. But the rest of the time? My guess is that when it is not a problem of technical skill, or of laziness, it might be a cultural issue.

为什么? 为什么在移动模块,重命名对象,更改功能签名时不只是让别名,适配器和其他兼容性垫片起作用? 凭借大多数现代语言的动态和内省性,这不是一件轻而易举的事吗? 有时开发资源非常稀缺,以至于已经太多了。 但是剩下的时间呢? 我的猜测是,当这不是技术技能或懒惰问题时,可能是文化问题。

Do you know this dopamine hit you get when you tick a box in a checklist, especially the last one? This satisfaction that sometimes makes you write an already completed task just so you can tick it? You might get the same thrill when you brutally refactor code to a cleaner architecture, or erase compatibility shims "as per deprecation policy". It's the happiness rush of the duty well done, of the return to purity.

您是否知道当您勾选清单中的一个方框时,会产生多巴胺的打击,尤其是最后一个方框吗? 这种满足感有时会使您编写一个已经完成的任务, 只是您可以勾选它 ? 当您残酷地将代码重构为更干净的体系结构,或者按照“弃用策略 ”擦除兼容性垫片时,您可能会感到同样的兴奋。 这是完成职责,恢复纯洁所带来的幸福感。

But this precise feeling is a huge lie. A blinding self-absorption. A harmful psychological bias.

但是这种精确的感觉是一个巨大的谎言。 令人目眩的自我吸收。 有害的心理偏见。

Compatibility shims are not technical debt; nor a set of warts. At the very contrary, they are invaluable assets. With these few chunks of source code, our software extends its compatibility to tens, hundreds, thousands of miscellaneous libraries and applications spread across the web, in both public and private repositories, ranging from tiny utilities to huge corporate applications. These foreign codebases, full of business logic, of money-bringing features, of highly specific code, are what make their foundations worth existing.

兼容性垫片不是技术债务。 也不是疣。 相反,它们是宝贵的资产。 借助这些少量的源代码,我们的软件将其兼容性扩展到了遍及Web的数十万,数以千计的各种库和应用程序,无论是公用存储库还是私有存储库,范围从小型实用程序到大型企业应用程序。 这些充满业务逻辑,赚钱功能,高度特定代码的外来代码库使它们的基础值得保留。

But this ecosystem is of an extraordinary diversity. Some repositories get commits every day from multiple contributors, some get a mass update once in a while when their maintainers get a little spare time, and some have not been touched for years (because their creator lost interest, or just couldn't find anything to improve). Some have Tox-like multi-version testing and continuous integration, some don't even have a single unit-test.

但是,这个生态系统具有非同寻常的多样性。 一些存储库每天都会收到来自多个贡献者的提交,一些存储库有时会在维护者有空余时间的情况下偶尔进行一次大规模更新,而有些存储库已经多年没有被使用过(因为其创建者失去了兴趣,或者只是找不到任何东西)改善)。 有些具有类似Tox的多版本测试和持续集成,有些甚至没有单一的单元测试。

So what happens when developers follow this trendy "Walk or die" philosophy? The ecosystem, already heavily fragmented by language (python2vs3, ruby, go, php... just for dynamic languages), by file format and network protocol, by framework and execution style (sync vs async), gets fragmented even more. In the most silent and deadly way. Basically, if we consider the codebases depending on a framework or library (here called "the software"):

那么,当开发人员遵循这种时髦的“走不走”哲学时,会发生什么? 生态系统已经严重地被语言(python2vs3,ruby,go,php ...仅用于动态语言),文件格式和网络协议,框架和执行样式(同步与异步)所分割。 以最沉默和最致命的方式。 基本上,如果我们根据框架或库(此处称为“软件”)来考虑代码库,则:

  • Repositories that haven't been updated for a few years are broken by default.默认情况下,几年未更新的存储库会被破坏。
  • Repositories that are actively maintained, but do not target the same software version as us, do not work either.主动维护的存储库,但没有针对我们的相同软件版本,也不起作用。
  • Bug trackers get filled with useless "Plz add support for version X.Y.Z" or "Plz restore support for version X.Y.Z" tickets.错误跟踪器充满了无用的“ Plz添加对XYZ版本的支持”或“ Plz恢复对XYZ版本的支持”票证。
  • Forks flourish around mildly renowned repositories ; forks which can't be merged back, since each of their modifications are highly likely to break things for other software versions ; and the subsequent improvements brought by each forker, being chained to divergent codebases, keep spreading without ever being merged back ; naturally, they get remade by several developers each on his own, since few of them take the time to review the forks graph and cherry-pick interesting commits.在知名度较高的仓库周围遍布叉子; 不能合并的fork,因为它们的每个修改都很可能破坏其他软件版本的功能; 以及每个分叉者所带来的后续改进,被链接到不同的代码库,并且不断扩散而从未被合并回来; 自然,它们会由数名开发人员各自重制,因为很少有人花时间查看forks图和有趣的提交。
  • Biggest projects sometimes get nice enough to provide a compatibility matrix, or "known working sets" pinned down to their patch version number. But as soon as you have more than a few dependencies, you enter a dependency hell that no conflict resolution algorithm can tackle ; you just have to fork, fork, fork, and monkey-patch, until your dependencies find an agreement.大型项目有时会变得足够好以提供兼容性矩阵,或固定到其补丁版本号的“已知工作集”。 但是,一旦您拥有多个依赖关系,就会进入一个依赖冲突地狱,冲突解决算法无法解决; 您只需要进行fork,fork,fork和monkey-patch,直到您的依赖项找到协议即可。
  • Project requirements get filled with links to git repository and commit hashes; semantic-less data which will make the next upgrades still more awkwardly experimental; or which will disappear due to an unexpected "force-push".项目需求中包含指向git仓库和提交哈希的链接; 缺乏语义的数据将使下一步的升级更加尴尬。 或由于意外的“推力”而消失。
  • Without surprise, many maintainers of these pluggable apps don't want to take on them the additional burden of filling their code with special cases, to work around the breakage frenzy of the main software's developers. As a result, the dependency hell keeps expanding unrestrained.毫不奇怪,这些可插拔应用程序的许多维护者都不想承受用特殊情况填充代码的额外负担,以解决主要软件开发人员的崩溃狂潮。 结果,依赖地狱一直不受限制地扩展。

So when proudly pluralizing the name of a submodule, when removing a purportedly little-used utility class, when making an optional argument become mandatory, we're not improving anything. We're just murdering practicality for the sake of aesthetical purity. We're recklessly destroying entire regions of the software ecosystem, turning gazillions of test suites into reddish nightmares. But we'll never know to what extent; especially if we don't check. Ignorance is bliss.

因此,当自豪地将子模块的名称复数时,当删除一个据称很少使用的实用程序类时,当使一个可选参数成为必需时,我们就没有任何改善。 我们只是为了美观而谋求实用性。 我们不计后果地破坏了软件生态系统的整个区域,将成千上万的测试套件变成了微弱的噩梦。 但是我们永远不会知道到什么程度。 特别是如果我们不检查。 无知是幸福。

Biological ecosystems can reach down to the depth of the abyss or to other planets if they have plenty of time; when things change too quickly, it's mass extinction. Software ecosystems are no different. Enjoying the cleanliness of an API "remade from scratch" is like enjoying the microbial sterility of a forest vitrified by a nuclear blast.

如果有足够的时间,生物生态系统可以深入到深渊或其他星球。 当事情变化太快时,那就是灭绝。 软件生态系统没有什么不同。 享受“从零开始”重新制作的API的清洁度就像享受被核爆炸玻璃化的森林的微生物无菌性。

For sure, it's a falsehood to think that because we use some open-source software, we're entitled to getting the bugfixes and features that we request. But it's equally false to think that because the users of our framework/library are not paying clients, we owe them nothing. They trusted us, built their own code against ours, followed our conventions and best practices, when they could have chosen another language/framework/library. How can we justify trampling their own efforts, making them waste days or weeks of development, just because we suddenly felt the irrepressible urge to change a naming scheme, or drop perfectly working code? We're all interdependent in a software ecosystem, and a tiny dose of awareness, carefulness and rationality can go a long way. "But you're never sure that a change doesn't break things", some will shrug. Sure. No one demands perfection. But not being deliberately harmful is already a very good start.

可以肯定地说,因为我们使用了一些开源软件,所以我们有权获得我们所要求的错误修正和功能,这是错误的。 但是,由于我们的框架/库的用户没有向客户付款,因此我们不欠他们任何东西,这同样是错误的。 当他们可以选择另一种语言/框架/库时,他们信任我们,针对我们建立自己的代码,遵循我们的约定和最佳实践。 我们怎么能证明践踏他们自己的努力,而浪费他们数天或数周的开发,仅仅因为我们突然感到改变命名方案或放弃完美的工作代码的迫切欲望? 我们都是在软件生态系统中相互依存的,一小部分的意识,细心和合理性就可以走很长一段路。 “ 但是您永远不确定变化不会破坏事情 ”,有些人会耸耸肩。 当然。 没有人要求完美。 但是不故意造成伤害已经是一个很好的开始。

There is like a paternalistic mood behind some advocates of the "walk or die" approach. "If we stick to API stability, contributors will get lazy and never update their modules, the ecosystem will rot in place instead of moving forward". Oh damn, how dangerous it is, to do people's good against their will. If we want users to update their codebase, at the very contrary, we should start by not brutally breaking things. We should bring shiny new features, not just a gun to their head. We should let them fix mildly annoying "deprecation warnings" when they feel like and can, not right now. We should let them spend their time on useful contributions, not on repairing what we have broken with the planned obsolescence that we dare calling "progress".

一些“走不走”方法的拥护者背后似乎有一种家长式的情绪。 “ 如果我们坚持API的稳定性,那么贡献者将变得懒惰并且永远不会更新其模块,生态系统将会腐烂而不会前进 ”。 哦,该死,违背人们的意愿做人的事有多危险。 相反,如果我们希望用户更新其代码库,则应从不残酷地破坏事物开始。 我们应该为他们带来闪亮的新功能,而不仅仅是枪支。 我们应该让他们在感觉可能且可能的时候修复轻微烦人的“弃用警告”,而不是现在 。 我们应该让他们把时间花在有益的贡献上,而不是修复我们敢于称之为“进步”的计划过时而打破的东西。

Fun facts: advertising breaking changes in release notes does not grant them legitimacy; and when a private API is so handy that it's used by multiple projects, maybe it's a sign that it should be made public and documented, not that it should be wrecked at the first impulse.

有趣的事实:在发行说明中进行重大更改的广告并不能使其具有合法性; 当专用API如此方便以至于被多个项目使用时,这也许表明它应该公开并记录下来,而不是一时冲动就被破坏。

So let's carve it into the marble of our desktops: API stability is, must be, on top of our list of concerns; along with robustness and adequation with final users' needs; but infinitely above any kind of aesthetical consideration. Only with long-term compatibility may our software ecosystems grow from a short elite of continually updated applications, to a huge and diverse galaxy of modules; some last- updated yesterday, some last-updated ten years ago, but all of them getting stuff done. Because that what software is all about, and that's what people are being paid for, at the end of the day. Not wasting time fixing the wheel that worked yesterday, and won't tomorrow ever more, because we heard the calling of the void.

因此,让我们将其雕刻到桌面的大理石上:必须将API的稳定性放在我们关注的问题的首位; 健壮性和满足最终用户需求的能力; 但绝对超越任何一种美学考虑。 只有长期的兼容性,我们的软件生态系统才能从一小撮不断更新的应用程序精英成长为庞大而多样的模块星系。 有些是昨天最新更新的,有些是十年前最新更新的,但是所有人都完成了工作 。 因为这就是软件的全部意义,而这就是人们最终要支付的费用。 不要浪费时间修理昨天工作的轮子,明天再也不会花时间了,因为我们听到了虚空的呼唤。

Compat Patcher概念 (The Compat Patcher concept)

Am I asking (open source) software maintainers to make more efforts, in order to achieve this so crucial long-term API stability? Nope. I wouldn't dare. At the contrary, I ask them to be lazier. But the good, the sensible, the both self-interested and benevolent, kind of lazy.

我是否要求(开源)软件维护者做出更多努力,以实现如此至关重要的长期API稳定性? 不。 我不敢 相反,我要求他们变得懒惰。 但是善良,明智,既自私又仁慈的人有点懒惰。

More compatibility means less support requests, less time justifying controversial changes, and more feature/bugfix contributions from our community. More compatibility doesn't even mean more keyboard typing. Except if we're only into toy projects, we've already put compatibility shims in place for a time. Just one thing to do : leave them be. They don't hurt us. They don't waste disk space. They are probably worth thousands of dollars per character. Let's just avoid one savage "Removing compatibility shim XYZ" commit, and move on towards greater goals.

更好的兼容性意味着更少的支持请求,更少的时间来证明有争议的更改以及我们社区提供的更多功能/错误修正。 更大的兼容性甚至并不意味着更多的键盘输入。 除非我们只参与玩具项目,否则我们已经将兼容性垫片放置了一段时间。 要做的一件事: 让他们成为现实 。 他们不伤害我们。 他们不浪费磁盘空间。 他们每个角色可能价值数千美元。 让我们仅避免一次野蛮的“删除兼容性垫片XYZ”提交,然后朝着更大的目标迈进。

And if the mere view of a compatibility shim makes us vomit (a not so unusual pathology I guess), there is awesome news : with high-level languages, we don't need shims in our code anymore. We just have to embrace the concept of Compatibility Patcher (or "compatcher" for neologism lovers).

而且,如果仅凭兼容性垫片的观点就使我们呕吐(我想这不是一种异常的病理学),那么就有一个了不起的消息:使用高级语言,我们不再需要代码中的填充。 我们只需要接受Compatibility Patcher (对于新词爱好者来说就是“ compatcher”)的概念。

Wat-iz-dat ? Just a companion library, often living its own life in its own repository, which plugs itself to the real software at startup time, and restores its compatibility with a decade of its previous versions. Thus, we can keep our codebase entirely unaware of whatever a "deprecation" might be, while still keeping a symbiotic coexistence with the thousands modules living in our ecosystem.

Wat-iz-dat? 只是一个伴随库,通常在其自己的存储库中过着自己的生活,它会在启动时将其插入到真正的软件中,并恢复与十年前版本的兼容性。 因此,我们可以使我们的代码库完全不知道“弃用”可能是什么,同时仍与生活在我们生态系统中的数千个模块保持共生共存。

Monkey-patching is ugly, someone said? Maybe, but never as ugly as spending hours retro-engineering a whole plugin architecture, just to realize that an additional "S" in naming conventions sufficed to ruin everything. Programming overlords might prefer to weave their code with external shims using aspect-oriented programming, but for most of us mere mortals, simplicity and pragmatism are widely sufficient enough. Some documentation, logging, and console warnings, are "explicit" enough to make anybody keep control over the codebase.

有人说猴子打补丁很丑吗? 也许但从来没有像花费数小时对整个插件体系结构进行重新设计那样丑陋,只是为了意识到命名约定中的附加“ S”足以破坏所有内容。 编程霸主可能更喜欢使用面向方面的编程将代码与外部填充编织在一起,但是对于我们大多数人来说,凡人,简单和实用就足够了。 一些文档,日志记录和控制台警告足够“明确”,以使任何人都可以控制代码库。

Let's not underestimate the power of high level languages. Examples with Python. We rename a submodule? Fine, thanks to import hooks, "from framework import oldmodule" and "from framework import newmodule" will return the exact same object. We change the signature of a function ? One tiny injection later, the old set of call parameters will automatically be adapted and forwarded to the new signature. We move an entire group of utilities out of the main repository? Fine, but as long as needed, the compatibility patcher will fetch them from their new location, and inject them back where they once so nicely belonged. We rename constants, classes, functions ? Leaving an alias was only costing a single code line, now with compatibility patchers this line doesn't even have to hurt our eyes and hearts anymore.

让我们不要低估高级语言的功能。 Python示例。 我们重命名一个子模块? 很好,感谢导入钩子,“ from framework import oldmodule ”和“ from framework import newmodule ”将返回完全相同的对象。 我们改变一个函数的签名了吗? 一小段注入之后,旧的调用参数集将自动进行调整并转发到新的签名。 我们要将整个实用程序组移出主存储库吗? 很好,但是只要有需要,兼容性修补程序就会从新位置获取它们,然后将它们重新插入它们曾经很好的归属位置。 我们重命名常量,类,函数? 留下别名只需要花费一条代码行,现在有了兼容性修补程序,该行甚至不必再伤我们的眼睛和心脏。

Please notice, Compatibility Patchers act like time travelers. They work even when developers delete a function, re-add it under a different shape, then remove it again. They work even when developers recklessly modify function behaviours, for example by exchanging similar arguments in-place. So imagine when developers cooperate with this system, and nicely decouple programming concerns so that the patch is minimal!

请注意,兼容性修补程序的行为就像时间旅行者。 即使开发人员删除功能,以其他形状重新添加功能,然后再次将其删除,它们也可以工作。 即使开发人员不顾后果地修改功能行为(例如通过就地交换相似的参数),它们也可以工作。 因此,请想象一下,当开发人员与该系统合作时,可以很好地消除编程问题,从而使补丁最小化!

Cherry on the cake, by separating "state of art" code and compatibility shims, Compat Patchers make it a breeze to selectively activate compatibility sets. Your project is brand new and only relies on bleeding edge libraries ? Fine, deactivate the whole patcher. You just need compatibility with the last two major versions of the framework? Just enable the corresponding families of shims. You need support for very old packages ? Leave the patcher configuration in maximal mode.

蛋糕上的樱桃,通过分离“最新技术”代码和兼容性垫片,Compat Patchers使选择激活激活集变得轻而易举。 您的项目是全新的,仅依赖于最新的库? 好,停用整个修补程序。 您只需要与框架的最后两个主要版本兼容? 只需启用相应的垫片系列即可。 您需要非常旧的软件包的支持吗? 将修补程序配置保留为最大模式。

Now comes the anxiety-provoking part : what are the downsides of Compat Patchers? Answer: up to a few seconds of delay at startup (when all shims are activated), and a few logical operations and type checks here and there at runtime. That's it. In the modern web world, where most server processes run for hours uninterrupted, process the most unoptimized (text-based) formats conceivable, and where performance depends much more on DB optimization and proper caching than on raw execution speed, it sounds like a legitimate expense, doesn't it?

现在是引起焦虑的部分:Compat Patchers的缺点是什么? 答:启动时(激活所有垫片时)最多延迟几秒钟,并且在运行时在此处和那里进行一些逻辑运算和类型检查。 而已。 在现代网络世界中,大多数服务器进程连续运行几个小时,可以处理最优化的(基于文本的)格式,并且性能更多地取决于数据库优化和适当的缓存,而不是原始执行速度,这听起来像是合法的。费用,不是吗?

Edit: another limitation of Compat Patchers is that they require a tiny little bit of cooperation from core developers. Indeed, we all implicitly know the rule of backwards compatibility: "Only Add Optional". Add new optional arguments, add new functions, add new modules; don't remove elements and behaviours, don't make old options mandatory. But there is an additional, golden rule: don't ever, ever, change the semantic of things in-place. If we change the meaning of an argument, the format of an output, the action of a callable, without any additional indicator, then setting up shims becomes (almost) unfeasible; in this case, even Compat Patchers won't be able to resolve this ambiguity, and guess the behaviour that our users were requesting when using our API. Let's blacklist forever these kinds of brutal and inimical changes.

编辑 :Compat Patchers的另一个限制是它们需要核心开发人员的一点点合作。 确实,我们所有人都暗中了解向后兼容的规则:“ 仅添加选项 ”。 添加新的可选参数,添加新的功能,添加新的模块; 不要删除元素和行为,不要使旧选项成为必需。 但是还有一条额外的黄金法则: 永远不要永远就地更改事物的语义 。 如果我们更改参数的含义,输出的格式,可调用的操作,而没有任何其他指示符,则设置垫片(几乎)是不可行的; 在这种情况下,即使Compat Patchers也无法解决这种歧义,并且无法猜测用户在使用我们的API时所要求的行为。 让我们永远将这些残酷而无常的变化列入黑名单。

练习时间! (Time for practice!)

Compat patchers are not just wishful thinking.

兼容修补程序不只是一厢情愿。

Here is one for the famous Django web framework. With a few dozens of small fixers, it allows one to use pluggable apps targeting from versions 1.6 to 2.2 of the framework. And it's only a start - feature requests and comments are welcome.

这是著名的Django Web框架的一个。 借助几十个小型修复程序,它允许一个人使用针对框架版本1.6至2.2的可插拔应用程序。 这只是一个开始-欢迎功能要求和评论。

This patcher is used in production on a few sites, including the Pychronia portal and its CMS/Blog ecosystem. It runs on CompatPatcherCore, a Python micro-framework for creating such companion applications in the blink of an eye (a cookiecutter recipe is even included).

该修补程序已在一些站点的生产中使用,包括Pychronia门户及其CMS / Blog生态系统。 它运行在CompatPatcherCore上 ,这是一个Python微框架,用于在眨眼间创建此类配套应用程序(甚至包括cookiecutter配方 )。

Without surprise, I warmly encourage you to bootstrap a Compat Patcher for the framework/library you might maintain, unless you are one of the few valiant minds already strongly committed to API stability.

毫不奇怪,我强烈建议您针对您可能维护的框架/库引导Compat Patcher,除非您是已经坚定地致力于API稳定性的少数勇者之一。

This concept should also be easy to port to Ruby, PHP, Javascript, and other high-malleability languages. With lower-level and static languages, the task might be much harder (and require macro processors and the likes), but who knows.

这个概念还应该易于移植到Ruby,PHP,Javascript和其他高恶意软件语言。 使用低级和静态语言,任务可能会困难得多(并且需要宏处理器等),但是谁知道呢。

So here we are. Update breakages are not a fatality. Just a bad habit that we must break, thanks to a little pondering and a few technical niceties. We may thus enjoy the delights of ever-growing and ever-working software ecosystems, those which do make development fun and exciting!

所以我们到了。 更新损坏不是致命的。 只是一个坏习惯,我们必须打破 ,由于一点点琢磨和一些技术细微。 因此,我们可能会享受不断增长和不断工作的软件生态系统带来的乐趣,这些生态系统确实使开发变得有趣而令人兴奋!

Edit 2019/07/05: Evocate the "hard scarcity of resources" as a possible reason for lack of shims, and tweak the tone of this part.

编辑2019/07/05:提倡“资源严重短缺”作为缺少填充的可能原因,并调整此部分的基调。

Edit 2019/07/14: Fix typos, and warn against in-place semantic changes.

编辑2019/07/14:修正拼写错误,并警告就地语义更改。

翻译自: https://www.freecodecamp.org/news/api-stability-is-cheap-and-easy/

compat包

compat包_使用Compat Patchers,API的稳定性既便宜又容易!相关推荐

  1. spark python 上传代码包_使用 Livy Rest API 提交 spark 批量任务 (jar,Python, streaming)...

    Livy是一个开源的REST 接口,用于与Spark进行交互,它同时支持提交执行代码段和完整的程序. image.png Livy封装了spark-submit并支持远端执行. 启动服务器 执行以下命 ...

  2. 友盟统计+渠道包_学习笔记

    友盟统计+渠道包_学习笔记 资料: 官网:https://developer.umeng.com/docs/66632/detail/66889#h3-u5E38u89C1u95EEu9898 视频资 ...

  3. python批量爬取小网格区域坐标系_Python爬虫实例_利用百度地图API批量获取城市所有的POI点...

    上篇关于爬虫的文章,我们讲解了如何运用Python的requests及BeautifuiSoup模块来完成静态网页的爬取,总结过程,网页爬虫本质就两步: 1.设置请求参数(url,headers,co ...

  4. 离线安装python包_补充

    离线安装python包_补充 一.利用好pip,找到所有依赖库 1.要安装 paramiko,先 pip show 一下 paramiko 2.继续 pip show 其依赖库 3.继续 pip sh ...

  5. 打蚊子表情包_打蚊子表情包 - 打蚊子微信表情包 - 打蚊子QQ表情包 - 发表情 fabiaoqing.com...

    拍打蚊子GIF - 蚊子表情包_蚊子表情 夏天来了,打蚊子_蚊子_夏天表情 为什么蚊子只爱我 - 蚊子表情包_蚊子表情 采访蚊子 请问你为什么要咬我 - 蚊子表情包_蚊子表情 蚊子飞在屎上 - 打屎打 ...

  6. 打蚊子表情包_蚊子表情包 - 蚊子微信表情包 - 蚊子QQ表情包 - 发表情 fabiaoqing.com...

    为什么蚊子只爱我 - 蚊子表情包_蚊子表情 拍打蚊子GIF - 蚊子表情包_蚊子表情 采访蚊子 请问你为什么要咬我 - 蚊子表情包_蚊子表情 蚊子飞在屎上 - 打屎打屎_屎_蚊子表情 我想,最爱我的是 ...

  7. R_circlize包_和弦图(二)

    作者:李誉辉 四川大学在读研究生 往期精彩: R_插值_拟合_回归_样条 接上一篇:R_circlize包_和弦图(一) link弦可见 在需要强调某些relation时,需要高亮对应的弦,一般有4种 ...

  8. java秃头表情包_最怕空气突然的安静表情包 - 最怕空气突然的安静微信表情包 - 最怕空气突然的安静QQ表情包 - 发表情 fabiaoqing.com...

    最怕空气突然安静最怕大乔突然关心_最怕_大乔_突然_安静_关心表情 突然登场 - 最怕空气突然的安静 ​_突然表情 突然抱紧 - 最怕空气突然的安静 ​_突然表情 突然兴奋 - 最怕空气突然的安静 ​ ...

  9. 【一包通刷】晶晨S905L3A/B_完美AI语音线刷包_打开ADB_ROOT权限

    [9.0一包通刷]晶晨S905L3A/B_完美AI语音线刷包_默认打开ADB ROOT权限支持游戏启动_万物互联启动动画 适用型号:M401A.CM311-1a.CM311-1sa.B863AV3.1 ...

最新文章

  1. 编译ONNX模型Compile ONNX Models
  2. 学习《Linux设备模型浅析之设备篇》笔记(深挖一)
  3. 深入理解 JavaScript 中的 replace 方法
  4. MySQL知识梳理与命令操作
  5. 表达式解析执行器 IKExpression
  6. 玩斗地主明白的7个道理
  7. 私人定制---打造属于自己的linux小系统
  8. react 中渲染html_如何在React中识别和解决浪费的渲染
  9. vue中更换标签页.ico图标报错路径找不到图片
  10. 隐写术写在简历上面_隐写术用纯英语解释
  11. 快捷指令 python_快捷指令 pythonista wifi连接上局域网(自动)唤醒主机电脑或投影仪...
  12. mysql 死锁 代码_MySQL死锁问题解决的代码详细介绍
  13. 探寻 JavaScript 逻辑运算符(与、或)的真谛
  14. Android怎样实现毛玻璃效果之Android高级模糊技术
  15. 阶段3 1.Mybatis_12.Mybatis注解开发_1 mybatis注解开发的环境搭建
  16. 自动化查询及增加配置参数功能
  17. mac无法正确打开html,苹果MacBook电脑打不开网页不能访问怎么办
  18. 关于我2021腾讯暑期实习一面一波流这件事以及反思
  19. WBE15_HttpServletRequest
  20. 笔记本计算机无法上无线网络,笔记本电脑无线网络连接不上原因有哪些【详细介绍】...

热门文章

  1. 设计模式——单例模式详解
  2. Map集合 java
  3. 动态数组与迭代器 0119
  4. animation动画效果 1002 css3
  5. django-聚合函数
  6. OPENSUSE + zabbix源码安装,PHP出现问题?怎么解决?
  7. 解决vue+axios post参数后端无法接收的问题
  8. MapReduce的计算资源划分
  9. mysqlbinlog日志一天产生太多脚本
  10. PX2板实现H.264裸码流的解码