君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

死神が予備校にいた。彼はりんごばかり食べていた。

f:id:karoten512:20180809003222p:plain

予備校にいた、死神の話。

僕が通っていた予備校には死神がいた。

その死神は毎日りんごばかり食べていた。

みんな知ってると思うけど、死神はりんごしか食べないんだ。

死神は昼休みになると、予備校の地下にあるリフレッシュルームに降りてくる。

そしてハンカチから一つのりんごを取り出し、両手で大事そうにもって、まるかじりする。

死神が、毎日昼休みにりんごをまるかじりしている

僕はそれをいつも、不思議そうに見ていた。

なんでりんごなんだろう。

ずっと不思議だった。

でもりんごをまるかじりする彼は、死神のくせになんだか神々しく見えて、

少し離れたところからそっと見るくらいしかできなかった。

神々しく見えるのには理由があった。実は彼にはもう一つ名があったのだ。

ザビエル。

それは明らかに彼の髪型に由来していた。

彼は御年50歳。

予備校には再受験組が割りといたので珍しいことではない。しかし、

ザビエルという死神が、毎日昼休みにりんごをまるかじりしている

こうなってくると一気に珍しくなってくる。

時がたってセンター試験前。

そんな彼は、みながそろそろセンター試験に向けてエンジンに火を入れ始める9月、

予備校からいなくなった。

ここで僕はようやくわかった。

そうか。本当は、彼は人間だったんだ。

知恵の実りんご)を食べてしまったせいで、

楽園(予備校)を追い出されてしまったんだね。

いつも人間は、禁忌を犯して追放される。

僕もいつか、大学に合格するという禁忌を犯して予備校を追放されるのだろう。

そんなことを思って、僕は禁忌を犯すべくセンター試験の勉強に没頭した。

ザビエルという死神が、毎日昼休みにりんごを食べていたが、センター試験を目前にして消えた

これで話は終わったはずだった。

でも真相は全然違った。

後ほど僕は友人から聞いた。

死神は、りんごを食べたから楽園追放されたわけではなかった。

別の禁忌を犯したのだ。

死神は婚活をしていた。

後から聞いた話だ。死神は受験のために予備校にきていたのではなかった。

予備校で婚活をしていたらしい。

予備校で婚活。新しい。

彼はめぼしい女性がいると突然近づき、こう言った。

「友達からどうですか?」

どうですか?、と言われましても。

こんなことを繰り返しているうちに、いろんな生徒から被害届がだされ、

ついには楽園を追放されてしまったらしい。

うちの予備校は3つ目の楽園だった。

彼は他の予備校でも同じことを繰り返していた。

そのたびに楽園を追い出され、予備校を転々として、

うちの予備校にたどり着いたようだった。うちは3つ目の楽園だった。

結局、この楽園には見切りをつけ、次の楽園を目指したのだろう。

「ザビエルという死神が、

 毎日昼休みにりんごをまるかじりしていたけど実は婚活もしていて、

 ついには追い出されてしまったけど、次の楽園に移動しただけだった」

盛り沢山すぎやしないか。

きっと

今でも彼は、生涯の伴侶をもとめて次の楽園を目指している。

僕は、彼が幸せになってくれたらいいなと思っている。

予備校は牢獄だった〜浪人時代予備校にいた「7浪さん」の話〜

f:id:karoten512:20180805163207j:plain

僕は大学に入るまで、3年かかった

3年。長かった。

受験勉強を始めたのが高3の夏。

それなりに勉強をしたのだが結局志望校には入れなかった。

結局僕が入ったのは予備校。そこで1年、そして2年といた。

よく「浪人時代は本当に苦しかった」と言っている人がいて、

「1浪でもつらい、2浪なんて頭がおかしくなる」なんて感想をくれたりするが、

僕は予備校生活が楽しかった。

そう。予備校には本当に色んな人がいた。アメリカもびっくりの人種のサラダボウルだ。

聞こえが良いが、悪くいうとただの魔窟だった。

七浪さん

僕が通っていた予備校には「リフレッシュルーム」と呼ばれているところがあり、

自販機があって、4人座れるでかい丸テーブルがいくつもあって、謎のカウンターがあった。

そこは予備校生が唯一くつろげるオアシス的場所だった。

毎日、大量の英単語・数式・いつ使うかわからない物理法則・その他諸々を詰め込みまくって、

脳が消化不良を起こしてゲロを吐いている、そんな生活を送っているのだ。

死刑囚だって最後はタバコを吸わせてもらえる、

だから予備校生だってリフレッシュしたっていいはずだ。

そんなリフレッシュルームの雰囲気を完全に破壊していたのが

「七浪さん」だった。

