Tallman

技術とか読書とかいろいろ

個人開発用マシンをThinkPad X1 Carbon with Ubuntuにしました

経緯

個人の開発マシンはプログラミング始めた去年の6月にMBP2014の13インチをヤフオクで落札して以来ずっとそれを使っていたのですが、5月末くらいにコーヒーを盛大にこぼしてトラックパッドが使用不能に…。
最新のMBPの13インチか迷ったけどLinux使ってみたかったのでThinkPad x1 CarbonにUbuntu入れて使うことにしました。
ThinkPad x1 Carbonにした理由は

です。いろいろいれたら17万くらいになっちゃいました。

スペック

  • Coffee Lake Core i7-8550U
  • 16GB RAM
  • 14.0型WQHD液晶
  • M.2 SSD180 (ぶっちゃけ200もいらないので減らした)
  • 英字キーボード

こうみるとそんなに盛ってないですね

ふぁーすと・いんぷれっしょん

f:id:sasa5740:20190708001839j:plain
ロゴがかっこいい
カーボンの天板の高級感と手触りは◎。キーボードも噂に違わぬ押しやすさです。 そしてなんといっても軽量です。前回のMBP2014が13インチが1.57 kg、職場のMBP2017の15インチが1.83kg。比較してThinkPad X1 Carbon G6は1.13kg。持つとわかりますが本当に軽いです。あと端子がまとも
スピーカーが背面にあるのだけ悲しい

Ubuntu入れてみて

ThinkPadLinuxってポピュラーな使い方だし大丈夫だろ〜と思ってたのですが結構苦労しました…
トラックパッドトラックポイント(赤ポチ)が反応せず、ググりまくって色々試してもどこか治るとどこか動かなくなる状態で途方にくれていました。
結局18.04から19.04にアップデートしたら治ったので良くわからない。 18.04でも使いたいって人がいたらこれをいれるのがいいかと思います。 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1791427/comments/94
スリープ状態でもバッテリーがガンガン消費される問題もありました。BIOSLinux用の設定に変えれば解決しますが。
現在もbluetoothの音質がかなり悪く、なんとかならんかと試行錯誤しています。

Macとの違い

そんなにないです。⌘キーって便利だったんだなぁというくらい。 tweak tool入れてaltをctrにするといい感じ。現状はかなり快適です。
Dockerいれるのに19.04だと公式通りにやってもうまく行かなくてちょっとハマりましたが、Dockerそのものは明らかにMacより軽いです。キビキビ。 ワークスペースやウインドウの管理なんかも楽ですしスムーズです。
とりあえず入れて正常に動くことを確認したもの

chrome入れれば環境はほとんど同期したも同然だし、シェルもfish使ってるのでチョチョっとプラグイン入れるだけですみました。 今はlinuxbrewもあるのでこれからも困ることはそんなにないかと思います。

f:id:sasa5740:20190708002905p:plain
テーマもデフォルトで十分いい感じだと思います

まとめ

やっぱり黒一色っていいですね。秋葉に黒い人が多いのもしょうがない。
Linuxのしくみ」とかこれを使って実践しながら読んでいきたいと思います。
後いざThinkPadで競プロや!ってABCでたらB以降さっぱりできなくて泣いた。

SQL実践入門を読みました

SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)

SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)

SQLアンチパターンや失敗から学ぶRDBの正しい歩き方を読んでいて、ウインドウ関数や結合などまだまだ浅い理解だなーと思って買いました。
以下、気になったことと感想を書きます。

where句で条件分岐するのは素人、プロはSELECT句で条件分岐する。

どういうことかというと 例えば 名前、性別、部署を持つテーブルがあったとして

社員名簿テーブル

名前 性別 部署
太郎 営業
花子 営業

男性と女性人数を部署ごとに出したいとき whereを使うと

SELECT  部署, 
COUNT(*)
FROM 社員名簿
WHERE 性別= ''
GROUP BY 部署;

SELECT  部署, 
COUNT(*)
FROM 社員名簿
WHERE 性別= ''
GROUP BY 部署;

という感じでUNION使っても二回テーブルスキャンしなくてはいけないところを

SELECT  部署, 
  SUM( CASE WHEN sex = '' THEN 1 ELSE 0 END),
  SUM( CASE WHEN sex = '' THEN 1 ELSE 0 END)
