Inline documentation – the secret habit of successful devs. | Hanami Mastery

0
55
Inline documentation - the secret habit of successful devs. | Hanami Mastery


The story

Everyone would love to have a secret power. A skill that makes you a hero. If you just said: everyone but me, don’t lie, I know you would.

The thing is, that there is no single skill that makes you such. If you aspire to join the top 10, 5, or top 3% of the best developers in the world, you will quickly realize that what those people have in common, is a particular mindset.

I’m nowhere close to the top 3% of Ruby developers, but I found that constant thinking about how to improve, how to deliver high-quality code with less and less effort, made me a way better programmer in a very short time.

There are several Habits I developed over the years of programming in various projects, that had a great impact on how relaxed I am and how efficient in terms of delivery, especially, thinking long-term.

One is definitely – TDD, which I’ll cover at some point, but today I want to tell you about the other important skill I found not so popular, but extremely beneficial. it’s inline documentation.

What is inline documentation?

Let’s talk about what inline documentation actually is.

The common understanding of inline documentation refers to comments placed within the code files, but that’s a very big simplification.

Comments in the code are just additional things to maintain, and there is a big chance, they’ll get out of date very quickly.

The difference between Inline documentation and just random comments is that documentation is structured, follows common conventions, and is kept at a minimal level.

This all put together allows for a bunch of great benefits to be added on top of it.

Benefits of practicing inline documentation

Before I’ll jump into the particular solutions, I’d love to show you the few advantages that adding inline documentation brings to your projects.

1. Docs generators

First of all, if I’m building a project or library, a component, or whatever else, I can make use of ready-to-use documentation generators, which parse my code and comments attached to it and generate neat, complete websites, where the whole team or whole community can easily track what’s going on within my classes.

One example of such generator for Ruby projects is rubydoc.info, which automatically detects public ruby gems and generates documentation pages based on the inline comments in the code itself.

Here I browse the dry-system documentation website, where you can easily browse through each method and class and check out what it does, what arguments it accepts, and what type of value it returns.

While this is neat, often you just have private repositories you work with so you may wonder if this kind of thing is available for private projects?

I have good news for you! You can generate such documentation for any repository, private, public, or local, with no effort whatsoever, having full control over sharing files with anybody in your team.

I’ll talk about it a bit more later in this episode.

But for now, let’s move to the other nice benefit.

2. Code editor interpreters

One of the more useful things that inline documentation allows you to do, is showing the documentation snippets of the documented class or method when you hover over its execution.

Inline documentation code interpreter popupInline documentation code interpreter popup

You may think: “Ok, but the code should be self-explanatory shouldn’t it?”. And I kind of agree. You may sometimes figure things out just based on the method or class name.

However, in a lot of cases, you would need to visit the implementation and figure out how the code works, which adds additional effort and may cost you a bit of time depending on how often you use it, and how well you know the project.

If you do have your code documented, at least a little bit, then you may save some time and brainpower, by letting your editor figure that out for you!

Let’s say, I have two subscription mechanisms in the system. One that subscribes via email, and the other, that subscribes to the Youtube Channel.



class SubscribeToHanamiMasteryNewsletter
  
  
  def call()
  end
end



class SubscribeToHanamiMasteryYoutubeChannel
  
  
  def call()
  end
end

And a class, using one of them.

class Action
  attr_reader :command

  def initialize
    @service = SubscribeToHanamiMasteryYoutubeChannel.new
  end

  def call
    service.call
  end
end

This is, what happens when I’ll hover over the service.call method execution line.

Automatic context recognition based on inline documentationAutomatic context recognition based on inline documentation

I get immediately the information about what type of class is assigned to the service reader, and what the method does, which is in this case, it subscribes the current video viewer to the youtube channel.

Diclaimer: As you can see here, automatic subscriptions are not fully implemented yet, so please use the manual way of subscribing to a channel, for a while yet.

Even though I don’t have the information what is hidden under the variable value just based on a variable name, it’s still immediately accessible and it proved to be useful quite often in my case.

I don’t need to visit the actual definition of the class and read through the code or tests, to figure out what it does exactly.

I like when this stuff saves me some context switching when I feel a breath of deadline on my back.

3. Easier code reviews