七浪さんとその取り巻き

坊主。目にはサングラス。壁を蹴ったら突き刺さりそうなほど先が尖っている靴。

手首には高そうな時計。そして意外に低い身長。

彼はいつも肩を怒らせて歩いているので謎にデカく見えた。

彼の朝は遅い。少し日が傾き始めた15時頃、リフレッシュルームに現れる。

七浪「う〜〜〜〜〜〜〜〜〜〜〜〜〜す

取り巻き達「お勤めご苦労さまッス!!

ここは獄中か?

獄中ヒエラルキー

脱獄モノ映画でみたことある。

長くいるやつほど偉いという獄中ヒエラルキーが、そこに存在していた。

僕は気づいてしまった。

予備校は入学ではない。投獄なのだ。

彼はもう7年も勤めている。懲役何年かしらないがきっともうシャバには戻れないだろう。

3浪や4浪はまだ社会復帰できる可能性が残っている。

僕みたいな1浪はお話にならない。まだ社会に片足を突っ込んでいるただの軽犯罪者だ。

もちろん、素行が悪ければ刑期はもっと伸びる可能性がある。ここではそういうルールなのだ。

彼は勝ち組だった

そんな彼は、リフレッシュルームでいつもポーカーをやっていた。

また彼は既婚だった。子供もいた。

そしてレクサスに乗ってた。

資金はどこから出てるんだと思ったが、親が金持ちらしい。

…酒、女、ギャンブル。

これらすべてが満ち満ちた医学部受験生が、確かに僕の身近に存在していた。

彼はいわゆる「勝ち組」だった。

七浪さんは消えた

七浪さんはセンター試験に近づくに連れ見かけなくなった。

きっと、レクサスを乗り回しているのだろう。

そして時が流れた

センター試験を命からがらこえて、二次試験で頭が真っ白になり、

3点の差で入学を逃した僕はめでたく2浪目に突入した。

授業が終わり、僕はリフレッシュルームにいった。

新入りはどんな面構えをしているのか見るために

長い予備校生活で、僕も完全な「投獄ヒエラルキー」の一員になってしまっていたのだ。

フレッシュな面構えを見ながら、

「生きの良いのが入ってきた…俺達のシゴキにどれだけ耐えられるか見ものだな」

なんてうそぶいていると、全然フレッシュじゃないやつがいた。

そいつは、もちろん坊主だった

命名変更

八浪さんだった。

……こうして彼の名前はincrementされていく。

今もどこかで、静かにincrementされているのかもしれない。

OSSから設計について学ぶ〜クラスの依存方向について〜

要約

僕が間違ってました。すみませんでした。

いきさつ

「Mapを使ったアプリケーションで、Mapの上にMarkerを立てたい」

という要件を満たすために、leafletというOSSを使うことにした。

github.com

  • 公式サイト

leafletjs.com

インターフェース(ライブラリの使い方)を予想してみた

OSSを使うときに、

こんな感じのインターフェースじゃないかなって予想してみた。

僕「MapがMarkerを持ってるから、こうだろ」

f:id:karoten512:20180804220204p:plain

僕「だから、インターフェースはこんな感じだろ」

const map: Map = new Map();
const marker: Marker = new Marker();
map.addMarker(marker);

僕「で、実装はこんな感じだろ」

class Map
{
    private markers: Array<Marker>;
    constructor() {
      this.markers = [];
    }
    addMarker(marker: Marker) {
        this.markers.push(marker)
    }
}

class Marker
{
    constructor() {     
    }
}

僕「うーむ。実に自然な発想だぞ。」

実際のインターフェース

const map: Map = new Map();
const marker: Marker = new Marker();
marker.addTo(map);

僕「え…?」

class Map
{
    constructor() {
    }
}

class Marker
{
    private map: Map
    constructor() {
    }
    addTo(map: Map) {
        this.map = map;
    }
}

僕「え…?え...?」

f:id:karoten512:20180804221839p:plain

Mapクラス「もしかして」

Markerクラス「わたしたち」

僕「(依存方向が)いれかわってる〜〜〜〜!?

他のOSSもみてみた

google map JavaScript API、mapboxGL, mapboxJSなどもみてみたが、

皆同じようなインターフェースだった。

つまり、

MapがMarkerに依存しているのではなく、

MarkerがMapに依存していた。

どうしてこんな設計なのか考えてみた

こっちのほうが変更に強いからだった。

変更に強いとは

例えば、MapにMarkerじゃなくてPopupも追加しようと思ったら、

僕が考えた実装方法だったらこうなる。

※ 理解を簡単にするため、ソースコードは極限まで単純化しています

f:id:karoten512:20180804223242p:plain