FROM 社員名簿
WHERE 性別= ''
GROUP BY 部署;

というように書くことができます CASE式はWHENに当てはまればそこで評価を終了するので先程のWHERE句での分岐より処理も早いです。

Joinの際に駆動表はなぜ小さくするのか

ネステッドループで結合する際に、駆動表はフルテーブルスキャンが行われますが内部表はインデックスが使われます。
どうせフルテーブルスキャンするなら小さいほうが良いし、大きなテーブルスキャンするならインデックス使ったほうが良いので、駆動表は小さいほうがいいんですね。
ハッシュで結合するのは結合するテーブルが同じくらい大きいサイズのときにも有効ですが、メモリを大量に消費するので注意ともありました。

ぐるぐる系とガツン系

ぐるぐる系というのはいわゆる繰り返し処理(ループ)のことです。 一行ずつレコードを引っ張ってきて簡単な処理する、という行為のことですね。
対してガツン系はCASEやウインドウ関数等を駆使して処理を一回で記述してしまうことです。
シンプルでトランザクションの制御が容易だが、チューニングしにくくパフォーマンスもでにくいぐるぐる系と、チューニングしやすくパフォーマンスもでやすいが、トランザクションの制御やオプティマイザに委ねる部分が大きいガツン系か、そのトレードオフを認識する必要があるとのことです。
もともとSQLはループをできるだけ排除したい、という思想の元で生まれたそうで、手続き型言語になれている人ほど処理を全部自分で書いてループさせがちなので、ガツン系のメリットをしっかり知っておくのが重要です。

インデックスが使えないとき、役にたたない時

「失敗から学ぶRDBの正しい歩き方」のありましたが、

  • IS NULL

  • 列に直接演算

これらで検索するときはインデックスが使えません。
なぜかというと、インデックスの中に存在する値はあくまでそのセルの中にある値であって、演算後の値でも、NULLでもないからです。
選択率が高い(取り出すレコードがテーブル全体に対して割合が高い)ときも要注意です。

感想

SQLの当たり前に使われている用語に対して説明、考え方が乗っている良書でした。
ウインドウ関数や結合についてはなんとなくで使っていることが多かったので、クロス結合やパーティショニングのカットのイメージから説明してくれる本書はありがたかったです。 また全体を通してトレードオフというものを意識して書かれてあるとも感じました。
それぞれのアルゴリズムや手法にメリットデメリットが書かれていて、それを把握した上で活用するのが大事だということが繰り返し述べられていた印象です。

SpotifyAPIとRuby2.7の新機能パターンマッチングで人気のある曲だけをフリーワードから検索して出力するスクリプトを書いた

Rubykaigi2019にてパターンマッチングについての発表がありました。

speakerdeck.com スライドにもある通りAPIからもらったJSONを扱うのに便利と感じました。
そこで実際に解析するスクリプトを書いてみたのがこちら。 github.com

スタンドの名前つけるの楽しいしモチベ上がるのでおすすめです。

Echoesのやること

Spotifyは内部で曲やアーティストにpopularityというスコアを100点満点でつけています。
Echoesはフリーワードで公開されているplaylistを検索して、その中に含まれているpopularityが90点以上のスコアを持ってる曲を出力してくれます。

f:id:sasa5740:20190522223424g:plain SpotifyAPIで提供されている検索機能を利用しています。
入力されたワードで検索して、受け取ったJson形式のレスポンスをパターンマッチングを使って解析しています。

playlists.each do |playlist|
  tracks = spotify_client.get_tracks_from_playlist(playlist)
  tracks[:items].each do |item|
    100.downto(90).each do |popularity|
      case item
      in { track:  { name: name, popularity: ^popularity } }
        result[name] = popularity
      else
        next
      end
    end
  end
end

具体的にパターンマッチング使ってるのはこの部分

    100.downto(90).each do |popularity|
      case item
      in { track:  { name: name, popularity: ^popularity } }
        result[name] = popularity
      else
        next
      end
    end

^popularityの部分は既に定義されている変数をパターンマッチに使いたいときに使う記法です。今回は100から90までのIntegerインスタンスを突っ込んでます。
elseも書かないとNoMatchingPatternErrorという例外が起きてしまうので注意。(このErrorいい感じになってほしい)
スコアがpopularity点だった場合にresultハッシュに突っ込んでいくことをやっているのですが、パターンマッチングを使うと変数に値を格納するのも直感的にかけます。
これがパターンマッチング使わないと

    100.downto(91).each do |popularity|
      if item[:track][:popularity] == popularity
        name = item[:track][:name]
        result[name] = popularity
      end
    end

という感じになります。今回はそれほどでもないですが、条件追加するごとにどんどん条件分岐が深くなっていくやつですね。

終わりに

パターンマッチングを使うと条件分岐もパターンでシンプルに設定し、かつ変数に値も入れてくれます。
こんな感じの単純な使い方以外にもクラスに構造を追加してパターンマッチングしたり色々遊べそうです。
実際遊んでる記事を上げておきます。

tech.medpeer.co.jp

developer.feedforce.jp

Ruby 2.7 楽しみですね

追記

@k_tsjさんにこう書くといいよアドバイスいただきました。

playlists.each do |playlist|
  tracks = spotify_client.get_tracks_from_playlist(playlist)
  tracks[:items].each do |item|
    case item
    in { track:  { name: name, popularity: 90..100 => popularity } }
      result[name] = popularity
    else
      next
    end
  end
end

rangeオブジェクトとASパターンを組み合わせるともっとわかりやすい:eye: すごいクールになりました。ありがとう御座います。

プロになるためのWeb技術入門を読みました O/Rマッピングフレームワークの目的

 先月、基本情報技術者試験をうけました。(受かってるといいな) 

午後の問題は現代文の試験かな?というのもありましたが、CPU、メモリ、仮想メモリページングとかアルゴリズム秘密鍵、公開鍵、プロトコルあたりは基礎体力をつけるのにいい内容が範囲に含まれていたかなと思っています。

その流れでWebサービスの技術のあやふやが多いな〜と感じたのでこちらの本を読みました。

「プロになるためのWeb技術入門」 ――なぜ、あなたはWebシステムを開発できないのか

「プロになるためのWeb技術入門」 ――なぜ、あなたはWebシステムを開発できないのか

 

HTTPやCookie、Sessionといった基本的なことについても丁寧に書かれていたのですが特に関心を持ったのは、O/Rマッピングフレームワークについての部分です。

日々O/RマッピングフレームワークとしてActive Recordを利用しているくせに、そもそもなんでO/Rマッピングフレームワークってあるの?というのはあやふやでした…

O/Rマッピングフレームワークの目的

本書ではRDBオブジェクト指向での表現をイメージで示したあとに

このようなリレーショナル・データベース上の表現と、オブジェクト指向言語におけるオブジェクトによる表現の違いを「インピーダンス・ミスマッチ」と呼んでいます。 

(中略)

このインピーダンス・ミスマッチを解決することが、「O/Rマッピングフレームワーク」の最大の役割になります。

として、RDBオブジェクト指向設計の構造上のミスマッチを解決するためにO/Rマッピングフレームワークを使っていると書かれています。 

オブジェクト指向での構造の表現は基本的に階層構造です。 オブジェクトは主従関係を持っています。対して、RDBの表現はというと、ちょっと自分ではうまく言語化できなかったので、こちらの記事から引用します。

インピーダンスミスマッチについて本気出して考えてみた - 酔いどれ設計ナイト2019 - Qiita

  • リレーショナルモデルは言うなれば項中心の世界で、その項が何者であるかはその定義域(ドメイン、データ型)によってのみ決まり、項の間に優劣や主従はない。
    • 項の間の関係はリレーショナル演算によって見出され、逆に言うとそれによってのみ項間の関係は決まる。

外部キー制約とかありますが、確かにRDBの表それ自体には明確な主従性はないですね。 

この表現のミスマッチを防ぐために登場したのがO/Rマッピングフレームワークということです。データベースとオブジェクトの対応を定義して、本来オブジェクト指向での表現で扱いづらいRDBのデータをオブジェクト指向に落とし込んでくれているんですね。

そもそもこの2つの表現の差異について考えたこともなかったので、自分はRDBに階層的なイメージを持っていたと思います。O/Rマッピングフレームワークを通してしかRDBのことをみていなかったとも言えますね…

