23 December, 2018

TIL #6 - go middleware, protobuf, unix shortcuts,SQL COALESCE, bots, find keyword in commit messages and sandi metz

Notes taken between: 17-21 December 2018


In Go, middleware is referred to as handlers. If you are not already familiar with middleware, it is abstracted code that runs before the intended code is executed.

Developing with protobuf / twirp

Rebasing git when your commits have generated files doesn't need to be painful

You have two choices:

  1. Revert any generated files for all commits and leave them to the last commit. Or
  2. Regenerate during the rebase: $ generate files

$ add files $ git rebase --continue

Proto files are a form of documentation.

Use all values in your proto messages, if you want to reuse a proto message but dont need to use a value then instead of leaving any values unsued, make new ones proto messages.

unix shortcuts

!! Will return your last command \$\_ will return your last argument


The COALESCE() function returns the first non-null value in a list.

so if your query results in no rows and it returns a panic instead of a zero value; This statement will return 0 instead.


GIT - Find keyword in commit messages

git log --grep=<pattern>

Limit the commits output to ones with log message that matches the specified pattern (regular expression).

Signs a bot is hitting your site

Uses uncommon useragents eg. mozilla/4 and 5

ch.6 notes for POODIR Sandi Metz

Well-designed applications are constructed of reusable code. Small, trustworthy selfcontained objects with minimal context, clear interfaces, and injected dependencies are inherently reusable. Inheritance is, at its core, a mechanism for automatic message delegation.

JavaScript, for example, has prototypical inheritance and Ruby has modules (more on modules in the next chapter), both of which also provide a way to share code via automatic delegation of messages

When a preexisting concrete class contains most of the behavior you need, it’s tempting to solve this problem by adding code to that class.

You can think of the class of an object as merely a specific case of an attribute that holds the category of self; considered this way, these patterns are the same. In each case if the sender could talk it would be saying “I know who you are and because of that I know what you do.” This knowledge is a dependency that raises the cost of change

Be on the lookout for this pattern. While sometimes innocent and occasionally defensible, its presence might be exposing a costly flaw in your design. Chapter 5, Reducing Costs with Duck Typing, used this pattern to discover a missing duck type; here the pattern indicates a missing subtype, better known as a subclass.

This single class contains several different, but related, types. This is the exact problem that inheritance solves; that of highly related types that share common behavior but differ along some dimension.

In many parts of the biological world it’s common for descendents to have two ancestors. You, for example, quite likely have two parents. Languages that allow objects to have multiple parents are described as having multiple inheritance and the designers of these languages face interesting challenges. When an object with multiple parents receives a message that it does not understand, to which parent ought it forward that message?

Message forwarding via classical inheritance takes place between classes. Because duck types cut across classes, they do not use classical inheritance to share common behavior. Duck types share code via Ruby modules (more on modules in the next chapter)

Even if you have never explicitly created a class hierarchy of your own, you use inheritance. When you define a new class but do not specify its superclass, Ruby automatically sets your new class’s superclass to Object. Every class you create is, by definition, a subclass of something.

In ruby; The implementation in NilClass unconditionally returns true, the one in Object, false. When you send nil? to an instance of NilClass, it, obviously, answers true. When you send nil? to anything else, the message travels up the hierarchy from one superclass to the next until it reaches Object, where it invokes the implementation that answers false. Thus, nil reports that it is nil and all other objects report that they are not

Sending super in any method passes that message up the superclass chain. Thus, for example, the send of super in MountainBike’s initialize method (line 7 above) invokes the initialize method of its superclass, Bicycle.

Chapter 3, Managing Dependencies, defined abstract as being disassociated from any specific instance, and that definition still holds true

Even though you now have a requirement for two kinds of bikes, this still may not be the right moment to commit to inheritance. Creating a hierarchy has costs; the best way to minimize these costs is to maximize your chance of getting the abstraction right before allowing subclasses to depend on it. While the two bikes you know about supply a fair amount of information about the common abstraction, three bikes would supply a great deal more. If you could put this decision off until FastFeet asked for a third kind of bike, your odds of finding the right abstraction would improve dramatically.

A decision to proceed with the hierarchy accepts the risk that you may not yet have enough information to identify the correct abstraction. Acquiring Behavior Through Inheritance hinges on how soon you expect a third bike to appear versus how much you expect the duplication to cost