Lessons Learned on GSoC 2019
Opening a Pull Request for Rubygems, a part of the Ruby language seemed like a terrifying thing to me. Like, all my code could be running on everyone elseās machines someday. What if I introduced a security bug? Although Iāve been contributing to open source projects since 2016, these thoughts kept on my mind.
It turns out that it was an extremely great experience. My code wasnāt āperfectā (if such thing exists), and I made a lot of mistakes, but Iāve learned so many things in the process that really worth it!
Well, I guess it's just the "No pain, No gain" rule. =)
Lessons Learned
Hereās some advice, so we (yes, Iām included) can avoid these mistakes in the future:
1. Keep It Simple Stupid
In case you didnāt know, KISS is a āreal thingā, not just a cool expression that I used
Well, well, well⦠Itās here where things get embarrassing (to me). As developers, we tend to overestimate the problems we have, and this leads to overcomplicated solutions. This problem showed up on the initial code of my PR for Rubygems.
I wasnāt fully aware of what every piece of gem-web did, so I tried to modify it as little as possible. Gem-web uses Rspec for testing, while Rubygems goes with Minitest. I knew I would have to update all the tests, but one thing I kept was (almost) all development dependencies.
So, when I opened the PR the gemspec of rubygems looked like this:
+ s.add_dependency(%q<launchy>, ["~> 2.4.3"])
+ s.add_development_dependency(%q<mocha>, ["~> 1.7.0"])
+ s.add_development_dependency(%q<webmock>, ["~> 3.5.1"])
+ s.add_development_dependency(%q<vcr>, ["~> 4.0.0"])
So, Iāve not only added three new development dependencies (mocha, webmock, and vcr), but also a RUNTIME one (launchy). This is especially bad because the PR target is part of a programming language!
As my mentor pointed out, the good old (and already added) Minitest could replace all of those test-related dependencies.
I know that those gems exist for a reason, and you (like I do) could like mochaās style rather than minitestās, but if you want to increase the chances of you PR being merged, itās a good practice not to add a bunch of dependencies.
Now I had to get rid of Launchy (which was used to open the URLs on usersā browser automatically). My first take on this was to create a hash with ALL THE POSSIBLE platforms that ruby could be running on and a method to open the default browser of it (Iām a genius).
OPEN_BROWSER_CMDS = {
aix: "defaultbrowser",
cygwin: "cygstart",
darwin: "open",
macruby: "open",
freebsd: "xdg-open",
# FIXME: What to do?
# hpux: "",
# java: "",
# dalvik: "",
# dotnet: "",
linux: "xdg-open",
mingw32: "start",
netbsdelf: "xdg-open",
openbsd: "xdg-open",
bitrig: "xdg-open", # check this
# solaris: "sdtwebclient", # version < 11
# solaris: "xdg-open", # version > 11
unknown: ""
}.freeze
As you can see, I had NO clue about to do with some platforms (like java and dotnet), and some platforms had different commands to open the default browser based on its version (like Solaris). That solution was not good enough, so I changed this hash to a big ugly switch case:
You can see the complete awfulness here
def open_default_browser_cmd(local_os, version)
case local_os
when 'aix'
'defaultbrowser'
when 'cygwin'
'cygstart'
when 'darwin'
'open'
# ... many other cases
when 'linux'
'xdg-open'
when 'mingw32'
'start'
when 'solaris'
if version < 11
'sdtwebclient'
else
'xdg-open'
end
else
''
end
end
Obviously, this was a terrible solution (and I knew it), but I couldnāt think on another way to accomplish it (without external dependencies). So, I opened the Pull Request anyway so the community could help out on this.
One of the things they said to me was that the open_default_browser_cmd
was very hard to maintain, and āWhat if the user just want to see the URL, not opening it at all?ā. Then AndrĆ© Arko came with a simple, yet powerful, solution that I havenāt thought of: ājust read the browser from an environment variableā. This was perfect simple! Now users could choose if they want to open the browser automatically or not (and what command should do it). That awful code turned into this:
def open_browser(uri)
browser = ENV["BROWSER"]
if browser.nil? || browser.empty?
puts uri
else
system(browser, uri)
end
end
Again: Keep it simple, stupid!
2. Communication
One of the things I love about open source (and especially about Ruby) is the community! Interacting with people, teaching, learning from them, this is so cool!
Do use this in your favor! Like what I did in the last section: I wasnāt sure about a feature, and the community guided me. They even showed me use cases that I didnāt think of. Donāt be shy to ask questions!
And that fear about adding a security bug? Well, here the community can (and will) help you! Thatās what @simi did on my PR for Rubygems.
Oh, and do not take things personally! If someone adds a comment about your code, itās just about your code, donāt be sad about it, but use this an opportunity for learning something (or prove your point if youāre confident about your solution).
3. Test test test
Never forget to add tests when you add new features to a project! It heavily increases the odds of your changes being accepted. And, of course, it should help you to keep track when your code is working or not, and warn you if you insert any bug. Use a coverage tool to make sure every piece of your code is being covered!
Final Thoughts
Yeah, this article was big! But it needed to. Being part of GSoC and contributing to such a big project like Rubygems was just a fantastic experience! Iāll carry the lessons Iāve learned for the rest of my career, and they will lead me to be a better programmer.
I have to thank Google so much for making this possible. I canāt describe how cool was this summer! I also have to thank Ruby and Rubygems for guiding me all the way through this. Thanks for the contributors that reviewed my PR (particularly Luis, Ellen and Josef), and the support on Slack (Aditya and Indirect).
Saroj (@zoras), my mentor was just amazing! He always answered me as fast as he could, and made me find my way rather than giving me the answer right away! This was really cool! Thank you!
At last, I like to thanks all the people next to me that always encouraged me: my fiancee, my friends, all my pals at LAPPIS. Love yāall!
If youāre wondering being part of GSoC 2020, start contributing now! Have no fear! You can do it! Here are some tips for you to get a headstart.
Thatās it, guys! If you made it until here, youāre the MVP. I hope something here helps you! And if it does, let me know! āTill next time! Bye!