エンジニッキ

エンジニアとして日々学んだことを書き残しています

名前空間を理解しよう

業務でRubyソースコードを読んでいた時に、しばしば   ~::~(ダブルコロン)を使ったメソッドが出てきて....?となってしまったので先輩エンジニアに聞いてみると、どうやらこれは「名前空間」という技を使っていることが分かりました。今回は、名前空間について学習したことをメモしていきたいと思います。

 

 

1名前空間とは

名前空間はその名の通り、同じ名前のメソッドやクラスがあっても判別できるように空間を作ることです。違う表現をすると「名字だけだとわかんないから、名前も書いてくれ」という感じです。例えば「おい!佐藤」って呼ばれただけでは、佐藤が複数人いたら誰だかわかりませんよね。「佐藤 〜」って名前も読んであげれば、反応が帰ってくると思います。プログラムも同じで、同一の名前がある時は「どっちやねん」と困ってしまいます。その判別をするために必要なのが名前空間なのです。

言葉だけではわかりにくいので、コードで実行していきたいと思います。

 

同じクラスに同じメソッドが入っていますね。この状態で実行するとどうなってしまうのでしょうか?

 

後から定義した「こんばんは」が出力されましたね。これでは、「こんにちは」と挨拶したくても実行することができません。どうすればよいのでしょうか? ...そう、こんな時こそ名前空間の出番です!

 

まずは名前空間を使う準備します。準備は簡単で、1つ目のクラスをModuleで包んであげます。これだけで名前空間を作ることができます。

 

ではさっそく名前空間使ってみましょう!

 

 

今度は「こんにちは」を出力することができました!名前空間を使った箇所は

God::Person.new

 この行の部分です。何をしているのかは簡単で、「Godモジュール内のPersonクラスのインスタンスを作ってください。」と指定しています。こうすることによって、同じ名前でも存在している空間が違うため、判別ができるという仕組みです!

 

 

 

 

 

 

 

共通鍵・公開鍵暗号方式とSSL

今日はAWSのサーバーにssh通信をする機会があったのですが、公開鍵や秘密鍵の仕組みについて忘れかけていたので、その備忘録として書いていきます。

 

共通鍵暗号方式

共通鍵暗号方式は、暗号化するための鍵と復号化(暗号解除)するための鍵が同じという特徴を持っています。僕なりに簡単に表現すると、「マスターキーが二つあって、片方を相手に渡す」といった感じです。

 

 

1 送信側が共通鍵を使いデータを暗号化(鍵は二つ持っている)

2 暗号化したデータともう一つの共通鍵を相手に送る

3 受信側は送られてきたデータを共通鍵で復号する

 

これが送受信の流れです。

 

共通鍵暗号方式のメリットは、データが暗号化されているため、第三者に見られても安心という点です。しかし、これにはデメリットもあります。それは、鍵自体を盗まれる可能性があるということです。

 

共通鍵暗号方式では、データだけでなく、復号するための鍵も送信しなくてはいけないのですが、この「鍵」自体は暗号化されていないため、悪意ある第三者に見られてしまうかもしれません。この問題を「鍵配送問題」といいます。こういった弱点があるため、現在では公開鍵暗号方式が主流になっているそうです。

 

 

2 公開鍵暗号方式

公開鍵暗号方式は、「公開鍵」と「秘密鍵」の二つを用いて通信するものです。公開鍵はその名の通り多数の人に公開する暗号化用の鍵で、秘密鍵は復号用に自分の懐に隠しておく鍵です。通常は受信側が公開鍵と秘密鍵の両方を作成します。流れとしてはこんな感じです

 

①受診者が公開鍵と秘密鍵を作成する

②公開鍵を外部に公開する

③送信側は公開鍵を使って送りたいデータを暗号化し、相手に送る。

④受信側は秘密鍵を使いデータを復号する。

 

ここで大事なことは、公開鍵は暗号化用秘密鍵は復号化用ということです。

外部に公開されている公開鍵では暗号化しかできませんので、悪意ある第三者に見られても安心というわけですね!

 

公開鍵暗号方式のメリットは共通鍵暗号方式よりも安全であることですが、デメリットとして基本的に一方通行の通信しかできないということや処理が複雑になるため、共通鍵暗号方式よりも処理速度が遅くなる傾向があるみたいです。

 

SSL (Secure Sockets Layer)

SSLはこのサイトを参考にしました

https://viral-community.com/blog/ssl-summary-1510/

 

SSLは先程までの共通・公開鍵暗号方式の二つを用いることで、より強力な暗号化通信を行っています。イメージとしては、共通鍵暗号方式の弱点を公開鍵暗号方式で補っている感じですね。

 

①クライアントがSSH通信をさせてくれ〜とサーバーに要求

②サーバーは要求にOKを出し、SSL証明書と公開鍵をクライアントに渡す(この時、復号用に秘密鍵も作られている。)

③クライアントは共通鍵を二つ用意し、一つを受け取った公開鍵で暗号化しサーバーに送る。

④サーバーは送られてきた共通鍵(暗号化状態)を秘密鍵で復号する

 

後は、共通鍵暗号方式と同じで安全に通信ができます。つまり、SSLは鍵配送問題が解決された共通鍵暗号方式ということですね!

 

 

 

 

 

 

オブジェクトの継承関係を把握しよう!(Ruby)

Rubyを勉強している時にこう思ったことはないですか。「オブジェクト指向って何」。「putsto_sメソッドは定義していないのにどこからやってきたんだ」というか何でデフォルトでこんなにメソッドを使えるのかと。今回はそんなもどかしい気持ちを解決するために「メタプログラミングRuby第2版」という本を買ってきました。その備忘録として書きます。

 

 

