This commit is contained in:
CanYellow 2023-04-05 23:04:20 +08:00
parent d65cd66b76
commit 866ece47b2
2 changed files with 240 additions and 246 deletions

View File

@ -1,146 +1,146 @@
[#]: collector: (lujun9972)
[#]: translator: (CanYellow)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Roy Fielding's Misappropriated REST Dissertation)
[#]: via: (https://twobithistory.org/2020/06/28/rest.html)
[#]: author: (Two-Bit History https://twobithistory.org)
被错误应用的罗伊·菲尔丁的有关描述性状态迁移的博士论文
======
TD
Roy Fielding's Misappropriated REST Dissertation
======
符合描述性状态迁移的 (RESTful,REST译自审定公布名词数据库) 应用程序接口 (API) 无处不在。有趣的是又有多少人真正了解“描述性状态迁移”的应有之义呢?
DN
RESTful APIs are everywhere. This is funny, because how many people really know what “RESTful” is supposed to mean?
大概我们中的大多数人都会跟[黑客新闻网站上的这篇公开问答][1]产生共鸣:
I think most of us can empathize with [this Hacker News poster][1]:
> 我阅读了几篇介绍描述性状态迁移的文章,甚至包括原始论文的部分章节。然而我仍然对描述性状态迁移到底是什么只有一个相当模糊的想法。我开始认为没有人真的了解描述性状态迁移,它仅仅是一个定义相当不充分的概念。
DN
> Ive read several articles about REST, even a bit of the original paper. But I still have quite a vague idea about what it is. Im beginning to think that nobody knows, that its simply a very poorly defined concept.
我曾经计划写一篇有关描述性状态迁移的博客,在里面探讨描述性状态迁移是如何成为这样一个在网络通信领域占主导地位的范式的。我通过阅读[2000年发表的罗伊·菲尔丁的博士论文][2]开始我的研究,这篇博士论文向世人介绍了描述性状态迁移的概念。在读过菲尔丁的博士论文以后,我意识到,相比之下,更引人注意的是菲尔丁的理论缘何受到如此普遍的误解。
DN
I had planned to write a blog post exploring how REST came to be such a dominant paradigm for communication across the internet. I started my research by reading [Roy Fieldings 2000 dissertation][2], which introduced REST to the world. After reading Fieldings dissertation, I realized that the much more interesting story here is how Fieldings ideas came to be so widely misunderstood.
(相对公平地说)很多人知道描述性状态迁移源自菲尔丁的博士论文,但并没有读过该论文。因此对于这篇博士论文的原始内容的误解才得以流行。
DN
Many more people know that Fieldings dissertation is where REST came from than have read the dissertation (fair enough), so misconceptions about what the dissertation actually contains are pervasive.
最大的误解是:这篇博士论文直接讨论了(译注:广义的)构建应用程序接口的问题,我此前一直认为描述性状态迁移从一开始就打算成为构建在超文本传输协议(HTTP)之上的网络应用程序接口(Web API)的架构模型,我相信很多人也这样认为。我猜测此前可能存在一个混乱的试验时期,开发人员采用完全错误的方式在超文本传输协议基础上开发应用程序接口,然后菲尔丁出现了并提出了将描述性状态迁移做为网络应用程序开发的正确方式。但是这种想法的时间线对不上:我们今天所熟知的网络服务的应用程序接口并非是在菲尔丁出版他的博士论文之后才出现的新生事物。
DN
The biggest of these misconceptions is that the dissertation directly addresses the problem of building APIs. I had always assumed, as I imagine many people do, that REST was intended from the get-go as an architectural model for web APIs built on top of HTTP. I thought perhaps that there had been some chaotic experimental period where people were building APIs on top of HTTP all wrong, and then Fielding came along and presented REST as the sane way to do things. But the timeline doesnt make sense here: APIs for web services, in the sense that we know them today, werent a thing until a few years after Fielding published his dissertation.
菲尔丁的博士论文(名为“架构风格与基于网络的软件架构设计”)(译者注,网络中文版的中文译名)不是讨论如何在超文本传输协议的基础上构建应用程序接口而恰恰是讨论超文本协议本身菲尔丁是超文本传输协议1.0版规范的贡献者同时也是超文本传输协议1.1版的共同作者。有感于从HTTP协议的设计中获得的架构经验他的博士论文将描述性状态迁移视为指导HTTP/1.1的标准化过程的架构原则的精华。举例而言,他拒绝了使用`MGET`和`MHEAD`方法进行批量请求的提议因为他认为这违反了REST所定义的约束条件尤其是在一个符合REST的系统中传递的消息应该是易于代理和缓存的约束条件。[1][3]因此HTTP/1.1转而围绕持久性连接设计在此基础上可以发送多个HTTP请求。菲尔丁同时认为
Fieldings dissertation (titled “Architectural Styles and the Design of Network-based Software Architectures”) is not about how to build APIs on top of HTTP but rather about HTTP itself. Fielding contributed to the HTTP/1.0 specification and co-authored the HTTP/1.1 specification, which was published in 1999. He was interested in the architectural lessons that could be drawn from the design of the HTTP protocol; his dissertation presents REST as a distillation of the architectural principles that guided the standardization process for HTTP/1.1. Fielding used these principles to make decisions about which proposals to incorporate into HTTP/1.1. For example, he rejected a proposal to batch requests using new `MGET` and `MHEAD` methods because he felt the proposal violated the constraints prescribed by REST, especially the constraint that messages in a REST system should be easy to proxy and cache.[1][3] So HTTP/1.1 was instead designed around persistent connections over which multiple HTTP requests can be sent. (Fielding also felt that cookies are not RESTful because they add state to what should be a stateless system, but their usage was already entrenched.[2][4]) REST, for Fielding, was not a guide to building HTTP-based systems but a guide to extending HTTP.
This isnt to say that Fielding doesnt think REST could be used to build other systems. Its just that he assumes these other systems will also be “distributed hypermedia systems.” This is another misconception people have about REST: that it is a general architecture you can use for any kind of networked application. But you could sum up the part of the dissertation where Fielding introduces REST as, essentially, “Listen, we just designed HTTP, so if you also find yourself designing a _distributed hypermedia system_ you should use this cool architecture we worked out called REST to make things easier.” Its not obvious why Fielding thinks anyone would ever attempt to build such a thing given that the web already exists; perhaps in 2000 it seemed like there was room for more than one distributed hypermedia system in the world. Anyway, Fielding makes clear that REST is intended as a solution for the scalability and consistency problems that arise when trying to connect hypermedia across the internet, _not_ as an architectural model for distributed applications in general.
We remember Fieldings dissertation now as the dissertation that introduced REST, but really the dissertation is about how much one-size-fits-all software architectures suck, and how you can better pick a software architecture appropriate for your needs. Only a single chapter of the dissertation is devoted to REST itself; much of the word count is spent on a taxonomy of alternative architectural styles[3][5] that one could use for networked applications. Among these is the Pipe-and-Filter (PF) style, inspired by Unix pipes, along with various refinements of the Client-Server style (CS), such as Layered-Client-Server (LCS), Client-Cache-Stateless-Server (C$SS), and Layered-Client-Cache-Stateless-Server (LC$SS). The acronyms get unwieldy but Fieldings point is that you can mix and match constraints imposed by existing styles to derive new styles. REST gets derived this way and could instead have been called—but for obvious reasons was not—Uniform-Layered-Code-on-Demand-Client-Cache-Stateless-Server (ULCODC$SS). Fielding establishes this taxonomy to emphasize that different constraints are appropriate for different applications and that this last group of constraints were the ones he felt worked best for HTTP.
This is the deep, deep irony of RESTs ubiquity today. REST gets blindly used for all sorts of networked applications now, but Fielding originally offered REST as an illustration of how to derive a software architecture tailored to an individual applications particular needs.
I struggle to understand how this happened, because Fielding is so explicit about the pitfalls of not letting form follow function. He warns, almost at the very beginning of the dissertation, that “design-by-buzzword is a common occurrence” brought on by a failure to properly appreciate software architecture.[4][6] He picks up this theme again several pages later:
> Some architectural styles are often portrayed as “silver bullet” solutions for all forms of software. However, a good designer should select a style that matches the needs of a particular problem being solved.[5][7]
REST itself is an especially poor “silver bullet” solution, because, as Fielding later points out, it incorporates trade-offs that may not be appropriate unless you are building a distributed hypermedia application:
> REST is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction.[6][8]
Fielding came up with REST because the web posed a thorny problem of “anarchic scalability,” by which Fielding means the need to connect documents in a performant way across organizational and national boundaries. The constraints that REST imposes were carefully chosen to solve this anarchic scalability problem. Web service APIs that are _public-facing_ have to deal with a similar problem, so one can see why REST is relevant there. Yet today it would not be at all surprising to find that an engineering team has built a backend using REST even though the backend only talks to clients that the engineering team has full control over. We have all become the architect in [this Monty Python sketch][9], who designs an apartment building in the style of a slaughterhouse because slaughterhouses are the only thing he has experience building. (Fielding uses a line from this sketch as an epigraph for his dissertation: “Excuse me… did you say knives?”)
So, given that Fieldings dissertation was all about avoiding silver bullet software architectures, how did REST become a de facto standard for web services of every kind?
My theory is that, in the mid-2000s, the people who were sick of SOAP and wanted to do something else needed their own four-letter acronym.
Im only half-joking here. SOAP, or the Simple Object Access Protocol, is a verbose and complicated protocol that you cannot use without first understanding a bunch of interrelated XML specifications. Early web services offered APIs based on SOAP, but, as more and more APIs started being offered in the mid-2000s, software developers burned by SOAPs complexity migrated away en masse.
Among this crowd, SOAP inspired contempt. Ruby-on-Rails dropped SOAP support in 2007, leading to this emblematic comment from Rails creator David Heinemeier Hansson: “We feel that SOAP is overly complicated. Its been taken over by the enterprise people, and when that happens, usually nothing good comes of it.”[7][10] The “enterprise people” wanted everything to be formally specified, but the get-shit-done crowd saw that as a waste of time.
If the get-shit-done crowd wasnt going to use SOAP, they still needed some standard way of doing things. Since everyone was using HTTP, and since everyone would keep using HTTP at least as a transport layer because of all the proxying and caching support, the simplest possible thing to do was just rely on HTTPs existing semantics. So thats what they did. They could have called their approach Fuck It, Overload HTTP (FIOH), and that would have been an accurate name, as anyone who has ever tried to decide what HTTP status code to return for a business logic error can attest. But that would have seemed recklessly blasé next to all the formal specification work that went into SOAP.
Luckily, there was this dissertation out there, written by a co-author of the HTTP/1.1 specification, that had something vaguely to do with extending HTTP and could offer FIOH a veneer of academic respectability. So REST was appropriated to give cover for what was really just FIOH.
Im not saying that this is exactly how things happened, or that there was an actual conspiracy among irreverent startup types to misappropriate REST, but this story helps me understand how REST became a model for web service APIs when Fieldings dissertation isnt about web service APIs at all. Adopting RESTs constraints makes some sense, especially for public-facing APIs that do cross organizational boundaries and thus benefit from RESTs “uniform interface.” That link must have been the kernel of why REST first got mentioned in connection with building APIs on the web. But imagining a separate approach called “FIOH,” that borrowed the “REST” name partly just for marketing reasons, helps me account for the many disparities between what today we know as RESTful APIs and the REST architectural style that Fielding originally described.
REST purists often complain, for example, that so-called REST APIs arent actually REST APIs because they do not use Hypermedia as The Engine of Application State (HATEOAS). Fielding himself [has made this criticism][11]. According to him, a real REST API is supposed to allow you to navigate all its endpoints from a base endpoint by following links. If you think that people are actually out there trying to build REST APIs, then this is a glaring omission—HATEOAS really is fundamental to Fieldings original conception of REST, especially considering that the “state transfer” in “Representational State Transfer” refers to navigating a state machine using hyperlinks between resources (and not, as many people seem to believe, to transferring resource state over the wire).[8][12] But if you imagine that everyone is just building FIOH APIs and advertising them, with a nudge and a wink, as REST APIs, or slightly more honestly as “RESTful” APIs, then of course HATEOAS is unimportant.
Similarly, you might be surprised to know that there is nothing in Fieldings dissertation about which HTTP verb should map to which CRUD action, even though software developers like to argue endlessly about whether using PUT or PATCH to update a resource is more RESTful. Having a standard mapping of HTTP verbs to CRUD actions is a useful thing, but this standard mapping is part of FIOH and not part of REST.
This is why, rather than saying that nobody understands REST, we should just think of the term “REST” as having been misappropriated. The modern notion of a REST API has historical links to Fieldings REST architecture, but really the two things are separate. The historical link is good to keep in mind as a guide for when to build a RESTful API. Does your API cross organizational and national boundaries the same way that HTTP needs to? Then building a RESTful API with a predictable, uniform interface might be the right approach. If not, its good to remember that Fielding favored having form follow function. Maybe something like GraphQL or even just JSON-RPC would be a better fit for what you are trying to accomplish.
_If you enjoyed this post, more like it come out every four weeks! Follow [@TwoBitHistory][13] on Twitter or subscribe to the [RSS feed][14] to make sure you know when a new post is out._
_Previously on TwoBitHistory…_
> New post is up! I wrote about how to solve differential equations using an analog computer from the '30s mostly made out of gears. As a bonus there's even some stuff in here about how to aim very large artillery pieces.<https://t.co/fwswXymgZa>
>
> — TwoBitHistory (@TwoBitHistory) [April 6, 2020][15]
1. Roy Fielding. “Architectural Styles and the Design of Network-based Software Architectures,” 128. 2000. University of California, Irvine, PhD Dissertation, accessed June 28, 2020, <https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf>. [↩︎][16]
2. Fielding, 130. [↩︎][17]
3. Fielding distinguishes between software architectures and software architecture “styles.” REST is an architectural style that has an instantiation in the architecture of HTTP. [↩︎][18]
4. Fielding, 2. [↩︎][19]
5. Fielding, 15. [↩︎][20]
6. Fielding, 82. [↩︎][21]
7. Paul Krill. “Ruby on Rails 2.0 released for Web Apps,” InfoWorld. Dec 7, 2007, accessed June 28, 2020, <https://www.infoworld.com/article/2648925/ruby-on-rails-2-0-released-for-web-apps.html> [↩︎][22]
8. Fielding, 109. [↩︎][23]
--------------------------------------------------------------------------------
via: https://twobithistory.org/2020/06/28/rest.html
作者:[Two-Bit History][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://twobithistory.org
[b]: https://github.com/lujun9972
[1]: https://news.ycombinator.com/item?id=7201871
[2]: https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf
[3]: tmp.Ewi4FpMIg6#fn:1
[4]: tmp.Ewi4FpMIg6#fn:2
[5]: tmp.Ewi4FpMIg6#fn:3
[6]: tmp.Ewi4FpMIg6#fn:4
[7]: tmp.Ewi4FpMIg6#fn:5
[8]: tmp.Ewi4FpMIg6#fn:6
[9]: https://www.youtube.com/watch?v=vNoPJqm3DAY
[10]: tmp.Ewi4FpMIg6#fn:7
[11]: https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
[12]: tmp.Ewi4FpMIg6#fn:8
[13]: https://twitter.com/TwoBitHistory
[14]: https://twobithistory.org/feed.xml
[15]: https://twitter.com/TwoBitHistory/status/1247187881946275841?ref_src=twsrc%5Etfw
[16]: tmp.Ewi4FpMIg6#fnref:1
[17]: tmp.Ewi4FpMIg6#fnref:2
[18]: tmp.Ewi4FpMIg6#fnref:3
[19]: tmp.Ewi4FpMIg6#fnref:4
[20]: tmp.Ewi4FpMIg6#fnref:5
[21]: tmp.Ewi4FpMIg6#fnref:6
[22]: tmp.Ewi4FpMIg6#fnref:7
[23]: tmp.Ewi4FpMIg6#fnref:8
[#]: collector: (lujun9972)
[#]: translator: (CanYellow)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Roy Fielding's Misappropriated REST Dissertation)
[#]: via: (https://twobithistory.org/2020/06/28/rest.html)
[#]: author: (Two-Bit History https://twobithistory.org)
被错误应用的罗伊·菲尔丁的有关描述性状态迁移的博士论文
======
TD
Roy Fielding's Misappropriated REST Dissertation
======
符合描述性状态迁移的 (RESTful,REST译自审定公布名词数据库) 应用程序接口 (API) 无处不在。有趣的是又有多少人真正了解“描述性状态迁移”的应有之义呢?
DN
RESTful APIs are everywhere. This is funny, because how many people really know what “RESTful” is supposed to mean?
大概我们中的大多数人都会跟[黑客新闻网站上的这篇公开问答][1]产生共鸣:
I think most of us can empathize with [this Hacker News poster][1]:
> 我阅读了几篇介绍描述性状态迁移的文章,甚至包括原始论文的部分章节。然而我仍然对描述性状态迁移到底是什么只有一个相当模糊的想法。我开始认为没有人真的了解描述性状态迁移,它仅仅是一个定义相当不充分的概念。
DN
> Ive read several articles about REST, even a bit of the original paper. But I still have quite a vague idea about what it is. Im beginning to think that nobody knows, that its simply a very poorly defined concept.
我曾经计划写一篇有关描述性状态迁移的博客,在里面探讨描述性状态迁移是如何成为这样一个在网络通信领域占主导地位的范式的。我通过阅读[2000年发表的罗伊·菲尔丁的博士论文][2]开始我的研究,这篇博士论文向世人介绍了描述性状态迁移的概念。在读过菲尔丁的博士论文以后,我意识到,相比之下,更引人注意的是菲尔丁的理论缘何受到如此普遍的误解。
DN
I had planned to write a blog post exploring how REST came to be such a dominant paradigm for communication across the internet. I started my research by reading [Roy Fieldings 2000 dissertation][2], which introduced REST to the world. After reading Fieldings dissertation, I realized that the much more interesting story here is how Fieldings ideas came to be so widely misunderstood.
(相对公平地说)很多人知道描述性状态迁移源自菲尔丁的博士论文,但并没有读过该论文。因此对于这篇博士论文的原始内容的误解才得以流行。
DN
Many more people know that Fieldings dissertation is where REST came from than have read the dissertation (fair enough), so misconceptions about what the dissertation actually contains are pervasive.
最大的误解是:这篇博士论文直接讨论了(译注:广义的)构建应用程序接口的问题,我此前一直认为描述性状态迁移从一开始就打算成为构建在超文本传输协议(HTTP)之上的网络应用程序接口(Web API)的架构模型,我相信很多人也这样认为。我猜测此前可能存在一个混乱的试验时期,开发人员采用完全错误的方式在超文本传输协议基础上开发应用程序接口,然后菲尔丁出现了并提出了将描述性状态迁移做为网络应用程序开发的正确方式。但是这种想法的时间线对不上:我们今天所熟知的网络服务的应用程序接口并非是在菲尔丁出版他的博士论文之后才出现的新生事物。
DN
The biggest of these misconceptions is that the dissertation directly addresses the problem of building APIs. I had always assumed, as I imagine many people do, that REST was intended from the get-go as an architectural model for web APIs built on top of HTTP. I thought perhaps that there had been some chaotic experimental period where people were building APIs on top of HTTP all wrong, and then Fielding came along and presented REST as the sane way to do things. But the timeline doesnt make sense here: APIs for web services, in the sense that we know them today, werent a thing until a few years after Fielding published his dissertation.
菲尔丁的博士论文(名为“架构风格与基于网络的软件架构设计”)(译者注,网络中文版的中文译名)不是讨论如何在超文本传输协议的基础上构建应用程序接口而恰恰是讨论超文本协议本身菲尔丁是超文本传输协议1.0版规范的贡献者同时也是超文本传输协议1.1版的共同作者。有感于从HTTP协议的设计中获得的架构经验他的博士论文将描述性状态迁移视为指导HTTP/1.1的标准化过程的架构原则的精华。举例而言,他拒绝了使用`MGET`和`MHEAD`方法进行批量请求的提议因为他认为这违反了REST所定义的约束条件尤其是在一个符合REST的系统中传递的消息应该是易于代理和缓存的约束条件。[1][3]因此HTTP/1.1转而围绕持久性连接设计在此基础上可以发送多个HTTP请求。菲尔丁同时认为
Fieldings dissertation (titled “Architectural Styles and the Design of Network-based Software Architectures”) is not about how to build APIs on top of HTTP but rather about HTTP itself. Fielding contributed to the HTTP/1.0 specification and co-authored the HTTP/1.1 specification, which was published in 1999. He was interested in the architectural lessons that could be drawn from the design of the HTTP protocol; his dissertation presents REST as a distillation of the architectural principles that guided the standardization process for HTTP/1.1. Fielding used these principles to make decisions about which proposals to incorporate into HTTP/1.1. For example, he rejected a proposal to batch requests using new `MGET` and `MHEAD` methods because he felt the proposal violated the constraints prescribed by REST, especially the constraint that messages in a REST system should be easy to proxy and cache.[1][3] So HTTP/1.1 was instead designed around persistent connections over which multiple HTTP requests can be sent. (Fielding also felt that cookies are not RESTful because they add state to what should be a stateless system, but their usage was already entrenched.[2][4]) REST, for Fielding, was not a guide to building HTTP-based systems but a guide to extending HTTP.
This isnt to say that Fielding doesnt think REST could be used to build other systems. Its just that he assumes these other systems will also be “distributed hypermedia systems.” This is another misconception people have about REST: that it is a general architecture you can use for any kind of networked application. But you could sum up the part of the dissertation where Fielding introduces REST as, essentially, “Listen, we just designed HTTP, so if you also find yourself designing a _distributed hypermedia system_ you should use this cool architecture we worked out called REST to make things easier.” Its not obvious why Fielding thinks anyone would ever attempt to build such a thing given that the web already exists; perhaps in 2000 it seemed like there was room for more than one distributed hypermedia system in the world. Anyway, Fielding makes clear that REST is intended as a solution for the scalability and consistency problems that arise when trying to connect hypermedia across the internet, _not_ as an architectural model for distributed applications in general.
We remember Fieldings dissertation now as the dissertation that introduced REST, but really the dissertation is about how much one-size-fits-all software architectures suck, and how you can better pick a software architecture appropriate for your needs. Only a single chapter of the dissertation is devoted to REST itself; much of the word count is spent on a taxonomy of alternative architectural styles[3][5] that one could use for networked applications. Among these is the Pipe-and-Filter (PF) style, inspired by Unix pipes, along with various refinements of the Client-Server style (CS), such as Layered-Client-Server (LCS), Client-Cache-Stateless-Server (C$SS), and Layered-Client-Cache-Stateless-Server (LC$SS). The acronyms get unwieldy but Fieldings point is that you can mix and match constraints imposed by existing styles to derive new styles. REST gets derived this way and could instead have been called—but for obvious reasons was not—Uniform-Layered-Code-on-Demand-Client-Cache-Stateless-Server (ULCODC$SS). Fielding establishes this taxonomy to emphasize that different constraints are appropriate for different applications and that this last group of constraints were the ones he felt worked best for HTTP.
This is the deep, deep irony of RESTs ubiquity today. REST gets blindly used for all sorts of networked applications now, but Fielding originally offered REST as an illustration of how to derive a software architecture tailored to an individual applications particular needs.
I struggle to understand how this happened, because Fielding is so explicit about the pitfalls of not letting form follow function. He warns, almost at the very beginning of the dissertation, that “design-by-buzzword is a common occurrence” brought on by a failure to properly appreciate software architecture.[4][6] He picks up this theme again several pages later:
> Some architectural styles are often portrayed as “silver bullet” solutions for all forms of software. However, a good designer should select a style that matches the needs of a particular problem being solved.[5][7]
REST itself is an especially poor “silver bullet” solution, because, as Fielding later points out, it incorporates trade-offs that may not be appropriate unless you are building a distributed hypermedia application:
> REST is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction.[6][8]
Fielding came up with REST because the web posed a thorny problem of “anarchic scalability,” by which Fielding means the need to connect documents in a performant way across organizational and national boundaries. The constraints that REST imposes were carefully chosen to solve this anarchic scalability problem. Web service APIs that are _public-facing_ have to deal with a similar problem, so one can see why REST is relevant there. Yet today it would not be at all surprising to find that an engineering team has built a backend using REST even though the backend only talks to clients that the engineering team has full control over. We have all become the architect in [this Monty Python sketch][9], who designs an apartment building in the style of a slaughterhouse because slaughterhouses are the only thing he has experience building. (Fielding uses a line from this sketch as an epigraph for his dissertation: “Excuse me… did you say knives?”)
So, given that Fieldings dissertation was all about avoiding silver bullet software architectures, how did REST become a de facto standard for web services of every kind?
My theory is that, in the mid-2000s, the people who were sick of SOAP and wanted to do something else needed their own four-letter acronym.
Im only half-joking here. SOAP, or the Simple Object Access Protocol, is a verbose and complicated protocol that you cannot use without first understanding a bunch of interrelated XML specifications. Early web services offered APIs based on SOAP, but, as more and more APIs started being offered in the mid-2000s, software developers burned by SOAPs complexity migrated away en masse.
Among this crowd, SOAP inspired contempt. Ruby-on-Rails dropped SOAP support in 2007, leading to this emblematic comment from Rails creator David Heinemeier Hansson: “We feel that SOAP is overly complicated. Its been taken over by the enterprise people, and when that happens, usually nothing good comes of it.”[7][10] The “enterprise people” wanted everything to be formally specified, but the get-shit-done crowd saw that as a waste of time.
If the get-shit-done crowd wasnt going to use SOAP, they still needed some standard way of doing things. Since everyone was using HTTP, and since everyone would keep using HTTP at least as a transport layer because of all the proxying and caching support, the simplest possible thing to do was just rely on HTTPs existing semantics. So thats what they did. They could have called their approach Fuck It, Overload HTTP (FIOH), and that would have been an accurate name, as anyone who has ever tried to decide what HTTP status code to return for a business logic error can attest. But that would have seemed recklessly blasé next to all the formal specification work that went into SOAP.
Luckily, there was this dissertation out there, written by a co-author of the HTTP/1.1 specification, that had something vaguely to do with extending HTTP and could offer FIOH a veneer of academic respectability. So REST was appropriated to give cover for what was really just FIOH.
Im not saying that this is exactly how things happened, or that there was an actual conspiracy among irreverent startup types to misappropriate REST, but this story helps me understand how REST became a model for web service APIs when Fieldings dissertation isnt about web service APIs at all. Adopting RESTs constraints makes some sense, especially for public-facing APIs that do cross organizational boundaries and thus benefit from RESTs “uniform interface.” That link must have been the kernel of why REST first got mentioned in connection with building APIs on the web. But imagining a separate approach called “FIOH,” that borrowed the “REST” name partly just for marketing reasons, helps me account for the many disparities between what today we know as RESTful APIs and the REST architectural style that Fielding originally described.
REST purists often complain, for example, that so-called REST APIs arent actually REST APIs because they do not use Hypermedia as The Engine of Application State (HATEOAS). Fielding himself [has made this criticism][11]. According to him, a real REST API is supposed to allow you to navigate all its endpoints from a base endpoint by following links. If you think that people are actually out there trying to build REST APIs, then this is a glaring omission—HATEOAS really is fundamental to Fieldings original conception of REST, especially considering that the “state transfer” in “Representational State Transfer” refers to navigating a state machine using hyperlinks between resources (and not, as many people seem to believe, to transferring resource state over the wire).[8][12] But if you imagine that everyone is just building FIOH APIs and advertising them, with a nudge and a wink, as REST APIs, or slightly more honestly as “RESTful” APIs, then of course HATEOAS is unimportant.
Similarly, you might be surprised to know that there is nothing in Fieldings dissertation about which HTTP verb should map to which CRUD action, even though software developers like to argue endlessly about whether using PUT or PATCH to update a resource is more RESTful. Having a standard mapping of HTTP verbs to CRUD actions is a useful thing, but this standard mapping is part of FIOH and not part of REST.
This is why, rather than saying that nobody understands REST, we should just think of the term “REST” as having been misappropriated. The modern notion of a REST API has historical links to Fieldings REST architecture, but really the two things are separate. The historical link is good to keep in mind as a guide for when to build a RESTful API. Does your API cross organizational and national boundaries the same way that HTTP needs to? Then building a RESTful API with a predictable, uniform interface might be the right approach. If not, its good to remember that Fielding favored having form follow function. Maybe something like GraphQL or even just JSON-RPC would be a better fit for what you are trying to accomplish.
_If you enjoyed this post, more like it come out every four weeks! Follow [@TwoBitHistory][13] on Twitter or subscribe to the [RSS feed][14] to make sure you know when a new post is out._
_Previously on TwoBitHistory…_
> New post is up! I wrote about how to solve differential equations using an analog computer from the '30s mostly made out of gears. As a bonus there's even some stuff in here about how to aim very large artillery pieces.<https://t.co/fwswXymgZa>
>
> — TwoBitHistory (@TwoBitHistory) [April 6, 2020][15]
1. Roy Fielding. “Architectural Styles and the Design of Network-based Software Architectures,” 128. 2000. University of California, Irvine, PhD Dissertation, accessed June 28, 2020, <https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf>. [↩︎][16]
2. Fielding, 130. [↩︎][17]
3. Fielding distinguishes between software architectures and software architecture “styles.” REST is an architectural style that has an instantiation in the architecture of HTTP. [↩︎][18]
4. Fielding, 2. [↩︎][19]
5. Fielding, 15. [↩︎][20]
6. Fielding, 82. [↩︎][21]
7. Paul Krill. “Ruby on Rails 2.0 released for Web Apps,” InfoWorld. Dec 7, 2007, accessed June 28, 2020, <https://www.infoworld.com/article/2648925/ruby-on-rails-2-0-released-for-web-apps.html> [↩︎][22]
8. Fielding, 109. [↩︎][23]
--------------------------------------------------------------------------------
via: https://twobithistory.org/2020/06/28/rest.html
作者:[Two-Bit History][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://twobithistory.org
[b]: https://github.com/lujun9972
[1]: https://news.ycombinator.com/item?id=7201871
[2]: https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_2up.pdf
[3]: tmp.Ewi4FpMIg6#fn:1
[4]: tmp.Ewi4FpMIg6#fn:2
[5]: tmp.Ewi4FpMIg6#fn:3
[6]: tmp.Ewi4FpMIg6#fn:4
[7]: tmp.Ewi4FpMIg6#fn:5
[8]: tmp.Ewi4FpMIg6#fn:6
[9]: https://www.youtube.com/watch?v=vNoPJqm3DAY
[10]: tmp.Ewi4FpMIg6#fn:7
[11]: https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
[12]: tmp.Ewi4FpMIg6#fn:8
[13]: https://twitter.com/TwoBitHistory
[14]: https://twobithistory.org/feed.xml
[15]: https://twitter.com/TwoBitHistory/status/1247187881946275841?ref_src=twsrc%5Etfw
[16]: tmp.Ewi4FpMIg6#fnref:1
[17]: tmp.Ewi4FpMIg6#fnref:2
[18]: tmp.Ewi4FpMIg6#fnref:3
[19]: tmp.Ewi4FpMIg6#fnref:4
[20]: tmp.Ewi4FpMIg6#fnref:5
[21]: tmp.Ewi4FpMIg6#fnref:6
[22]: tmp.Ewi4FpMIg6#fnref:7
[23]: tmp.Ewi4FpMIg6#fnref:8

View File

@ -1,100 +1,94 @@
[#]: subject: "Open Source Software: Is There an Easy Path to Success?"
[#]: via: "https://www.opensourceforu.com/2022/07/open-source-software-is-there-an-easy-path-to-success/"
[#]: author: "Jules Graybill https://www.opensourceforu.com/author/jules-graybill/"
[#]: collector: "lkxed"
[#]: translator: " "
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
Open Source Software: Is There an Easy Path to Success?
======
Theres so much that goes on behind the scenes while developing open source software. So how does one make an open source project successful? Is there a shortcut? This article indicates there isnt one.
![team work working together][1]
Open source has become all the rage now. Many entrepreneurs are drawn to it by the allure of quick success. But the truth is, there is no easy path to such success. There is no one thing that you can do to get all of open source right.
In fact, a lot of the challenges that companies face early on are not technology challenges, but are people and cultural challenges.
There are many layers of open source that need to be worked on to build a project that can become a hit in the market. And maintaining that success is an ongoing process. But at the crux of it all lies finding the right answer to a very basic question: what exactly is open source?
### Open source is the code
For many new users who may not be fully aware of the layers that make open source, the answer is fairly simple: open source is software! And that is not wrong, of course, since that is how most of us are using it. But theres just so much more to open source than merely being touted as software.
The essence of any open source project still remains the code. It is what makes the project special and useful for the user. When youre working in open source, the code is just as much a part of the product as the software.
Developing a project from the ground up, or even creating a fork of an existing project, requires thousands and thousands of lines of code to be written, even while handling such a large and complex codebase. Especially in the case of creating a fork, care must be taken to remove any prior licences, marketing material, or anything that might not be useful for the user anymore. After all, it is the features of a project that attract its user base and what retains it. When end users are deciding whether to use open source software, they will read the source code, and what they see there should be something that builds their confidence.
### Open source is the community
How you engage with the community is also a part of the task of building a product. Building a community and maintaining a healthy relationship with it is one of the most crucial aspects of open source, but is also often the hardest for most leaders as there is very little one can do to control it. One can try to lay the foundation and can be supportive but, ultimately, its the people who decide whether they want to join a community.
It is important to maintain a level of transparency with the community and keep it in the loop. The community can get involved at any step that it wants to. Its really important that you show most of your work to the community while you are doing it, apart from things that need to be done confidentially, like setting up security, signing certificates, branding, and so on. This helps in winning its trust because, in the end, it is the community that you are liable to, and it can make or break your project. This may make the project work a lot more deliberate, slower and exposed, but it works well in the end.
Making your work-in-progress so open can seem daunting, especially when you are worried about the repercussions of a delay in updates or having a bug. Yet, making the community members privy to your moves will not only help you build a trustful relationship with them, but also make them feel appreciated.
However, making your workflow public will also invite scrutiny from the community members, who will often have their opinions and offer you their feedback. Taking note of this feedback is important, because that is how you can make your open source project truly for them. They are the end users and their feedback will reflect how they see your project panning out for them in the long run, and ultimately, how successful and mainstream your software becomes.
As an example, when we are thinking about a new feature, we publish a request for comments at RFC. We get a lot of feedback, and we have to think hard about how we can incorporate it.
Since open source is a largely collaborative work, there will be initiatives by the community to offer their support in making the project the best version possible. Not all of it will work out. But as long you are listening, the community will feel involved.
Engaging with the community has its pitfalls too. There may be differences of opinion within the community, and also between the maintainer and the community, especially when it comes to the matter of governance. Governance is something which is really important for an open source project to have. That is why it is important to have clear documented governance practices, which also include the community.
Community governance is a tough, but essential, nut to crack. Delegation in itself requires a lot of trust. For a project with millions of lines of code, it can be cumbersome to find someone in the community who can meaningfully lead it. But open source projects often consist of smaller sub-projects, which are better left handled by someone from the community. This helps the community to be more closely involved too.
| - |
| :- |
| Building a community always has its highs and lows. Let me list some of the tricks that helped maintain a healthy balance between the communitys and my teams vision.
State your principle: Especially in the early stage of the open source project when the source code is still coming together and things are not exactly going perfectly, it is hard for somebody coming from outside to really understand why you are making the decisions that you are making. Communicating the principles on which you take actions helps you to be upfront about your thought process so that the community does not interpret things incorrectly.
This practice is really helpful. It is also important to follow through and show that when you make a decision, it is guided by one of these principles.
Decide how you are going to collaborate: This may be through channels like Discord, Slack, or simply emails. But if you try to use all of them, you will immediately diffuse the community. People will be communicating with each other all over the place. Choose one or two collaboration tools, and really invest in them for synchronised communication.
Treasure the feedback: Listen to feedback from the community and act on it. Show tat you care about what the community says, even if it requires you to make tough decisions.
Maintain a code of conduct: If you interact with a community, you need to define what is going to be acceptable conduct. Having that in place helps warn people in case they go out of line. You can avoid a lot of trouble if you can just define this early on.
Think about how you will distribute your project: There may be instances when you may not be willing to make your project available to the public because you do not have a certain component in place, or you have features you may not want to make accessible to everyone. Creating distribution terms that suit your preference without compromising on what the user wants is key, so that people who want certain features can access these while those who can do without them also have the option to start using the project without having to compromise.
Avoid polls as much as you can: This is because, often, certain members vote for an option that may not be what the majority goes with. This can create a sense of failure in these members and make them feel excluded from the project. Instead, try asking them what problems they would like to be solved, and then try to invent a solution that does not involve trade-offs. |
**State your principle:** Especially in the early stage of the open source project when the source code is still coming together and things are not exactly going perfectly, it is hard for somebody coming from outside to really understand why you are making the decisions that you are making. Communicating the principles on which you take actions helps you to be upfront about your thought process so that the community does not interpret things incorrectly.
This practice is really helpful. It is also important to follow through and show that when you make a decision, it is guided by one of these principles.
*Decide how you are going to collaborate:* This may be through channels like Discord, Slack, or simply emails. But if you try to use all of them, you will immediately diffuse the community. People will be communicating with each other all over the place. Choose one or two collaboration tools, and really invest in them for synchronised communication.
*Treasure the feedback:* Listen to feedback from the community and act on it. Show tat you care about what the community says, even if it requires you to make tough decisions.
**Maintain a code of conduct:** If you interact with a community, you need to define what is going to be acceptable conduct. Having that in place helps warn people in case they go out of line. You can avoid a lot of trouble if you can just define this early on.
*Think about how you will distribute your project:* There may be instances when you may not be willing to make your project available to the public because you do not have a certain component in place, or you have features you may not want to make accessible to everyone. Creating distribution terms that suit your preference without compromising on what the user wants is key, so that people who want certain features can access these while those who can do without them also have the option to start using the project without having to compromise.
*Avoid polls as much as you can:* This is because, often, certain members vote for an option that may not be what the majority goes with. This can create a sense of failure in these members and make them feel excluded from the project. Instead, try asking them what problems they would like to be solved, and then try to invent a solution that does not involve trade-offs.
### Open source is licensing
Open source is about giving your users autonomy over how they want to use your software, and licensing provides just that. Whats great about an open source licence is that regardless of what you as a maintainer do, all your end users and stakeholders can always maintain a certain set of forks, which are important forks.
Licensing gives people the option to take the project into a different direction if they deem it fit. They have the right to create a fork, which results in a lot of amazing software being developed. Maintainers have more responsibility to listen to their community members and to run the project in a way that works for them.
Its advisable to make use of the many licences available instead of setting your own terms separately, simply because stakeholders and users are usually familiar with commonly used licences, so you do not have to waste time explaining them. This also helps you to focus your energy on the other parts of the project.
### Finally, open source is a movement
Open source involves many, many dimensions and people. Most importantly, it is about understanding what these people want and creating an environment that encourages collaboration and transparency. It is about building communities that help to build the open source project the way they want it to be. The more opportunity maintainers create to let them do that, the better the product is and the more successful it gets.
Open source is all of these things and the more expansive view you take, the better you can leverage it. Think about how you can excel in every dimension of open source because, at the end of the day, there is no easy path to open source success.
--------------------------------------------------------------------------------
via: https://www.opensourceforu.com/2022/07/open-source-software-is-there-an-easy-path-to-success/
作者:[Jules Graybill][a]
选题:[lkxed][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.opensourceforu.com/author/jules-graybill/
[b]: https://github.com/lkxed
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/07/team-work-working-together-1.jpg
[#]: subject: "Open Source Software: Is There an Easy Path to Success?"
[#]: via: "https://www.opensourceforu.com/2022/07/open-source-software-is-there-an-easy-path-to-success/"
[#]: author: "Jules Graybill https://www.opensourceforu.com/author/jules-graybill/"
[#]: collector: "lkxed"
[#]: translator: "CanYellow"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
开源软件:存在成功的捷径吗?
======
开发开源软件背后的工作是相当庞大的。那么我们如何保证开源项目的成功呢?存在捷径吗?本文认为是没有的。
![团队合作][1]
今天,开源已经风靡世界。很多大型企业在快速成功的诱惑下被推向开源。但真实情况是世界上并不存在成功的捷径。你无法做到通过一次努力就能让所有的开源项目正常运行。
事实上,上述公司早期遇到的许多挑战都不是技术上的,而是人员与文化上的。
开发一个能够在市场上获得成功的开源项目需要同不同层级(的开源社区人员)一同工作。维护这样的项目也是一个持续的过程。所有这一切的关键在于找到以下这个非常基础的问题的正确答案:开源究竟是什么。
### 开源是代码
对于很多没有深刻认识到构成开源的不同层级(的开源社区人员)用户而言,答案相当简单:开源就是软件!这当然没有错,毕竟这就是我们多数人如何使用它的。不过,相比仅仅被视作软件而言,开源远不止这些。
任何开源项目的实质仍然是代码本身。代码是使一个开源项目有别于其他项目并使其对用户有益的根本。当你在开源中工作的时候,代码和软件一样都是产品自身的一部分。
从零开始开发一个(开源)项目或者复刻(fork)一个现有项目的分支,即便是在处理如此庞大而复杂的代码库时,也需要编写成千上万行代码。尤其是在创新一个现有项目的分支的情况下,在移除任何在先的许可证、宣传材料或者其他任何可能已经失去作用的文件时必须小心翼翼。终究是一个项目的功能吸引了它的用户群并维持项目的持续发展。当终端用户在考虑是否使用开源软件的时候,他们会阅读项目的源代码,而他们在其中所看到的应当是那些能够建立他们的信心的内容。
### 开源是社区
如何参与到社区中也是产品构建项目的一部分。创建一个社区并维护一个健康的社区关系是开源的核心之一,但对于大部分的领导者而言也往往是最坚难的任务,很少有人能很好地维护它。你可以尝试建立基金会或者提供赞助,但是最终还是人们自行决定是否想要加入社区。
维护一定程度的社区透明度并不断保持也是重要的。社区可以随心所欲地参与项目。除了需要秘密进行的工作之外,诸如安全设置、签发证书、注册商标等,尽可能多的将你所做的工作展示给社区是相当重要的,这有助于取得社区信任。你终究需要对社区负责,你的项目成也社区,败也社区。这可能会导致你的项目开发更谨慎、更缓慢并且向社区公开,不过项目最终会进展顺利。
如此地公开你正在进行的工作似乎有些令人生怯,尤其是当你担心更新推迟或者是出现漏洞的影响的时候。不过,让社区成员知悉你的进展不仅有助帮助你建立与社区之间的信任关系,而且能够让社区成员感到被认可。
另一方面,公开你的工作流也可以获得来自社区成员的监督,他们经常有自己的见解并向你反馈。记录这些反馈是很重要的,这使得你的开源项目如实地反映社区需求。他们是项目的末端用户,而他们的反馈则反映了他们如何看待你的项目的长期发展以及你的项目最终将有多么成功或者主流。
举例而言,当我们在考虑一个新功能的时候,我们在征求意见文档(RFC, Request for Comments)中发布一个征集意见的请求,我们会收到大量的反馈,我们必须认真思考应当如何吸收这些反馈。
因为开源是一个大型的合作项目,社区在支持开源项目成为可能的万里挑一的项目上享有主动权。并非所有的问题都要解决,但只要你有在倾听社区的呼声,社区就会有参与感。
参与到社区中也存在一些隐患。社区内部、项目维护与社区之间均可能存在不同意见,尤其是在涉及管理问题上。管理问题对于一个开源项目来说是相当重要的。这也就是为什么拥有一份清晰的文档化的管理条例对于项目以及社区均是如此重要。
社区管理是一个关键的而又难啃的骨头。社区授权本身需要相当大的信任。对于一个拥有成千上万行代码的项目,在社区中寻找能够有效领导社区的人物是不容易的。不过开源项目经常是由更小的子项目组成的,这些子项目最好由社区中的某个人进行管理。这有助于社区更紧密地参与到项目中。
| - |
| :- |
| 建立社区的过程不是一帆风顺的。让我列举一一些有助于维持社区与我的团队之间平衡的技巧。
**声明你的原则:**尤其是在开源项目的早期,在项目代码仍在完善,很多事情还不完美的时候,项目之外的人员很难真正理解你所做的决定。向他们说明你做出决定所依据的原则有助于你在思考过程上保持坦率,从而让社区不会错误地干扰你的事务。
这一经验非常有效,在你做出决定时坚持遵循其中一项原则并展示出来是非常重要的。
*确定如何进行协作:*你可以通过Discord、Slack或者邮件等途径完成这一工作。但是如果你试图同时使用他们你将毫不意外的分散项目社区。社区人员将在所有这些途径上互相交流。选择一到两种沟通工具投身于他们来保证社区的信息同步。
*珍惜反馈意见:*倾听来自社区的反馈并付诸行动。即使需要你作出艰难的决定,你也应当向社区展示你是重视社区话语的。
**维护一套行为准则:**如果你与社区打交道,你需要定义什么行为是可以接受的。一套落地的行为准则有助于在人们越过红线时警示他们。如果你可以提前制定这些你可以避免很多麻烦。
*考虑如何分发你的项目:*存在这样的情况,因为你还没有准备好某一个组件,或者是因为存在一些项目功能你不希望所有人都能够访问,所以你可能并不希望将你的项目完全向公众公开。关键是制定符合你的要求而不是向用户妥协的分发条款,如此,需要某种功能的用户可以获取所需项目的同时不需要该功能的用户也不需要做出妥协而开始使用该项目。
*尽可能地避免投票:*这是因为部分成员经常会赞成与大部分成员的意见相左的选项,这会使这些人产生一定程度的失望,并让他们觉得被项目所孤立。反之,尽量尝试询问他们想要解决什么问题,并尝试创造一个不需要付出代价的解决方案。
### 开源是许可
开源是给予你的用户如何使用你的软件的自由,而许可能够做到这一点。一个开源项目许可是极好的,它保证了不论你作为维护者做了什么,你的所有终端用户以及利益相关方总是可以维护一系列的项目复刻版本,这些都是重要的项目复刻版。
许可提供了人们可选择性,如果他们认为有必要,他们可以将项目复制到不同的路径中。他们拥有创建副本的权利,这使得许多优秀的软件能够被开发出来。维护者有责任倾听他们的社区成员的声音并以一个对项目的社区成员有利的方式运营项目。
我们推荐使用现有的许多可用的许可证而不是独立制作你自己的许可条款,仅仅只是因为用户以及利益相关方通常都很熟悉公共许可证,因此你不需要再花费时间在解释许可条款上。这将帮助你将你的精力集中在项目的其他部分上。
### 最后,开源是一项运动
开源包括了很多维度,也包含了很多人员。最重要的是,它是有关理解人们想要什么的,也是有关创建一个鼓励协作与透明的环境的。开源也是有关创建有利于开源项目走自己想走的道路的社区的。维护者创造越多的机会让社区自由发挥,开源产品就越好,也越发成功。
开源是以上这些方面,而你的视野越宽阔,你就能越好的利用它。请考虑你如何能够在开源的每一个维度上出类拔萃,因为时至今日,开源的成功之路并无捷径。
--------------------------------------------------------------------------------
via: https://www.opensourceforu.com/2022/07/open-source-software-is-there-an-easy-path-to-success/
作者:[Jules Graybill][a]
选题:[lkxed][b]
译者:[CanYellow](https://github.com/CanYellow)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.opensourceforu.com/author/jules-graybill/
[b]: https://github.com/lkxed
[1]: https://www.opensourceforu.com/wp-content/uploads/2022/07/team-work-working-together-1.jpg