Authoring and sharing a package is a relatively simple activity these days. Systems like GitHub and npm make it easy for an author to share and publish their work. This is a great thing; it is a wonderful time to be a developer and involved in a developer community.

However, there is a cost to sharing and releasing one’s code that is often unwritten and overlooked. Authors may feel like they are sharing their grand ideas with the world, but they often fail to understand the expectations that go along with publishing a package. Likewise, users think that they can just download a package in an all-you-can-eat buffet of open source software, never realizing that the very success of the package they are downloading requires them to participate in the community of that package. Both sides have responsibilities in the situation and for either side to ignore those responsibilities is a recipe for failure.

Several months ago the JavaScript community dealt with this very problem. A highly respected package author, had shared a package (event-stream) he wrote for fun and it got very popular. As is the case, popularity came with more requests for support and bug fixes. In short order requests became demands, and the author’s time and interest lagged. All the while, very few users where willing to step up and help. So when someone did step up and help, the author accepted and turned over the repository. Shortly thereafter malicious code was introduced into the package and everyone who relied on the package became an potential victim.

In many ways event-stream was a kind of “perfect storm” event that may be unlikely to occur again. Yet, the event-stream saga is a very real example of the cost of publishing code for others to use. Some would blame the author for not providing a better notification that he was handing the package off to someone else. Others would blame the users for not supporting the package either financially or through participation. Still others would point out that this is a professional community and as a professional one is required to know and understand how their software works and the systems it relies upon work. Yet, no matter how we throw the blame around, the reality is everyone paid the price for the failure, and everyone (the author, the users, and the greater community) is culpable.

A dependency, a package, is more than software; it is a relationship. Like all relationships, it comes with a set of expectations between the parties involved: party A in a relationship expects certain things of party B, and in turn party B expects certain things of party A. When either side fails to live up to those expectations that is when the relationship degrades and fails and people get frustrated, hurt, and betrayed.

Consider what one expects when downloading a software package:

  • Function: The user of a package expects that when a package is given X, it will return Y. This is the expectation by the user that a package will work and that it will meet their needs. Occasionally a package fails to work or meet the needs of the user, at which point they uninstall it and the relationship is over.
  • Constraint: The user of a package expects that a package is constrained to doing only what it is intended and described to do and nothing more. That is, the user expects a package to not do other things whether malicious or not.
  • Support: The user of a package expects the author of a package to provide some level of support. This includes well written documentation, responsive bug fixes, avenues of communication, and the addition of new features.
  • Notification: The user of a package expects to be informed when the package changes, how it changes, and why those changes were introduced. Notification allows the author to communicate with the users directly.

But what a lot of people overlook is the other side of the relationship having its own expectations:

  • Feedback: The author of a package expects that the user of a package will report issues with the package. One can never predict all of the edge cases where code may have problems. The author is dependent on the user providing the details about where those edges are and where they fail.
  • Reciprocity: The author of a package expects that the user of a package will help maintain and grow the package. This is a critical part of the open source equation: that everyone shares in the maintenance and growth of the package for the betterment of all. Without this participation most packages languish and die.
  • License: The author of a package expects that the user of the package will use that package in accordance with the licensing terms. The license is an expression of the legal wishes of the author, but the author lacks little ability to enforce such things. Instead, the author relies upon the relationship with the user to encourage these legal wishes.

When any one of these expectations from either side is broken the relationship is strained. Some times that strain can be minor and survivable, but often it can be completely destructive. In the case of the event-stream story from above, the users failed to fulfill the Reciprocity expectation which in turn caused a snowball effect causing other expectations to fail, which eventually led to critical failure of the entire package.

So how does one address these problems? How do the authors and users of a package prevent failures from occurring in the future? How does one ensure that the participants in our communities get what they need to not just survive but thrive as part of the community?

It begins by recognizing that there is still much work to be done on the systems in use and how the community uses those systems. Now, many of the tools at the disposal of package authors are geared toward providing and maintaining some of the expectations outlined above. GitHub, for example, can be said to be helpful in some of these expectations, but lacking (whether intentionally or not) in many of them. Certainly it enables the Support, Feedback, and Reciprocity expectations, but there is still much room for improvement.

While stronger more supportive systems and tools will help address some of the community problems, one must also be willing to examine and address the individual and community aspects as well. In many ways, the current situation in which the community finds itself is a function of getting better tools without considering the social engineering those tools also require. So any solution must also examine the people involved.

The authors need to to understand that releasing software is not a “fire and forget” situation and that the users have expectations of the package and its author. There must be a realization that by sharing code with the world, one is creating a community that requires nurturing to grow and thrive. When we publish our code with GitHub it is no accident that you immediately get an Issues tab and a Wiki tab. These are the author’s tools to build a community. And as the author one must be ready to accept that they are the leader of this community. That means meeting the expectations of that community to the best of your ability: maintaining the software, ensuring it is safe to use, supporting it as needed, and updating your users about changes.

However, nobody is suggesting that sharing code automatically dictates a lifetime of servitude. Authors must have the tools and community support necessary to lead within the confines of their time commitments. Part of nurturing and enabling a community is knowing how to ask for and accept help when it gets overwhelming and how to apprise your community about the situation.

Yet the author is not alone in this package relationship: the users bear an even greater obligation to the relationship. Every time a user downloads a new package and does not find some way to participate that user is helping to contribute to that package’s failure. It sounds harsh, but one cannot continue to treat open source software as a free ride and expect to suffer zero consequences.

The manner in which a user contributes back to an open source project comes down to two possible actions: time or money. A user can donate time by helping to improve and grow the project: opening detailed issues reports, submitting pull requests which fix bugs or add features, improving documentation, offering support to newer users, helping to lead the project, all of these activities take time from the user and give it to the author to help in the project. Time is the most critical thing an author needs to maintain a project. However, if time cannot be found or is prohibited or prevented by one’s employer, consider donating money or asking the company to step up and donate money. This can be tricky for some projects as questions about who gets the money, taxes, etc come into play. However, if there is an avenue to donate, please use it. If not consider asking the project to add one. Also, for some projects it is possible to buy advanced licenses or support agreements and this can be considered as method of getting money into the project.

Ultimately a package is only as strong as both the author and its users make it. It is incumbent upon both sides of the author/user relationship to commit to their expectations. Anything less is setting oneself up for failure. The event-stream incident is a lesson from which current and future packages can learn. The users share as much, maybe even more, culpability as the author does. An unwillingness to see that is an indicator of a willingness to fail again. And the big failure of event-stream is not that malicious code got injected, it is that no one will learn from it.

Supporting materials and further reading: