I write code primarily in ruby. here are a few things that are different from the norm in my personal coding style.
I don’t use the private
nor protected
keywords in languages
when writing OOP code I avoid using private
, protected
, or any other
keyword in a language intended to hide information or implementaion details.
instead I prefer to adopt a naming scheme to indicate to other users of the
code what parts are intended for public consumption, and what is intended only
as supporting methods for implementation. for example, when writing a ruby
module
with some public and some supporting methods, I’ll do something like
this:
module SomeModule class << self def public_method1 # meant for public consumption end def _support_method1 # supporting method, note the underscore end def public_method2 # meant for public consumption end def _support_method2 # supporting method, note the underscore end end end
the reason I do this is a few reaons
- hiding implementation details generally doesn’t prevent anyone from calling
those methods, nor relying on any quirks in their behavior. most languages
that have facilities like a
private
keyword also have ways of getting around such facilities, which in my view renders them less useful.private
seems more often used to hide details from other developers in a misguided sense that we’re saving other developers time. I don’t think this is accruate, and it comes at the cost of writing tests forprivatge
methods more difficult. I am aware that some people feel that you should not testprivate
methods, but it has been my experience that bugs can just as easily hide inprivate
methods as they do inpublic
methods. so avoiding this extra hurdle seems to reduce the overhead involved in developing code. - due to the considerations above, I find the use of
private
to be an overly formal naming convention. I think what golang does (use capitalization to determine what’s public/private) is better, and simpler. in ruby, since capitalization isn’t used for method names, I instead prepend supporting method names with an underscore. in this way, I can also put supporting methods very close to the primary methods that call them, making it easier to see more of the code’s context in a single place. - I rarely write code for anyone other than myself or my employer, and even when I publish code for the general public I still follow these rules, because I find them to be simpler overall.
frame problems as data pipeline problems when you can
while I don’t write code in lisp, some of my most used capabilities within ruby
are the methods in the Enumerable
module. I find these so useful
that I will often compose a solution to a programming problem as a series of
steps operating over some kind of collection or list, as one often does in lisp.
you can also see programming problems solved as data pipelines in a linux
shell’s use of the pipe (|
) operator. the concept is roughly the same.
use simple, open data structures rather than custom data structures
a few guidelins:
- if there is no custom behavior to a class, then consider whether it out to be a hash or struct that simply holds data instead of a class that wraps it.
- if a hash will do the job, but the performance isn’t what you’d like, consider whether you need that extra performance vs. the simplicity and practicality of using a hash, and all the functionality in the standard library and ruby gems meant to work with hashes.
- use the standard library when you can, because every bit of effort you put into knowing your core language will be returned back to you in time saved at a rate higher than building your own thing or using custom libraries. but of course this only applies if a custom data structure or library works well.
testing libraries
if I want to use a testing library, I’m generally going to choose a simple assertion-based library. I’m not a huge fan of testing libraries that use English-like phrases to represent program output. I feel that computers are too precise, detailed, and intolerant to vauge language to work well with English-like phases.
to put this another way:
- if I have to choose between explicit vs. vague I’ll generally choose explicit, even if that means being more verbose.
- if I have to choose between being extra layers of abstraction in a system to make it seem more English-list, or fewer layers that are perhaps more compact in their expression, I will choose fewer layers. adding more layers of abstration and indirection might seem like it helps code organization because every little method has its place, but it can also magnify the number of layers and files someone must understand to make sense of the code.
an example
I wrote a small ruby gem, called
tiny_bus
that follows the
style points above. there aren’t any tests, but it’s well documented and works,
and it includes examples on how to invoke and utilize the class. a quick,
working example with supporting explanations is what most developers need more
than for the code to be neatly tucked away in many little boxes.