class Map
{
    private markers: Array<Marker>;
    private popups: Array<Popup>;
    constructor() {
        this.markers = [];
        this.popups = []; // 追加
    }
    addMarker(marker: Marker) {
        this.markers.push(marker)
    }
    // 追加
    addPopup(popup: Popup) {
       this.popups.push(popup)
    }
}

// 追加
class Popup {
    constructor() {        
    }
}

つまり、Popupの機能を追加しようとしたときに、

Mapの方も修正が必要になってくる。

さらにOverlay(地図上に何かを覆い隠す)を機能として追加してみると、、、

f:id:karoten512:20180804223708p:plain

いい感じに「やな感じ」がしてきましたね笑

やな感じの正体

新たな機能を追加するたびに、Mapの方にも修正が発生してしまっているというのが、

やな感じの正体です。

これは「開放・閉鎖の法則」に違反しています。

開放/閉鎖原則に沿ったソフトウェアは、既存のソースコードを変更せずに機能修正や機能追加を行うことができる。 そのため、品質検査を再実行する必要がない。(wiki)

また、MapとMarkerだけ使いたいときもあるはずです。

そのときも、MapはPopupやOverlayのことまで知っている必要がある、というのもおかしな話ですね。

依存関係を逆転してみる

f:id:karoten512:20180804224309p:plain

class Map
{
    constructor() {
    }
}

// 追加
class Popup
{
    private map: Map
    constructor() {
    }
    addTo(map: Map) {
        this.map = map;
    }
}

既存のコードに手を加えずに、機能を追加することができます。

すごい。すごいね。

どんなときに応用できるか

たとえば、ペイントのようなアプリをつくるとしましょう。

f:id:karoten512:20180804224540p:plain

機能をボンボコ追加しても、修正をしても他のクラスには影響がでません。

素敵ですね。

まとめ

依存関係を逆転して考えると、

その後の機能追加時のコストに大きな差が出てきそうです。

そんなことを、今回知りました。

ただ、今回本当に単純化しているので、実際はもうちょっと複雑なはず。

注意したいです。

本当にオブジェクト指向を使う必要があるのか?

タイトルについて

すみません、煽りました。

いきさつ

オブジェクト指向で設計した時と、

オブジェクト指向を使わなかった時について、

「単純にコード量だけで」比較してみます。

その上で、オブジェクト指向の利点について再度考えてみます。

つくるもの

  • 1秒間に1, 数字がカウントアップされる
  • カウントアップされるたびに、2で割ったあまりと3で割ったあまりが表示される

f:id:karoten512:20180727001417g:plain

コード

NOTオブジェクト指向でかく

const view1Input = document.getElementById("view1Input");
const view2Input = document.getElementById("view2Input");
const view3Input = document.getElementById("view3Input");

var count = 0;
const countUp = () => {
  count++;
  view1Input.value = count % 2;
  view2Input.value = count % 3;
  view3Input.value = count;
};
setInterval(countUp, 1000);

オブジェクト指向で設計して書く

  • input要素の書き換え…Viewクラス
  • カウンター値保持...Modelクラス
  • 処理開始...Mainクラス

という簡単な責務で考えます。 そしてとりあえずobserverパターンで実装します。

すると。

class ViewModCounter {
  constructor(el, model) {
    this.inputEl = el;
    this.model = model;
    this.mod = 1;
  }
  setMod(num) {
    this.mod = num;
  }
  render() {
    this.inputEl.value = this.model.count % this.mod;
  }
}

class ViewCounter {
  constructor(el, model) {
    this.inputEl = el;
    // viewはmodelに依存している
    this.model = model;
  }
  render() {
    this.inputEl.value = this.model.count;
  }
}

class Model {
  constructor(count) {
    this.count = count;
    this.listeners = [];
  }
  setCount(count) {
    this.count = count;
    this.notify();
  }
  addListener(listener) {
    this.listeners.push(listener);
  }
  notify() {
    this.listeners.forEach((listener, index, listeners) => {
      listener.render();
    });
  }
}

class Main {
  constructor() {
    this.model = new Model(1);

    const view1Input = document.getElementById("view1Input");
    const view2Input = document.getElementById("view2Input");
    const view3Input = document.getElementById("view3Input");

    let view1 = new ViewModCounter(view1Input, this.model);
    view1.setMod(2);
    let view2 = new ViewModCounter(view2Input, this.model);
    view2.setMod(3);
    let viewCounter = new ViewCounter(view3Input, this.model);

    this.model.addListener(view1);
    this.model.addListener(view2);
    this.model.addListener(viewCounter);
  }
  run() {
    const model = this.model;
    let sec = 0;
    setInterval(() => {
      sec++;
      model.setCount(sec);
    }, 1000);
  }
}

