00:00:14.530
All right, what's up everyone? How's it going? So, who among you has ever released a Ruby gem? Okay, good, I like it. Now, who has released a popular gem with tons of contributors, users, and lots of love? Okay, all right. So, today we want to get from Group 1 to Group 2, and everyone is welcome to join us. Before we get started, a quick introduction: my name is Mat Brown, and if you want to tweet insults at me, that's fine. I live in Brooklyn, and I work for Genius, a platform for annotations. One time, John Resig used our platform, and it was really cool. Here's my talk.
00:00:41.150
We will discuss seven specific things that will make your gem more appealing and ensure your users are happy. Of course, this is a Ruby conference, so we'll talk about how to get users up and running quickly. We'll cover writing good documentation, changing your gem without causing pain to users' applications, coexisting with users' application environments, and how abstractions can lock people in and how to prevent that.
00:01:08.540
We'll also discuss making it easier on your contributors by providing an easy-to-run test suite and giving them automatic feedback on their contributions. Let's start with Quick Start. Take Sinatra as an example. It’s a fantastic gem; arguably the best micro-framework out there. The top of the Sinatra README features a quick start that is only four lines long.
00:01:49.370
This four-line setup includes the Ruby installation command, which doesn’t even count as code. You type one line into your shell, and you're good to go. This is what we should all aspire to. Everyone expects a quick start this easy. Programmers aren't asking for it because they aren't smart or are lazy; they want to spend their time building beautiful, functional, wonderful products instead of installing and configuring things.
00:02:20.640
So, having a really short and effective quick start is actually a feature of your code, not just your README. You can't create a short quick start unless your gem allows it. So how do we achieve that? Think about how we usually write a gem. When working on an application, we might have some code that we think should be open sourced, believing it would be useful to others.
00:02:46.400
We take some code, create a directory for our gem, and probably point to the local version of the gem in our application's Gemfile. While developing it, we might write some tests and documentation, then go back to our application to check compatibility. However, I never feel what it's like to use the gem from scratch in a fresh application. Something that has worked well for me is creating an example app.
00:03:32.160
It doesn’t have to be a Rails app; just something that makes sense for the problem you're solving. Consider how it feels if I wanted to use this gem for a plausible use case. I always find at least one pain point that I can solve to make getting started using this technique easier.
00:04:05.040
The key is to put yourself in the position of a new user. Once they start using it, they will want to learn more and easily find everything your gem has to offer. That’s where documentation comes in. Returning to Sinatra, not only does it have a great quick start, but scrolling down shows that the README is incredibly detailed.
00:04:29.230
A long README is very beneficial because there's no better place for documentation than the README itself. It's prominently displayed on GitHub. Also, when you generate code documentation, it is often included with the gem, allowing access without the internet. The README is crucial for laying out a map of what your gem is capable of.
00:05:09.170
To ensure that it accomplishes this, I recommend making the README part of your development process, just like writing tests. You wouldn’t submit a pull request or even make a commit containing new code without including new tests.
00:05:39.440
You can extend this further: whenever you add something new to your application, also add corresponding information in the README. Think about how you're going to explain this to your users before you lay down any tests or code.
00:06:07.880
Every feature of your gem should appear in the README, making it searchable so users can navigate it effectively. However, keep in mind that the README cannot be exhaustive. It can't cover every method or option; that’s where inline code documentation becomes essential.
00:06:53.260
For example, the Addressable gem uses Yard, a documentation tool, to structure Ruby code documentation more effectively than the built-in Ruby documentation. Yard enhances the potential for communication about how our code works. It provides a way to specify expectations about arguments and return types, generating clear documentation that communicates these requirements.
00:07:43.770
Yard includes various tags, such as the API tag, allowing us to specify the visibility of methods, marking deprecated methods with a single line. This tool ensures that our documentation is accurate and can even give more authority to the documentation than the code itself. Additionally, Ruby Doc Info hosts free documentation for Ruby projects, enhancing the usability of gems by automatically pulling documentation from your code and it’s quite beneficial.
00:08:51.600
However, we must also ensure that our gems do not cause unpleasant surprises. Users should not fear potential issues from upgrading to a new version of your gem. A primary means of conveying versioning information is by using semantic versioning, which divides version numbers into three parts.
00:09:20.620
The basic idea is that bumping the patch level signifies bug fixes that do not change any outward-facing behavior, meaning users can safely upgrade without worry. Bumping the minor version indicates that something new has been added without breaking existing functionality. Finally, the major version signifies a breaking change that requires a careful approach to upgrading.
00:09:53.470
As developers, we sometimes focus too much on our improvements and not enough on our users' experience. Aiming to design a beautiful interface might lead to breaking existing ones, causing unnecessary pain for your users. We can learn from JavaScript, where the community chose to always support old versions of existing code in future versions, introducing a new keyword rather than breaking the past.
00:10:35.420
This way, the JavaScript community ensures that all previous versions of code continue to work, supporting users who have invested in older interfaces. In thinking about the environment in which our gems exist, we need to play nice with other libraries.
00:11:16.460
Most gems have at least one dependency, which is Ruby itself, and they may also depend on other gems, making it critical to manage these dependencies thoughtfully. In our gemspec, we should specify version dependencies but aim for loose constraints to avoid locking users into specific versions.
00:11:50.900
Instead of demanding an exact version of a library like Active Support, we can use a broader versioning strategy that allows for safe upgrades, thus creating a better experience for users who may not be able or willing to stay on the latest versions.
00:12:31.770
Employing tools like Gymnasium can help audit your gems’ dependencies and notify you when they are out of date, making it easier to ensure compatibility moving forward. However, even if you say you support many versions, it’s crucial that you confirm that your gem operates correctly with all of them.
00:13:14.070
You will want to run tests against all the versions of Ruby and other core dependencies your gem claims to support. Travis is an excellent tool for this, providing seamless integration with GitHub, automatic testing of your code against various Ruby versions and forks, and ensuring your gem works across different environments.
00:14:47.190
Furthermore, maintaining robust test coverage across different versions is crucial, and the Appraisal gem helps you achieve that by allowing you to define a variety of gem dependency configurations to be tested automatically. This ensures that any changes or updates to your gem do not inadvertently break compatibility.
00:15:27.990
Next, let's consider the user experience in social networks, like Twitter and Facebook, which have great gems developed for interacting with their APIs. The public interface we create in our gems is what users expect to work with, and we should ensure it reflects the actual functionality.
00:15:56.550
For instance, while the Twitter gem provides a method to update tweets, if a new feature is introduced, such as 'poking,' it might not yet be supported. Users might want to access lower-level methods, yet the gem's private methods must remain hidden from users to avoid any inconsistency.
00:16:41.460
Alternatively, gems can be designed with a lower-level API as a stable foundation, building higher-level functionality on top of it. This layered architecture allows you to provide flexibility and robustness to your users, enabling them to create more complex calls when needed.
00:17:12.430
The quick start guides your users just as the test suite guides your contributors. If contributors cannot run the tests easily, they will likely become frustrated and not contribute back to your project. Therefore, ensuring that your test suite is easy to run is vital for encouraging contributions.
00:17:54.410
Utilizing tools like Bundler can greatly simplify the testing process, allowing you to manage testing dependencies effectively. If you rely on external services such as PostgreSQL, consider using Vagrant, which helps provide a consistent test environment for potential contributors.
00:19:01.130
However, being able to run tests is only one part; you also want to ensure contributors can write code that adheres to your style guidelines. Tools like RuboCop can help in setting style rules, providing automatic linting, and giving contributors non-confrontational feedback about code style.
00:19:40.750
By integrating RuboCop into your project, you can remove personal biases regarding code style from the feedback process. This helps maintain a consistent style across your project without subjective judgments from the maintainers. Just remember that setting up clear guidelines and using such automation tools can greatly enhance the quality and cooperation around contributions.
00:20:44.200
In conclusion, recap the key points: write a gem with a really short and effective quick start; develop an extensive README; utilize tools like Yard for code documentation; avoid breaking changes whenever possible; leverage semantic versioning to communicate effectively with your users.
00:21:56.280
Ensure that your gem supports older versions whenever applicable, keeping an eye on updates through tools like Gymnasium, and continuously run tests across various supported versions utilizing Travis. Remember to avoid locking users into specific abstractions whenever possible.
00:23:18.160
Consider providing both high-level and low-level APIs to accommodate different use cases. Make it simpler for contributors to run your test suite by leveraging tools like Bundler and Vagrant. Finally, use RuboCop to ensure non-confrontational feedback on style issues.
00:25:04.360
Now, let’s address some questions. The first question is regarding the use of RuboCop. I appreciate the feedback. Another question is about creating a contributing document, which is indeed a great idea. You can create a file named CONTRIBUTING.md, and GitHub will automatically link to it in pull request submission forms.
00:25:59.360
When it comes to the choice of license, I would suggest MIT, as it's a very standard choice that most developers are familiar with. Avoid multiple license types in your gems to prevent confusion. If you are publicizing a gem, consider platforms like Ruby Flow, Hacker News, and subreddit communities related to Ruby.
00:27:35.280
When it comes to versioning, I recommend starting with a version like 0.0.1 during initial development. After that, when you are ready to go live, feel free to release it as 1.0.0. If you support newer versions like Rails 5, assess whether it's a patch level or minor upgrade based on changes made—this helps in maintaining clarity for users.
00:28:53.240
Finally, if you decide to use someone else's namespace in your gem, maintain that convention. Underscored names convention is preferred for Ruby files, whereas dashes are typically better suited for defining namespacing in gem files.
00:30:25.760
Indeed, it can be a bit wild west regarding naming conventions, so tread carefully. If you must test compatibility with different dependencies, tools like Appraisal can help list the versions to check against and collect results in a methodical way.
00:30:47.240
When integrating your gem with Rails, it is genuine to create a full Rails app just for testing purposes, especially if there are view-level helpers involved, as that simulates the actual environment.
00:31:00.540
Above all, remember that keeping your gem flexible, well-documented, and easy to contribute to is essential for long-term use and community health.