Inline Function

関数のインライン化 動機 意図がわかるように命名された短い関数を使うことはコードを読みやすくする。しかし、関数の本体がその名前と同じくらいわかりやすいことがある。そうしたときには関数を取り除く。 「関数のインライン化」は、うまく分割できない関数群があるときにも使われる。こうしたときは、それらを1つの大きな関数にインライン化してから、望ましい形の関数群として再抽出すればよい。 通常、「関数のインライン化」を使うのは、間接化しすぎた結果、どの関数も別の関数へ委譲しているだけにしか見えず、委譲に次ぐ委譲の途中で迷っている状態。 手順 関数がポリモーフィックなメソッドでないことを確認する。 クラスのメソッドで、サブクラスでオーバーライドされている場合はインライン化できない。 この関数の呼び出し元をすべて見つける。 関数の各呼び出し元をすべて見つける。 1つ置き換えるごとにですとする。 すべてのインライン化を一度にする必要はない。一部のインライン化がやりにくいようなら、機会を持って徐々に進めてもよい。 関数の定義を取り除く Before def say_state(self): print_state(self) def print_state(self): print(f"I'm going {self.speed} kph!") After def say_state(self): print("I'm going {} kph!".format(self.speed))

February 20, 2022

Why We Sleep

睡眠こそ最強の解決策である なぜ朝型人間と夜型人間がいるのか 朝型と夜型の分類は、「クロノタイプ」とも呼ばれている。大人の場合、クロノタイプはほぼ遺伝で決まることが多い。 午後のコーヒーが夜の睡眠を奪う 睡眠と覚醒を決める要素は2つあり、24時間単位の概日リズムはその最初の1つだ。そして2つ目の要素が「睡眠圧」になる。今この瞬間も、あなたの脳内では、「アデノシン」と呼ばれる化学物質が着々と増えている。アデノシンの増加は、起きている間ずっと続いている。だから起きている時間が長くなるほど、脳内のアデノシンも多くなるということだ。アデノシンは、起きている時間を計測する装置だという考え方もできる。 脳内のアデノシンが増えると、眠りたいという欲求が高まる。この現象が「睡眠圧」だ。脳内に蓄積されたアデノシンは、脳の覚醒を司る部位のボリュームを下げ、睡眠を司る部分のボリュームをあげるという、2つの技を同時にこなすことができる。アデノシンの量がピークに達すると、もう眠くて眠くてたまらないという状態だ。たいていの人は、12時間から16時間起きているとこの状態になる。 しかし、ある種の化学物質を使えば、アデノシンから出る睡眠信号を消し、眠気を覚ますことができる。その物質が「カフェイン」だ。 カフェインの半減期は、平均して5時間から7時間になる。たとえば午後7時30頃に夕食のコーヒーを1杯飲んだとすると、午前1時30分になってもまだ半分のカフェインが体内に残っていることになる。 なぜ深い眠りと浅い眠りがあるのか 深いノンレム睡眠のいちばん大切な機能は、もういらなくなったニューロンのつながりを削除することだ。対照的に夢を見るレム睡眠は、ニューロンのつながりを強化する役割をはたしている。 2つの睡眠で記憶スペースの容量不足を解消する 粘土を使って像を造ると想像してみよう。まず、大きな粘土のかたまりを台座に置く。大きな粘土のかたまりは、寝るまでに脳内に蓄積されたすべの記憶にあたる。次に、粘土のかたまりを削り、大まかな形にしていく。これが長時間続くノンレム睡眠だ。その間に、細部の造形を行うこともある(短いレム睡眠)。 この最初の段階が終わると、また粘土を大まかに削る作業が始まる(2度目の長いノンレム睡眠)、それからさらに細部をつくり込んでいく(先ほどより少し長いレム睡眠)。このサイクルを何度か繰り返すと、求められる作業のバランスが変わる。大まかに削る作業はほぼ終わり、今度は細部のつくり込みがメインになる(レム睡眠が大半を占め、ノンレム睡眠の出番はほとんどなくなる)。 このように、睡眠は巧みな技を使って、記憶スペースの容量不足という問題を解決している。 ノンレム睡眠で情報を整理し、レム睡眠で情報を統合する 深い眠りのゆっくりした脳波が、短期の記憶が保管されている場所から新しい記憶の入った荷物を受け取り、長期の記憶を保管する場所に届けている。 覚醒時の脳波の役割が、外側の情報を受け取ることであるなら、ノンレム睡眠の脳波の役割は受け取った情報を吟味することだ。その吟味の過程で、情報を移動したり、記憶を整理したりしている。 夢をみているとき、身体はマヒ状態になる 夢を見る段階が始まる数秒前になると、身体は完全に麻痺した状態になりそれが睡眠の終わりまでずっと続く。 レム睡眠とノンレム睡眠、どちらが重要か? 進化の過程で最初に出現したのはノンレム睡眠。 徹夜明けの脳波、レム睡眠よりも、深いノンレム睡眠のほうをはるか求める。 回復のチャンスがどれだけあろうとも、脳は、一度の睡眠で失われた睡眠のすべてを取り戻そうとしないということだ。ノンレム睡眠とレム睡眠を個別に見て、トータルの睡眠時間を見ても同じ結果になる。 人間だけでなくすべての種族は、失われた睡眠を一度に取り戻すことはできない。 レム睡眠こそ最大のギフトだ レム睡眠の間に見る夢には、進化の面でもう1つ大きな貢献をしている。それは、創造性を育てることだ。ノンレム睡眠の役割は、新しい記憶を長期の保管庫に移動させることだった。しかし、それらの新しい記憶を取り出し、それまでの経験のカタログと衝突させるのはレム睡眠の役目だ。 レム睡眠の間に起こる記憶の衝突から、創造性の火花が生まれる。それまで関連のなかった情報の間に、新しいつながりがつくられるからだ。睡眠サイクルをくり返しながら、レム睡眠は脳内に広大な情報のネットワークをつくっていく。 また、レム睡眠は一歩引いて視野を広げ、答えのようなものを導き出すこともできる。つまり、バラバラの情報を個別に理解するだけでなく、情報全体が意味することも理解できるのだ。そして目を覚ますと、昨日までの難問の解決策が見つかり、革新的なアイデアが思いついたりするのである。 自閉症スペクトラムとレム睡眠 1990年代、生まれたばかりのラットの研究が始まった。彼らのレム睡眠を阻害したところ、神経の屋根、つまり脳の皮質がつくられなくなった。脳の建設工事そのものが完全に中断してしまったので。どんなに日がたっても、レム睡眠を奪われた脳波、もうそれ以上の発達を見せることがなかった。レム睡眠を復活させると、皮質の建設工事も再開された。しかし建設のペースが上がるわけではなく、脳が完全な発達を遂げることはなかった。生まれたばかりの時期に睡眠を奪われると、脳の発達の遅れは一生残るということだ。 なぜ睡眠で記憶力が高まるのか? 睡眠紡錘波の活動を観察しているときに、100ミリ秒から200ミリ秒ごとに一定の感覚で流れる電気の存在に気が付いた。 その電流は、新しい記憶を保管する海馬と、もっと大容量で、長期記憶を保存する部位は脳の皮質に存在する。海馬がUSBメモリーだとするなら、この部位はハードディスクのようなものだ。 その瞬間、私たちは、睡眠の世界で人知れず行われている電気の活動を目撃していた。新しく入ってきた情報を、一時的な小容量の保存庫(海馬)から、長期的な大容量の保存庫(皮質に)移動していた。 こうして睡眠中に海馬の中がきれいに掃除されるので、起きたときにまた新しい情報を取り入れることができるのだ。 徹夜は成績を下げる 徹夜グループは睡眠をとったグループに比べ、成績が40%悪かった。深いノンレム睡眠を奪われて浅い眠りになると、たとえ睡眠はとっても海馬の学習能力は低下する。 睡眠不足の脳は、新しい記憶を司るニューロンのつながりを形成することができなくなる。つまり、新しい記憶を脳にしっかり刻みつけることが、ほぼ不可能になるのだ。 24時間ずっと起きていたラットも、ほんの2時間か3時間の睡眠を奪ったラットも、ほんの2時間か3時間の睡眠を奪っただけのラットも、結果は同じだった。シナプスの中で記憶の土台になるプロテインを形成するのは、学習プロセスの中で記憶の土台になるプロテインを形成するのは、学習プロセスの中でもっとも基本的な作業だが、睡眠不足の脳はそれさえもできなくなってしまう。 この分野の最新の研究によると、睡眠不足はDNAにも影響を与える。 という。具体的には、海馬の脳細胞の中にある、学習に関連した遺伝子だ。つまり睡眠不足は、脳内にある記憶をつくる装置に、そこまで深いダメージを与えるということだ。この状態で何かを記憶するのは、波打ち際に砂のお城をつくることに似ている。結果は言わなくてもわかるだろう。 学習したその日に寝ないと記憶は脳に定着しない 睡眠による記憶の強化はまったく認められなかった。つまり、何かを新しく学習したその日の夜に眠らないと、記憶を刻みつけるチャンスを失ってしまう。その後でどんなにたくさん寝ても、最初の睡眠を取り戻すことはできない。 睡眠不足と肥満 睡眠が足りないと、満足感を知らせるホルモンであるレプチンの分泌が減り、食欲を刺激するグレリンの分泌が増える。これはまさに、ダブルパンチの精神攻撃だ。睡眠不足という1人の敵が、「満腹感をなくす」というパンチと、「空腹感を増やす」というパンチを同時に放ってくる。その結果、睡眠不足の人は、どんなに食べてきても満足できなくなってしまう。 夜は涼しく-理想的な寝室の温度は18.3度 眠りに入るには身体の中心の体温(中核温)が摂氏1度ほど下がる必要がある。そのため、暑すぎる部屋よりは、寒すぎる部屋のほうが寝付きがいい。寒すぎる部屋は少なくとも脳と身体の温度を下げて、眠るのに最適な状態にしてくれるからだ。 中核温が低下すると、脳の中央にある温度に敏感な細胞がその細胞がその変化を感知する。この細胞は視床下部の中にある。温度の細胞のすぐ隣にあるのが、脳内の24時間時計である視交叉上核だ。もちろん、それには理由がる。夜になり、中核温がある一定の温度より下がると、温度の細胞がすぐ隣にいる視交叉上核にメモを送る。そのメモと、あたりが暗くなってきたという情報を頼りに、視交叉上核はメラトニンの分泌を始める。 つまり、メラトニンの分泌を促す情報は、日が暮れて暗くなることだけではない。日が暮れて温度が下がることも、メラトニンの分泌には必要だ。 睡眠不足はなぜ損失を与えるのか 実験では、睡眠不足の被験者と、睡眠を十分にとっている被験者を集め、それぞれに自分のやりたいタスクを選んでもらった。タスクの内容は、単純作業(留守番電話を聞く)から頭を使う仕事(問題解決能力と創造性が必要とされる複雑なプロジェクトの遂行)までさまざまだ。そして、**いちばん簡単な仕事を選ぶのは、きまって睡眠不足の被験者だった。**彼らはつねに楽な道を選び、創造的な解決策をほとんど思いつかない。 興味深いことに、先ほど紹介した実験の参加者たちは、自分が寝不足の時は簡単な仕事を選んでいることも、仕事の効率が落ちていることも自覚していなかった。