const main = new Main();
main.run();

めっちゃ増えた

記述量だけみると、オブジェクト指向で設計するほうが大変です。

※ もちろん要件によっては記述量が逆転することもありえます

じゃあいつオブジェクト指向設計を使うのか

個人的には、

  • 要件が複雑になった時
  • 扱うモノが増えた時

この時、オブジェクト指向設計じゃないとかなり苦しむな、と感じています。 あとは保守のときですね。きちんと設計しないと一つの修正がいろんなところに飛んだりします。

注意

オブジェクト指向設計とはクラス化することではありません。

あくまでも、オブジェクト指向は手段で、

目的は「実装時にいかに楽に、そして保守時にいかに楽になれるか」というところにあります。

それを意識せずにただただクラス化するだけだと、

逆に辛くなることだって起こりえます。

(辛くなったことがある)

そこらへんの話がこの本にかいてあります(もっかい読みたい)

https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E8%A8%AD%E8%A8%88%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-Ruby%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8B-%E9%80%B2%E5%8C%96%E3%81%97%E3%81%A4%E3%81%A5%E3%81%91%E3%82%8B%E6%9F%94%E8%BB%9F%E3%81%AA%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E8%82%B2%E3%81%A6%E6%96%B9-Sandi-Metz/dp/477418361X

DDDのリポジトリについてちょっとしらべた

f:id:karoten512:20180722231817p:plain

いきさつ

昔書いていたアプリケーションがあまりにあまりなので、

(モデルの責務がいたるところに染み出している)

DDD使って書き換えられないか検討するために勉強を始めた(1日目)

Repositoryからやっていきます

Repositoryについて

エンティティの永続化を担当する。

あと、エンティティの検索を担当する。

使われているところ&メリット

主にServiceクラスで使用されている。

ただし、Serviceクラスが依存しているのはRepositoryクラスそのものではなく、

Repositoryのinterfaceに依存している。

<?php
class UserService {
    private $_userRepository;
    public function __constructor(IUserRepository $userRepository) {
        $this->_userRepository = $userRepository;
    }
} 

なので、もし別のリポジトリを使うことになってもServiceクラスを書き換える必要はない。

つまり、ORMを別のものに替えたり、もっと簡易なクエリビルダ的なものにしたりすることができる。

感想

そもそも今までActiveRecordパターンを使ったフレームワークRails, FuelPHPのORM)での開発がほとんどで、

永続化したり検索したりする部分も"Model"でやっていたので新鮮。

ただ、まだちゃんとしたメリットまではわかっていない。

これから勉強していく。

JavaScriptのgetter, setterについて復習してみた

getter, setterとは

オブジェクトに値を代入したり、

参照したりする時に呼ばれる関数のこと。

書き方

set {プロパティ名}(value) {
  // 処理
}
get {プロパティ名}() {
  // 処理
}

のように書く

実例

var obj = {
    set value(val) {
        this._value = val + 1;
    },
    get value() {
        return 'getterからは' + this._value + 'を返す' 
    }
}
obj.value = 1; // setterが呼ばれる
console.log(obj.value); // getterからは2を返す ←getterが呼ばれている

用途

値をセットしたり、値を参照したりする時、

決まった処理をする際に便利。

json-serverが鬼のように便利で、しかも可愛かった

f:id:karoten512:20180512165110p:plain

いきさつ

APIのmockがほしかった。

今までexpressとかで実際にAPIをつくっていたのだが、

ちょっとめんどくさくなってきた。

何かいい方法がないかな〜と思ってたら「json-server」という良さげなものがあったので試してみた。

github.com

install

npm install -g json-server

jsonデータを用意

db.jsonというファイルを用意する。

{
  todos: [
    { id: 1, content: aaaa, done: false },
    { id: 2, content: bbb, done: true },
    { id: 3, content: ccc, done: true }
  ]
}

json-serverを起動

db.jsonというファイルを同ディレクトリ内に用意。

json-server --watch db.json

f:id:karoten512:20180512164253p:plain

絵文字がかわいい。

localhost:3000にアクセス

f:id:karoten512:20180512164428p:plain

こっちもかわいいかよ。

localhost:3000/todos/1 にアクセス

{
  "id": 1,
  "content": "aaaa",
  "done": false
}

しっかり返ってきてる。

まとめ

GETしか試していないが、

ドキュメントに

GET    /posts
GET    /posts/1
POST   /posts
PUT    /posts/1
PATCH  /posts/1
DELETE /posts/1

とあるのでいろいろ使えそう。

あとかわいい(重要)