The Workshop: Producing Packages (Part 3) - php[architect] Magazine December 2018

Joe • September 3, 2020

learning packages phparch writing php

Warning:

This post content may not be current, please double check the official documentation as needed.

This post may also be in an unedited form with grammatical or spelling mistakes, purchase the December 2018 issue from http://phparch.com for the professionally edited version.

The Workshop: Producing Packages (Part Three)

by Joe Ferguson

Over the past two months we've been building PHP Easy Math a purposely simple example library to demonstrate how to build a reusable package for the PHP ecosystem. Make sure to check the previous issues if you're just now joining us! This will be the third and final installment in this series. This month we're going to cover triaging and managing issues users may open as well as pull requests to your library.

How to Triage Issues

Issues are the primary way your library users will communicate their needs and problems to you. It is your responsibility to answer each issue promptly with respect and tact. Always assume the issue author is well-intentioned; if you find yourself typing in all capitals, maybe you should step away for a bit before answering the issue. While you don't have to address every single issue and you shouldn't feel beholden to users for free tech support, I always try to respond to issues even if it's to let the author know it's not something I can help.

I try to triage issues as they come in depending on what I’m working on. If they come in during normal day job hours or if I know I won’t be able to investigate in a timely manner I will often post a comment acknowledging I see the issue and give a timeframe of when I expect to be able to investigate. This is a great way to show your users you care about their issues and will make time to investigate.

Step 1: Review The Issue

Read through the entirety of the issue and try not to make assumptions or guess the solution. If the author has included steps to reproduce, give them a try and see if you can reproduce the issue too.

If the issue is a duplicate, or if the author is clearly doing something wrong, be tactful in your response. Link the user (in a peaceful tone) to the related issues. Don't reply with a “let me google that for you" link; it’s not 2001 anymore, and you shouldn’t be a jerk.

Step Two: Acknowledge and Document

If you’re able to reproduce the issue, let the user know and start documenting your debug process. I typically do this in the issue comments so it’s easy to refer to the context of the debugging or research. This may include testing different versions, compatibilities, operating systems, etc. Be thorough and patient during this process. Communicate with the author to ensure you're both on the same page and talking about the same things.

Research any error messages. Even if the problem isn’t your libraries fault it may be helpful to other users who may run into the same thing. If you do find the issue is not with your package and is caused by another package, comment and update the author to let them know. Share links to related issues and don’t be afraid to open an issue on the upstream repo if there isn’t already one open.

Resolution

If the issue can be resolved, let the author know the timeline of when they can expect you to fix it. Don’t be afraid to use tags on Github and mark the issue “Needs Fixing” or “Help Wanted” to encourage others to try to contribute a fix. This is a great way to drive engagement in your open source project. I always like to inform the user when they can expect to see a change (e.g., the next release, the next month when a release is scheduled, or some other timeframe due to whatever reasons may exist).

If you can’t fix the issue for whatever reason, explain your reasoning and close the issue. Closing the issue isn’t the end, users can still comment on closed issues but don’t close an issue until you’re ready. I only close issues when I’ve exhausted all known options, checked with other developers for an option, or otherwise have expended all ideas for resolution.

Issue Templates