Active RecordはO/Rマッピングフレームワークとしてなにが優れているのか

本書とは直接関係ないですが、Railsエンジニアが常に意識しているActive Recordというフレームワークは何が優れているのでしょう。

「プロになるためのWeb技術入門」ではO/RマッピングフレームワークとしてiBATISというフレームワークが紹介されています。SQLマップファイルというDBのデータとオブジェクトの対応と実際に発行するSQLを書いています。SQLを明示的に書くことで細かい注文にも対応できるよう設計されています。  

それに対してActive Recordは命名ルールやスキーマのルールに従う必要がありますが、設定用コードは最小限ですみます。レールにのっていればSQLをそれほど意識しなくてもO/Rマッピングフレームワークの恩恵に預かれるということなんですね。

まさに設定より規約を重視した設計でRailsらしいと言えます。*1もちろんこれに甘えずSQLおよびRDBの知識は絶対に必要だとは思いますが。

 

最後に

今回のブログではO/Rマッピングフレームワークについての部分だけ取り上げましたが「プロになるためのWeb技術入門」は様々なWebアプリケーション開発の技術が”なぜ”あるのかを丁寧に説明してくれる本でした。Webアプリケーションの歴史やHTTPからアプリケーションのアーキテクチャ、セキュリティにまで幅広く一冊で言及している本はなかなかないのではないでしょうか。根本の仕組みと考え方が大事ですね。なんでもそうですけど。

大規模サービス技術入門を読みました。ついでにRubyでVB Codeを実装してみた

大規模技術サービス入門という本を読みました。扱うデータの総量が大規模になってきたときに想定される問題、その問題に対処する具体的な方法がふんだんに書かれています。
株式会社はてなさんでやっている(いた?)インターンシップの内容がベースになっています。そのため、ある程度複雑な考え方や用語等も説明やイメージを織り交ぜて記載されています。

重要だと思った点は以下の3つです。

  • メモリ、OS、IOの動作といった低レイヤの知識
  • DBやアプリケーションのサーバーの構成
  • 計算量を減らすにはアルゴリズムの知識が必要

メモリ、OS、IOの動作といった低レイヤの知識は重要

まず本書の最初には、OS、メモリ、仮想メモリLinuxのページキャッシュ、そしてそれらにおける具体的な速度について丁寧な解説がありました。
「メモリ内で計算できないこと」が、いかにパフォーマンスに影響するかが具体的にイメージできるように解説されていました。
ディスクI/Oが多くなると重くなる。メモリの消費は少ないのがベターです。
ちょうど基本情報を受ける前に読んでいたので余計刺さりました。

DBやアプリケーションのサーバーの構成

スケールが難しいDBサーバーをスケールさせるための構成。その他にもボットのための専用サーバーを用意したり、冗長性のためのDBサーバーのマルチマスタ等具体的な構成が数多く紹介されています。
また、手法に対してメリットだけでなくデメリットも紹介されていました。例えばDBのパーティショニングを使えばDBの分散やキャッシュの効率は高まりますが、その分運用は複雑になります。メモリを増やすで対応できないかを検討する必要もありますし、運用を別の技術で解決できないかを考える必要もあります。(今はクラウドが主流だとは思うので別の知識も必要そうですが)

計算量を減らすにはアルゴリズムの知識が必要

二分木探索、n-gramインデックスの具体的な利用方法が紹介されていました。
また、メモリにキャッシュしやすくするための圧縮や計算量が大きくなりがちな全文検索については詳細に解説されています。 実際にPerlで書かれたサンプルコードとともにVBCodeや転地インデックスといって手法をコードに落としこんでいるところまで書いてあります。
自分も圧縮のときに紹介されていたVBCodeについてRubyで実装してみました。自分のコードで圧縮されたファイルっていいですね。

github.com IOクラスとかシリアライザとかまだまだ勉強不足ですね。

まとめ

大規模サービスについて想定される問題についての現実的な解決策が惜しげもなく公開されている良書でした。 一番なるほどと思った部分を引用します。

結局、原因がわかればその原因に対する対応方法は自明なのです。この自明になった対応方法を実践することが、チューニングにほかなりません。