Finally, inline documentation makes the code review easier. A lot easier. If you like those of your teammates, who review your code, which is true in my case, it makes sense, to help them as much as possible, to go through your changes as quickly, and effortless, as possible, as there will be a greater chance you’ll get more, high-quality feedback, and you’ll keep good relationships with you mates.

How does it help?

Well, while it can be acceptable for me to go through the different parts of the code, grasp the implementation of the dependencies, while all that is relevant for the context of the task I am working on, people who review my code have their own tasks, often unrelated.

To properly review my code, they need to go through the task definition, specs, and chances are, they’ll forget about something as all that code can be new for them.

Github Review example with inline documentationGithub Review example with inline documentation

Having then a few guides on top of class or methods can make a difference for them.

If you are reviewing the code daily, I am wondering, what are your thoughts on this particular point.

How to do inline documentation in Ruby?

Now having covered why it can be beneficial to add some of the inline docs to your code, I’d love to tell you about the possible concrete solution.

There are several common formats of inline documentation in your code, and what I found the most resonating with me, is YARD doc, which is a tool designed for Ruby.

YARD home pageYARD home page

In a very clear format, I can describe what the class or method does, why it exists, which arguments it accepts and what value it returns.

  
  
  
  
  def call
  end

There are also conventions to document custom DSL methods, private API, and a lot more if you wish.

It would be tedious to go all of this in this article, so guess what? I recommend you to check out the great documentation of this documentation!

If you’ll just get familiar with a few most basic features I presented already, it’ll already make a huge difference in your projects and teams.

Generating documentation using YARD

If I do have my code documented, I can generate the neat, complete documentation files, by the yard doc command.

I have here a dry-transformer files downloaded, and just to show you how it works, I’m going to generate local docs for this gem.

By the way, check out episode 6, where I covered the basics of complex ruby transformations using dry-transformer!

First I need to install the yard gem, and then I can generate docs using a single command.

gem install yard
yard doc

The generator gives me a bunch of useful stats, telling me which files in my project are not documented and how much of the total codebase is covered with docs.

This generates a set of files, where I can easily navigate through and browse them without an effort.

As I mentioned before, If you create a public library, there are several engines automatically picking up your gem and generating docs for you!

However, the nice thing is, that even if you want to keep your code private, you can still generate up-to-date documentation files during CI builds, and upload them to private servers if you wish, so everyone in your company can easily access necessary documentation.

Myths and why not everyone uses it?

Ok, so if the inline docs are so awesome, why does not everyone use them?

1. An additional thing to maintain.

The first thing that comes to my mind is probably the most valuable point. Inline documentation, like any documentation, is one more thing to maintain. You may minimize the number of changes required on every update, as well as the risk of going out of sync with actual code, if you’ll keep things simple and only document the key points, but still – it is a bit more work to be done.

2. Short-term thinking

I do like to make things simple and keep things simple. The only trick is, I prefer thinking long-term, instead of short-term.

It’s a big simplification in itself, but in general, I don’t have the time and money to make the same thing twice so I am trying to reduce such situations as much as possible.

This is why I write tests when I am coding. And this is why I write inline docs, while I’m coding. Not always, not 100% but whenever I can.

3. Code should explain itself.

Old school programmers can tell you that the code should explain itself. Here is why this can be just a hilarious joke.

It’s true but only to some extent. In academic examples it’s realistic. But in reality, code can’t explain itself.

Code just shows a narrow context, not explaining the why.

What if, for example, you’ll have a code snippet written in two different languages at once?

Not possible? Here are a few examples.

1. Install gpg in the setup script in your project.

You may often see such code in setup scripts of various ruby projects. Inside, you may find ruby code, that calls shell commands to set up dev environment without effort.

  if system("gpg --version")
    puts "gnupg already installed"
  else
    puts "Installing gpg via brew ..."
    system("brew install gnupg")
  end

I know shell and ruby, so no problem here.

2. Call LUA script in ruby Redis, to make the method thread-safe.

But here is the other example.

key_id = "my_sample_key"
version = 1

redis.eval(
  %(
    if redis.call("get",KEYS[1]) == ARGV[1]
    then
        return redis.call("del",KEYS[1])
    else
        return 0
    end
  ), keys: [key_id], argv: [version]
)