If you have a common set of questions you need an issue author to answer, you may want to consider using GitHub (issue and pull request templates. These templates can display information for the user to fill out such as PHP version, operating system, library version, etc. so you can get a better idea of the circumstances and environment on which they’re experiencing the issue. You can also use pull request templates to do similar things like provide a workflow checklist for the pull request author to fill out to show they've followed your established workflow.

In the Laravel Homestead repository, I leverage issue templates to collect several data points from users such as:

  • Vagrant version
  • Homestead version
  • Vagrant provider version
  • logs of commands and expected results and actual results

This allows me to easily skim through issues and quickly identify version incompatibilities, common known issues with providers or environments, and any other issue I may be able to easily spot.

We can add an issue template for our library by creating the following file in our repository: .github/ISSUE_TEMPLATE.md. Our ISSUE_TEMPLATE.md file is a simple text file in Markdown format which will be displayed to the user when they are opening a new issue. They don’t have to copy and paste anything; they just have to fill out the template and submit.

Sometimes users will disregard your template and write out their issues. It may be difficult to be patient with users like this. I will often close their issue and politely request they follow the issue template to describe their problem fully. I’ve never had a case where a legitimate user refused to fill out a template. Maybe I’m just lucky? Always assume the user on the other end has good intentions. You can’t hear the emotion and inflection in their voice from reading their written words. Try not to read into what the user is saying. Instead, assume the best, but prepare for the worst.

Dealing With Pull Requests

Since we're working on open source code, at some point someone may want to send us a pull request. A pull request is a formal change request to merge changes from another branch or another branch on someone else's copy of your repo (also known as a fork). It is our responsibility as open source maintainers to review and give feedback on pull requests. If the pull request adds some great new feature, it's free code for us! If the pull request is changing a lot of code, we should be tactful and supportive in our feedback. Always provide constructive criticism. Don't tell anyone what they did wrong, tell them what they could do better.

In Part One of this series we wired up Travis-CI to run our tests every time we pushed a commit and when someone opens a pull request. Travis becomes our pull request gatekeeper. If the changes we are reviewing in the pull request cause the tests to fail, we know there is a problem. The problem could be the incoming pull request fixes a bug and we need to add or update our tests. The problem could also be the user didn't update the tests when they made the change. Another possible scenario is the user's change broke something the existing tests caught. When this happens, you should give the user some feedback on how to fix their code or how to update the tests (if it's not clearly evident).

Always encourage contributors to fix, add, and update tests in addition to the other code changes they have made. We don't need to be strict about this. After all, they are doing us a favor by contributing their time and code to our project. If the tests all pass and the contributor has added new tests to cover any functionality they have added we’re in good shape! If the contributor has not added tests and they have added functionality we should gently ask them to add supporting tests. If they reply with, “I don’t know how” please go easy on them! Everyone learns at their own rate. If you have the time, help them through adding tests. If they are not receptive or just stop replying, consider accepting the change as is and adding the tests yourself.

No matter the outcome of the pull request always take the time it takes to type out “Thanks for opening this pull request” or “thanks for your time working on this.” Always remember someone else took the time to work on your library. They are doing you a favor (hopefully).

Acceptance Checklist

The things I like to check for in any pull request are listed here.

Do I want this change?

Is this change something which gives the library more functionality? Does it fit with what the rest of the package does? Does it make sense? If it adds dependencies, do they make sense, are they up to date, and actively maintained?

Do the Tests Pass?

Did the author add or remove tests based on their changes? Spot check to make sure the author wrote all the necessary tests to ensure the new feature tested with successful conditions as well as proving the failure is handled as expected. At the same time, look at the code style of the new code, does it follow the established style guide? If not, we can always default to checking if the code is PSR-2 compliant.

What Feedback Do I Have for the Author?

GitHub has a fantastic review system for pull requests. You can also request a review from someone in the organization if you’d like. I’m trying to get in the habit of using this feature as the final outcomes are "Approve", "Request Changes", and "Comment" which give the author a good sense of what needs to be done (if anything).

This is where you can easily request the author change functionality, add test cases, or further discuss what you’d rather see. Feel free to add simple comments or discuss changes inline---the review system is quite helpful for both sides of the pull request.

If you are using Bitbucket or GitLab, make sure you comment inline or as regular comments on the pull request.

Handling a PR You Want

Pull requests you want are easy to handle. By this point, we’ve already ensured the tests are passing, and the author has added tests as needed. Depending on how large the pull request is you may want to pull down the changes to look at them on your own system in your own editor. To do so, we can run two commands to checkout the code:

git checkout -b reviewing-feature master
git pull git@github.com:svpernova09/php-easy-math.git reviewing-feature

Now we have a new branch reviewing-feature in our local folder with all of the changes. From here we can test to our heart's content.

Handling a PR You Don't Want

The pull request you don’t want is always harder than ones you want. You want to be respectful of the author for taking the time to make changes to your code. We want to always ensure we understand where the author is coming from so we can understand why they think the change is needed. You don’t have to become their best friend but make sure you spend enough time to wrap your head around what they want to be able to do. If what they want just doesn’t fit into your defined scope simply let the user know. Remember to be tactful and respectful with your comments.

Closing the pull request without merging is like a door slamming shut; try to close the door as gently as you can. No one enjoys rejection, but unfortunately closing pull requests once they’ve been determined they are no longer needed is part of the job as an open source maintainer. There can be multiple reasons: the change wasn’t wanted/needed, another author beat them to the punch and solved the issue in a better way, or something else. Regardless, remember to have empathy and respect when commenting on why you’re closing the pull request without merging.

Last Steps for Pull Requests

Once we’re happy with the changes, we can hit the big merge button! Make sure to thank the contributor for their time! Now we have changes in our master branch. They haven’t been tagged in a release, so we need to tag a new release.

Tagging New Releases

Tagging new releases is how you communicate to your users what has changed from one release to the next. In this context, releases can also be called versions which is another popular way to reference a release. The de facto standard for how we number our releases is to use Semantic Versioning where we have a version separated with two decimals. The decimals represent major, minor, and patch versions in that order. So a 1.2.5 release indicates major version 1, minor version 2, and patch version 5. This tells our users anyone currently running 1.2.x should be safe to upgrade without breaking anything. Users who are currently using 1.x.x can see the new release has a few minor changes they may need to review. If we have any users using 0.x.x then the 1.2.5 tells them there are breaking changes from their current version and likely will need to update their application to support our new version.

The guide I like to use when determining what my next version number will be is somewhat straightforward but can still be subjective. I will always choose to bump a minor version even if I’m not sure it’s justified. If there are changes to files in the repository that don't affect how my library functions, such as updating a README or another such file I will bump the patch version because this new 1.2.5 release will not break anything in 1.2.5 (or anything in 1.2). If we update logic somewhere in our library or change currently set behavior, I would bump the minor version to indicate there is a small change users of the library should investigate before upgrading. Never tag a minor release which has a backward compatible breaking change. Major versions are exactly what you want to bump when adding breaking changes.

Further simplifying the “what is our new version going to be” question, we can think about it in the context of our library users. We’re tagging 1.2.5, but if we have logic changes, we should probably bump the minor version so the release would be 1.3.0. If we added features but didn’t change anything else, we would also bump the minor version to indicate there has been a meaningful change to the functionality. Finally, when we have huge changes, bump up the minimum PHP version we support, or break backward compatibility, we’ll bump the major version to 2.0.0. This allows us to correct past mistakes while keeping the library in a usable state for any of our existing users while allowing them to understand how our library's version will affect their application.

Tagging releases is an important aspect of maintaining an open source library. It’s our job to ensure our users have a stable, tested version to use and they are clear on changes based on our use of Semantic Versioning in our releases.

Recap

I have thoroughly enjoyed writing this three post series on producing packages. I hope you have found it valuable and useful in your own PHP libraries and packages.

Warning:

This post content may not be current, please double check the official documentation as needed.

This post may also be in an unedited form with grammatical or spelling mistakes, purchase the December 2018 issue from http://phparch.com for the professionally edited version.