サービスが大きくなってきたときにボトルネックになっているのはなんなのか、メモリにキャシュしきれてないのか、アルゴリズムが悪くディスクI/Oが多発しているせいなのか、はたまた外部のボット等全く違う要素なのか、正確に判断することが重要です。
そのためにはアプリケーションがどのように動いているか?という基本的かつ全般的なコンピューターやインフラの知識が必要だと感じました。
低レイヤやインフラだけでなく、ボットやリクエストの多いAPIに対して専用のサーバーを用意するといった、局所性を理解した構成のためには、サービスの理解も重要です。サービスを提供するって大変ですね。

Riot Games API + Rails + React + Ant design でLeague of Legendでチャンピオンごとにガイドを共有できるwebアプリをつくりました

guidegg.herokuapp.com

なにができるか

チャンピオンを選んでそれぞれ関連する記事を保存できるってだけのアプリです。
f:id:sasa5740:20190422235522p:plain

名前を入れるとインクリメントサーチでキャラが絞り込まれるUIだけ凝りました。もっとアニメーションつけたりしたら面白そう

アカウントそれぞれで保存していく方式ではなく、みんなが保存したものをみんなが見る形式です。
チャンピオンのデータや現在のフリーチャンピオンとかはRiot Games APIを叩いて取得してます。
URLはるだけなので動画ページでもTwitterのつぶやきでもなんでも載せれます。
また、URLを貼るとはてなブログカードっぽく表示するようにしました。

f:id:sasa5740:20190422235403p:plain

なんでつくったか

LOLのガイドっていろいろな所にあるし、記事、動画、はたまた一つのツイートと形態も様々ですが、それらをチャンピオンごとにまとめておける or 見れる集約サイトがあると楽だなと。

使った技術

React及びJavaScriptの勉強を兼ねてreact-railsを使ってRailsのviewにAnt Design を導入して作ってみました。
やっぱり出来のいいコンポーネントが多数用意されてると便利です。
フロントとサーバー側を分けた構成にしているわけではないのでページ遷移は直接aタグを使っています。悲しい。
ひらがなでもカタカナでも検索できるようにしてあります。
かなり恥ずかしいですが、下記がソースコードです

github.com

ひらがなをカタカナにするメソッドはこの素晴らしい記事を参考にしました。コピペですすいません。
最初にチャンピオンのデータを全部propsで渡してstateにセットして、検索時にはpropsに検索語句でfilterかけてまたstateにセットしてます。
stateは親以外は知らないような構造になるようにし、直接変更しないようにしました。(そうしろってreactチュートリアルでやってた)

既知の問題点

記事のURLはURLであるかぐらいしかvalidationはってないので、URLがそのチャンピオンに関係あるか?そもそもLOLに関係あるか?等々を全く見ていません。
あと最大の問題点は めんどくさくて記事の削除機能をつくってないことですかね。

「オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方」を読みました

を読んだ備忘録です。

5章 ダックタイピングでコストを削減する

ダックタイピングは、たとえオブジェクトのクラスや型が違っても、同じふるまいをするのであれば共通化できるということです。
特に特定のクラスであれば〇〇を行って、別のクラスだったら✗✗をするのような感じのcase文を見かけたときには、それぞれに共通のインターフェースをもたせて依存を減らすことができます。
例えばこんな感じのコード

