module_function と extend self の違いやモジュール関数についてよくわからなかったので調べた結果をまとめる。
module_function は、特異メソッドとプライベートメソッドを同時に定義するためのメソッドです。
特異メソッドであり、プライベートメソッドでもあるメソッドのことを「モジュール関数」と呼びます。
module M
  module_function
  def hoge
    'hoge'
  end
end
モジュール関数は (パブリックな) 特異メソッドであるので、モジュールをレシーバに指定して呼び出すことができます。
M.hoge # => 'hoge'
また、プライベートメソッドでもあるので include することでレシーバを省略して呼び出せるようになります。
class C
  include M
  def fuga
    hoge
  end
end
C.new.fuga # => 'hoge'
include してもそのクラスにパブリックメソッドが追加されるわけではありません。
C.new.hoge # => NoMethodError: private method `hoge' called
extend self は自身の持つメソッド全てを自身の特異メソッドとして定義します。
この場合、特異メソッドと定義したメソッドのスコープは同じになります。
つまり、パブリックメソッドとして定義するとモジュールを指定して呼べますが include した際にパブリックメソッドとして追加されるようになり、プライベートメソッドとして定義するとモジュールを指定して呼べず、 include した際にプライベートメソッドとして追加されます。