February 19, 2022

Dependency Inversion Principle

ソースコードの依存関係が(具象ではなく)抽象だけを参照しているシステムが最も柔軟である。 Before from abc import ABC, abstractmethod class Order: def __init__(self): self.items = [] self.quantities = [] self.prices = [] self.status = 'open' def add_item(self, name, quantity, price): self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self): total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class Authorizer(ABC): @abstractmethod def is_authorized(self) -> bool: pass class Authorizer_SMS(Authorizer): def __init__(self): self.authorized = False def verify_code(self, code): print(f'Verifying SMS code {code}') self.authorized = True def is_authorized(self) -> bool: return self....

February 18, 2022

Interface Segregation Principle

包括的なインターフェースがあるより、いくつかの特定のインターフェースに分割すべき。 Before from abc import ABC, abstractmethod class Order: def __init__(self): self.items = [] self.quantities = [] self.prices = [] self.status = 'open' def add_item(self, name, quantity, price): self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self): total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class PaymentProcessor(ABC): @abstractmethod def auth_sms(self, code): pass @abstractmethod def pay(self, order): pass class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code): self.security_code = security_code self.verified = False def auth_sms(self, code): print(f'Verifying SMS code {code}') self....

February 18, 2022

Liskov Substitution Principle

サブクラスは、スーパークラスと置換可能でなければならない。 Before from abc import ABC, abstractmethod class Order: def __init__(self) -> None: self.items = [] self.quantities = [] self.prices = [] self.status = 'open' def add_item(self, name: str, quantity: int, price: int) -> None: self.items.append(name) self.quantities.append(quantity) self.prices.append(price) def total_price(self) -> int: total = 0 for i in range(len(self.prices)): total += self.quantities[i] * self.prices[i] return total class PaymentProcessor(ABC): @abstractmethod def pay(self, order: Order, security_code: str) -> None: pass class DebitPaymentProcessor(PaymentProcessor): def pay(self, order: Order, security_code: str) -> None: print('Processing debit payment type') print(f'Verifying security code: {security_code}') order....

February 18, 2022