try to back up my opinions with some evidence but of course there will be differing thoughts. My opinions are based on over two years of maintaining relatively popular Ruby libraries, as well as being a full-time Ruby dev for over five years.
a request, I don’t want to see a SocketError pop up. I didn’t make a socket, how did I error? Libraries should catch their exceptions, wrap them in their own, and expose them in a documented way. More on this later.
the norms. * Ruby has been around for a long time now, we’ve got our conventions. * Helps people pick it up faster. * Gives users that “it just feels right” feeling. Don’t try to be cool. I’m not going to spend much time on this section because this is generally the part that people get right, because they’re used to working with Ruby already and this is what they focus on. Plus, during the talk I’m super crunched for time, so I had to move on.
something fancy, configuration should be non-magical and straightforward. * Use plain Ruby (APIs), or maybe JSON/YAML for tools. Idiomatic, well understood.
4 obj.setting = "value2" * Use normal constructors and option hashes for instance-level configuration. * Very idiomatic, very clear. Instance Configuration
3 Log4r::Outputter.stderr 4 log.level = Log4r::INFO This is what the user of your library would have to do to enable logging for your library. Super easy, predictable.
option • Use something custom * stdout/stderr: Tempting, but extremely annoying and can cause crashes if pipe is closed. * “debug” option is fine, but don’t require it. Sometimes I want debug logging, but not other debug behavior. * log4r may not be the best, but the last thing we need is more fragmentation.
twitter.com (SocketError) ! from app.rb:in `new' ! from app.rb:in `<main>' This is the API that you would use as a developer of a library. Simple enough.
Twitter.socialize! 5 rescue Twitter::Error 6 # Twitter is always down so 7 # I stopped caring. 8 end A single parent class makes it easy to catch-all in a specific library, such as this case.
to twitter (Twitter::ConnectionError) ! from app.rb:in `new' ! from app.rb:in `<main>' With descriptive, specific error classes, its easy to see what is going on and to catch that specific example.
off docs until the end so your lib isn’t changing much anymore, but documentation is SO BORING that you’ll end up hating yourself. * Write it as you go (like tests). If the library changes, then you’ll have to change docs, so there is more work, but at least you’ll have the docs at the end. * Example: Vagrant 0.1 docs pushed off until the end, took me 2 weeks to write them. Really burned me out. More work, but less pain.
the same repo as the code. * Use a branch, won’t ever be merged into master, so clean it and just keep it going. * Makes it easy to contribute. (Pull requests!) * Can see “point-in-time” documentation for specific versions
old markdown, but try to fit it into a Jekyll-powered site. * Two birds, one stone: - Readable from the source. - Able to generate a pretty website. Readable + Website!
you don’t get a good Ruby library, you get a _great_ Ruby library. From learning about your library to developing with it to maintaining it, everyone will thank you.