This is a snippet taken from official Redis documentation, to ensure thread-safe lock mechanism key removal. A bit more advanced scenario, and here ruby code of the Redis Client calls the LUA script to make things work well.

It’s readable. Simple code, no logic, you may say: self-explanatory – but I can’t already. I’d think quite a bit while staring at this snippet to figure out what it odes if I’d see it without any kind of context provided.

3. Call a custom SQL in Ruby

The next snippet is so popular in ruby applications, that I often forget that it touches the same problem, of mixing two languages together.

User.
  joins('left outer join tasks on tasks.user_id = users.user_id').
  where(tasks: { id: nil })

Here, the ruby script generates raw SQL and passes it to the Postgres adapter, to perform left outer join instead of inner join. I borrowed this one from the Talks about Convenience vs Simplicity Peter Solnica gave in 2014 at RedDotRuby conf which I recommend checking out.

  1. Generate Javascript Code for EventStore Projections in Ruby Client

The last example of this mix I want to show now, I implemented it in ruby event store client not so long ago, to allow for generating server-side projections, that are written in Javascript.



module EventStoreClient
  module HTTP
    module Commands
      module Projections
        class Create < Command
          def call(name, streams, options: {})
            data =
              <<~STRING
                fromStreams(
                .when({
                  $any: function(s,e) {
                    linkTo("#{name}", e)
                  }
                })
              STRING


            res = connection.call(
              :post,
              "/projections/continuous?name=#{name}&type=js&enabled=yes&emit=true&trackemittedstreams=true", 
              body: data,
              headers: {}
            )

            (200...300).cover?(res.status) ? Success() : Failure(res)
          end
        end
      end
    end
  end
end

Here I dynamically generate javascript code using ruby class and send this snippet to the server.

What is unclear here? Class is very well named. It’s a command that creates projection. There is only one method, that obviously performs the command. But when you will look at it, you’ll be like: “What the hell is happening here?”

And I totally agree.

Keep in mind though, that all those examples above, are very simple. Extremely simple, if you wish, and you can still understand what is happening, even if you only work with ruby.

But it’s totally possible, you’ll encounter more complicated examples in your projects that mix several languages together.

But diffs… blames…

Ok, you may say that the git history is enough. Code editors give you a life browsing of who changed what and when, so it is easy to get a context, no?

![[git-commit-details-editor-popup.png]]

Is it? In my opinion, often it is, but often it’s also not enough.

In real life, you may have a file added in one pr, but then you just run a linter on it after a few months, and each line changes. You lose your context.

Again, having comments here and there that are more static, can really improve the overall clarity of your codebase.

Tips for keeping inline docs efficient and useful

So what can we do to make inline documentation useful, not another piece of garbage we add to our code?

  1. Keep it slim and skinny.

Remember, that inline docs are an additional thing to maintain. If you can keep things simple, do it! Document only what is necessary, and when you see it necessary.

  1. Use existing conventions and frameworks.

Then use existing conventions, and frameworks, like Yardock, to get a bunch of additional benefits.

  1. Finally, Don’t make it religion.

Do I always add it? The answer is simple: NO. I add it when I have a time, and mood for it, and when there is a reason to do so. I developed a habit of adding such docs, but I find there is a lot in common to tests I write.

There is a great resource from Jason Swett about when not to write tests, and I can suggest being pragmatic about inline docs too.

When I would write sth like: UUIDV4Generator.call, then I’d definitely not be stressed out about adding an inline doc to anything in it.

Summary

Inline documentation is a great tool that can bring awesome long-term benefits to your team, and I find it very useful if

If you want to see more content in this fashion, Subscribe to my YT channel, Newsletter and follow me on Twitter!

Thanks

I want to especially thank my recent sponsors,

  • MVP match
  • Junyang Ng – for supporting me in a highest personal tier
  • DNSimple.

for supporting this project, I really appreciate it!

By helping me with a few dollars per month creating this content, you are helping the open-source developers and maintainers to create amazing software for you!

And remember, if you want to support my work even without money involved, the best you can do is to like, share and comment on my episodes and discussions threads. Help me add value to the Open-Source community!

If you know other great gems you wish me to talk about, leave a comment with #suggestion, and I’ll gladly cover them in the future episodes!





Source link

Leave a reply

Please enter your comment!
Please enter your name here