1 オブジェクトとは

Ruby で扱える全ての値はオブジェクトです。」Rubyを勉強している人なら皆知っていると思いますが、今回は改めて、全てがobjectになっているのかどうか実行して調べたいと思います。

 

まずはインスタンスを確認

class A
end

obj = A.new

p obj.class

#=> A

 

.classはレシーバがどのクラスのインスタンスか調べるメソッドです。(ここではobjを調べている)実行結果からobjはAクラスのインスタンスであることがわかりますね。

では次にAクラスのクラスを調べてみましょう。

class A
end

obj = A.new

p obj.class

#=> A

p A.class

#=> Class

 

AクラスはClassクラスのインスタンスであることがわかりました。では最後にClassクラスのクラスを調べましょう(ややこしい)

class A
end

obj = A.new

p obj.class

#=> A

p A.class

#=> Class

p Class.class

#=> Class

結果はClassでした。ここからわかることはClassクラス自信がclassを生成しているということですね。

 

 

2継承クラスを調べる

先程まではオブジェクトのクラスを調べていましたが、今度は継承クラスを調べます。「何が違うねん」とツッコミをいれられそうなので僕なりに簡単に説明すると、クラスは横の繋がり、継承クラスは縦の繋がりを表しています。

 

先程の横の繋がり

f:id:keigo_takahashi:20190429005849j:plain

 

 

次はこの矢印が上方向のクラスを調べます。

 

さっきと同じようにインスタンスから調べてみましょう。

class A
end

obj = A.new

p obj.superclass

#=> `<main>': undefined method `superclass' for #<A:0x007fdaee140ea8> (NoMethodError)

.superクラスはレシーバのクラスの親クラスを調べるメソッドですがErrorが起こっていますね。どうやらobjはインスタンスであるためこのメソッドは使えないようです。

 

次にAクラスの親クラスをを調べてみます。

class A
end

obj = A.new

p A.superclass

#=> Object

Aクラスの親クラスはObjectクラスのようです、遂にオブジェクト指向の本質がみえてきましたね。

 

次はClassクラスの親クラスを調べてみましょう。

class A
end

obj = A.new

p Class.superclass

#=> Module

結果はModuleでした。こうなると気になるのはModuleの親クラスですね。調べてみます。

 

class A
end

obj = A.new

p Module.superclass

#=> Object

またObjectに戻ってきました。ここまでの結果を図にして書いてみます!

 

f:id:keigo_takahashi:20190429012652j:plain

(メタプログラミングRuby第2版参考)

 

つまり、僕たちが自分で定義したメソッドやインスタンスは全てObjectクラスを引き継いでいることが分かりました。これがオブジェクト指向と言われる理由ですね。

 

もう一つの疑問である「puts」や「to_s」等のメソッドはどこに定義されているのかを調べるために「 ancestors」メソッド使います。このメソッドはレシーバの親クラスを遡って調べ、配列にして返してくれるメソッドです。ちなみに親クラスの他にインクルードされているModuleも含んで遡ります。では、Objectクラスに「ancestors」を使い調べてみます。

class A
end

obj = A.new

p Object.ancestors

#=> [Object, Kernel, BasicObject]

継承にKernelというModuleが入っています。怪しいので「methods」メソッド(レシーバが持っているメソッドを配列で返す)を使いKernelに定義されているメソッドを調べてみます。

 

class A
end

obj = A.new

p Kernel.methods

#=> [:sprintf, :format, :Integer, :Float, :String,
#:Array, :Hash, :warn, :raise, :fail, :global_variables, :__method__,
#:__callee__, :__dir__, :eval, :local_variables, :iterator?, :block_given?,
#:catch, :throw, :loop, :trace_var, :untrace_var, :at_exit, :syscall, :open,
#:printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :`,
#:p, :test, :srand, :rand, :trap, :load, :require, :require_relative, :autoload,
#:autoload?, :proc, :lambda, :binding, :caller, :caller_locations, :exec, :exit!,
#:system, :spawn, :sleep, :exit, :abort, :Rational, :Complex, :set_trace_func, :freeze,
#:===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :inspect, :included_modules, :include?,
#:instance_methods, :public_instance_methods, :protected_instance_methods,
#:constants, :const_get, :const_set, :const_defined?, :const_missing, :class_variables,
#:class_variable_get, :class_variable_set, :class_variable_defined?, :public_constant,
#private_constant, :singleton_class?, :include, :prepend, :module_exec, :class_exec,
#:class_eval, :method_defined?, :public_method_defined?, :private_method_defined?,
#:public_class_method, :private_class_method, :instance_method,
#:=~, :!~, :eql?, :hash, :class, :singleton_class, :clone, :dup, :itself, :taint,
#:untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods,
#:private_methods, :public_methods, :instance_variables, :instance_variable_get,
#:instance_variable_set, :instance_variable_defined?, :remove_instance_variable,
#:kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method
#:public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum,
#:equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]


ものすごい数のメソッドが出てきました... この中に「puts」メソッドだけでなく「Array」や「String」など、普段使っているクラスが定義されていますね。

 

 

まとめると、ObjectはKernelモジュールを継承しているため、僕たちが定義したクラスやインスタンスはKernelを引き継いでいる、そのためデフォルトで「Array」や「String」などのメソッドを使うことができるというわけですね!

 

f:id:keigo_takahashi:20190429021834j:plain

 

 

RubyフレームワークであるRailsも継承を使う場面が非常に多いので、こういった継承関係を常に意識して開発をしたいです!