class Test
  def make(questions)
    questions.each { |question|
      case question
      when SelectiveQuestion
        question.make_selective_question
      when DescriptiveQuestion
        question.make_descriptive_question
      end
    end
  end
end

Student#answerは渡された問題のクラスによって処理を分岐しています。
これは他のクラスへ依存を増やすことになり、更に問題の種類を増やしたらcase文をまた一段追加しなくてはなりません。
ここで登場するのがダックタイピング questionsにはmake_questionという振る舞いを期待して、make_questionすればダックじゃなくてもダックなのです。

class Test
  def make(questions)
    questions.each do |question|
      question.make_question
    end
  end
end

これで各Questionクラスにmake_questionを実装すれば、いちいちクラスを増やすたびにケース文を追加することもなくなります。振る舞いを抽象化して他のクラスを信頼することが大事。

6章 継承によって振る舞いを獲得する

本書では継承とコンポジションという2つのコード構成のテクニックが紹介されています。
1つ目がこの章の主題の継承で、クラスの継承は依存を強くしてしまうリスクはあるけど、親クラスの小さな変更で全てを変えたり、サブクラスの追加が簡単に行えたりとメリットも大きいです。

この章で一番大事なことは、「親クラスは小クラスにとっても当てはまることのみ持っているべき」という継承の契約でしょう。
この契約を守る方法として、一度それぞれ具体的にクラスを作って、全てに共通する抽象的な部分だけ集めて親クラスにしようというものが書かれていました。
親クラスは抽象的であるべき、の典型的な例はStandardErrorとかでしょうか。エラーという概念のみ表していますよね。
また、この章ではもう一つ継承による構造での依存を下げる具体的な案として、superを減らすということも書かれています。
フックを親クラスに持たせるテクニックはまさにそれで、制御を抽象的な親クラスにうつしてクラス同士の結合を減らす作業が紹介されていました。

第七章 モジュールでロールの振る舞いを継承する

引き続き継承を扱っている章です。6章の内容がより具体的に書かれているのと、モジュールのミックスインにたいしても、メソッド探索の中に追加されるものだから継承と基本的に同じ考え方で行おうねと書いてあります。

第八章 コンポジションでオブジェクトを組み合わせる。

継承とは別のコードの構成としてコンポジションについて書かれています。
継承はいわゆる階層構造(is_a?)でしたが、コンポジションではhas-aの関係、例えば本書では自転車はPartsをもち、PartsはPartをもっている...という考え方でコードを構成します。

#オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方 225pより
class Bicycle
  attr_reader :size, :parts

  def initialize(args = {})
    @size = args[:size]
    @parts = args[:parts]
  end

  def spares
    parts.spares
  end
end

require 'forwardable'
class Parts
  extend Forwardable
  attr_reader :parts

  def_delegators :@parts, :size, :each

  def initialize(parts)
    @parts = parts
  end

  def spares
    parts.select(&:needs_spare)
  end
end

require 'ostruct'
class Part
  attr_reader :name, :description, :needs_spare

  def initialize(args = {})
    @name = args[:name]
    @description = args[:description]
    @needs_spare = args.fetch(needs_spare, true)
  end
end

require 'ostruct'
module PartsFactory
  def self.build(
                 config,
                 parts_class = Parts
                )
    parts_class.new(
      config.collect do |part_config|
        create_part(part_config)
      end
    )
  end

  def self.create_part(part_config)
    OpenStruct.new(
      name: part_config[0],
      description: part_config[1],
      needs_spare: part_config.fetch(2, true)
    )
  end
end

なかなかコードがないと伝えづらいのでコードを引用させていただきました。(ForwardableとかOpenstruact初めて知りました…
個々のわかりやすい動作をするオブジェクトを集めて最終的に複雑なオブジェクトを作り出すという構造です。
コンポジションは継承に比べてそれぞれのオブジェクトの関係を明示しないと関係をもってくれませんが、よりオブジェクト同士の依存を少なくする事ができます。
しかし、それがデメリットでもあり、自転車、Parts、Partそれぞれの構造はわかりやすいですが、全体像はわかりにくく、委譲を明示しなくてはならないので、継承のように少ない記述でコードの共有をサポートしてくれたりはしません。
継承とコンポジション、どちらを選択すべきか?という問いに対しては、コンポジションでできそうだったらコンポジションのほうが依存を少なくできるので有効な場合が多い、と書かれていて、パーツがおおければコンポジションのほうが、パーツそれぞれを深く掘り下げて、抽象的な共通部分を見つける継承が適していると判断できれば継承を利用すると良い可能性が高いとのことです。

第9章 費用対効果の高いテストを設計する

テストの大切さや入力と出力の部分だけ考えるべき、といった部分はよくある意見と特に変わらないのですが、よりコードの構造に沿ったテストを無駄なく書こうとする具体的な方法が書かれていました。
継承されたコードをテストする時は、抽象的な親クラスのテストはインクルードして全てパスするようにする、というびはこの本で初めて認識した考えかでした。

まとめ

全章を通して、オブジェクトの責任を明確にすること、オブジェクト同士の依存は少なくすること、依存してもより変更がないものにすること。関係をつくるインターフェースを注意して設計することの大切さが説かれていました。デザインパターンの話がすこし出てきて、しっかり理解できてないこともあるので今度はrubyによるデザインパターンとかいいかな?と考えております。