デザインパターン「Observer」

仕事中に登場したので復習を兼ねて書きます。 デザインパターンの内容は結城浩『増補改訂版 Java言語で学ぶデザインパターン入門』を参照しています。

何がうれしいパターンなのか

観察対象(Subject*1)が変化したときに、観察者(Observer)に通知します。 状態変化に応じて、処理を記述できるようになります。

クラス図

f:id:alek3:20180924000503p:plain デザインパターン本で頻出の、交換可能性を実現しています。

右側のObseverはインタフェースでも可。例ではインタフェースになっていました。

なお、Observerパターン自体にはSubjectに変化をもたらすものは登場しないので、例ではSubject内にexecuteとして実装されています。

import java.util.ArrayList;
import java.util.Iterator;

// Subject
public abstract class NumberGenerator {
    private ArrayList observers = new ArrayList();
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    public void deleteObserver(Observer observer) { 
        observers.remove(observer);
    }
    public void notifyObservers() {               
        Iterator it = observers.iterator();
        while (it.hasNext()) {
            Observer o = (Observer)it.next();
            o.update(this);
        }
    }
    public abstract int getNumber();  // getSubjectStatusにあたる
    public abstract void execute();  // デザインパターン範囲外
}
import java.util.Random;

// ConcreteSubject
public class RandomNumberGenerator extends NumberGenerator {
    private Random random = new Random();   
    private int number;             
    public int getNumber() { 
        return number;
    }
    public void execute() {
        for (int i = 0; i < 20; i++) {
            number = random.nextInt(50);
            notifyObservers();
        }
    }
}

java.util.ObserverインタフェースとObservableクラス

JDK1.0から、Observerパターンの一種がObserverインタフェースとObservableクラスによって備えられています。 しかし、書籍内では、subject役がObservableクラスを使う必要があるといった理由から、これらは使わずに自前で実装するのが良いとしています。

その主張は理解できますが、一方でその手法は原始的すぎるように感じ、より洗練された手法はないかと探してみることにしました。

Observerがdeprecatedになったことについて

stackoverflow.com

Java9になってObserverやObservableがdeprecatedになったと書いてあります。
その理由について、Raviさんは以下の通り述べています。

  • シリアライズできない
    • ObservableがSerializableを実装していないため
  • スレッドセーフでない
    • イベント通知の順番が保証されず、別のスレッドでも起きうる
  • イベントモデルがしょぼい
    • 何かが変わったという通知は出せるが、何が変わったかという情報が得られない

また、ベストアンサーにあるように、それらはレガシーコードであるため、直すより取り潰したほうが早いという総合的な理由があります。
全体的にそりゃdeprecatedされるわという印象です。

代わりに何を使うかという話ですが、java.beans.PropertyChangeListenerが挙げられています。

まとめ

やろうとしていることは理解できますが、その手段としては、Observerパターンそのものでは古いという印象を持ちます。そこらへんの進化とかモバイルの関わり*2とかを調べたかったのですが進みきれませんでした。

デザインパターンシリーズ

alek3.hatenablog.com

その他記事

qiita.com

タイトルの形式をここと同じように『デザインパターン「○○」』にしました。全般的にデザパタ本をかなり丸々引用していて大丈夫か感は少しだけありますが、噛み砕かれているのとプラスアルファの記載もあって読みやすいです。

*1:observableでもある

*2:RxJavaとかFlowなどのワードは出てきたが調べるところまで行っていない

伊藤祐策さんの「Webエンジニアの求人」ツイートに回答する

このツイート見て、見えっ張りな僕と自己評価の低い僕がせめぎ合いました。

見栄「いやいやさすがに全部わかるっしょ、ねぇ?」
自己「全部完璧に説明できるのかよ、俺には無理だよ説明してみろよさあ」
見栄「……一部調べて回答させていただきます。」

そんなわけで復習を兼ねてこれらのツイートの項目に回答していきます。 各項目の後ろの一言は、最初に頭に浮かんだ言葉です。

OSI参照モデルとは?~7つあるアレ~

OSI(Open Systems Interconnection)参照モデルとは、国際標準化機構(ISO)により策定されたコンピュータなどの通信機器の通信機能を、階層構造に分割したモデルです。*1

言い換えると、ネットワーク通信を相互に行うために制定されたプロトコルです。

OSI参照モデルは以下の7層で成り立っており、各層は互いに独立しています。

階層 名前
第7層 アプリケーション層
第6層 プレゼンテーション層
第5層 セション層
第4層 トランスポート層
第3層 ネットワーク層
第2層 データリンク層
第1層 物理層

それぞれの説明は長くなるので省略します。

TCP/IPとは?~4層あたりのアレ~

TCP/IPとは、現在のネットワークのデファクトスタンダードプロトコル*2です。 OSI参照モデルがあくまでモデルであるのに対し、TCP/IPは現在のネットワークで使われている技術の集合です。

TCPOSI参照モデルで言うところの主に第4層、IPは第3層にあたります。 それぞれどんな仕組みなのかは省略します。*3

POSTとGETの違い~動詞で考えればええ~

どちらもHTTPメソッドの一つです。

『Webを支える技術』では、以下の説明がなされています。

GETは指定したURIの情報を取得します。 POSTの代表的な機能は、あるリソースに対する子リソースの作成です。

Getは冪等であり(何度やっても結果が同じであり)、かつ安全であるが(既存のリソースに変化をもたらさない、すなわち副作用がないが)、POSTは冪等でなく、安全でもないという違いもあります。

SQLインジェクション対策~プレースホルダーでしょ?~

SQLインジェクションとは、主にWebアプリケーションの脆弱性をついて、任意のSQLを実行させることを言います。SQLインジェクションが成功してしまうと、保有しているデータが流出したり、改ざんされてしまったりします。そのためSQLインジェクションを防ぐための対策が絶対に必要になります。

有効な対策の一つには静的プレースホルダーがあります。要するにユーザーの入力を反映させる場所を予め決めておいて、実行されるSQLを想定内のものにする仕組みです。

XSSとは?~クロスをXって表すのかっこいい~

クロス・サイト・スクリプティングと読みます。 いわゆる徳丸本では、以下のように説明されています。

通常、Webアプリケーションには外部からの入力などに応じて表示が変化する箇所があり、この部分のHTML生成の実装に問題があると、クロスサイト・スクリプティング(Cross-Site Scripting)という脆弱性が生じます。

WebアプリケーションにXSS脆弱性がある場合、クッキー値を盗まれてなりすましの被害にあうといった問題が発生しえます。

サラッと書きましたが被害としては結構重いのでしっかり対策を打つ必要があります。

XSS脆弱性の対策としてあげられているのは、HTMLで特殊な意味を持つ記号文字(メタ文字)をエスケープすることです。

公開鍵暗号とは?~秘密鍵と公開鍵~

暗号とは他人に勝手に自分のファイルを読まれないように変換する手法ですが、暗号化するための「鍵」の種類は大きく2つあります。共通鍵と、公開鍵です。

公開鍵暗号方式では、自分しか持たない秘密鍵と、他人に公開する公開鍵があります。あるファイルを公開鍵で暗号化すると、それは自らが保有するペアの秘密鍵でのみ、復号できます。

公開鍵暗号方式は、暗号鍵をいかに安全に相手に渡すかという鍵配送問題を解決する方法であり、結城浩『暗号技術入門』では

公開鍵暗号は、暗号の歴史における最大の発明であるといえるでしょう。

と述べられています。

同書籍では公開鍵暗号の欠点も2点あげられています。

  • 対称暗号と比較して処理が何百倍も遅い
  • 公開鍵が信用できるものか判断しなければならない

これらの欠点を克服するための仕組みとして、それぞれハイブリット暗号システム、公開鍵の認証があります。

まとめ

説明足りないなという自覚はありますがこれくらいにさせてください。何も見ずにほぼ書ききったのもあればかなり調べて書いたものもありました。一方、どのトピックスでも「この本を読めば、またはこのサイトを見れば必要なことが書いてある」という状態にはなっていたのでそれは良かったかなと。

参考文献

『まんがでわかるLinuxシス管系女子①』まとめたった

まんがでわかるLinux シス管系女子(日経BP Next ICT選書)

まんがでわかるLinux シス管系女子(日経BP Next ICT選書)

まとめたった(死語)

前回記事の続きで、今回は既刊3巻中の最初の1巻を読みました。

前半(第1話~第13話)はLinuxの頻出コマンドが紹介されていて、後半(第14話~第24話)からシェルスクリプトの書き方の話になります。

後々私が振り返るために、トピックスを挙げておきます。

前半トピックス

  • 第1話:他のコンピュータをリモート操作したい
  • 第2話:一時的に管理者権限で操作したい
    • sudo
  • 第3話:さまざまな語句を一度に検索したい
    • grep
    • grep -r -i -E "((やまだ|山田) *(たろう|太郎) | yamada +tarou)" ディレクトリのパス
    • -rが再帰検索、-iがignore case、-Eが正規表現の使用
  • 第4話:端末でも対話的にファイルを編集したい
  • 第5話:vimでもコピー&ペースト&アンドゥしたい
    • vで選択モードに入る
  • 第6話:突然の回線切断から復帰したい
    • 仮想端末(ex.tmux)
  • 第7話:他の操作の結果を見ながら作業したい
    • 画面の分割
    • 縦横の分割が可能
  • 第8話:最近実行したコマンドを呼び出したい
    • 上下キーとCtrl+r
  • 第9話:ずっと前に実行したコマンドを呼び出したい
  • 第10話:ネットワーク越しにファイルをコピーしたい
    • scp。双方向可能
  • 第11話:システムの過負荷を把握したい
    • top
  • 第12話:システムのメモリー不足を把握したい
    • sudo service apache2 restart
  • 第13話:ログファイルから必要な行だけ取り出したい
    • パイプライン、zcat

後半トピックス

話数を省略して、トピックスだけ挙げます。

後ろの方になっていくほど、普通のプログラミング言語の話と同じになっていくのが面白かったです。 仕事で引き継いだシェルスクリプトカイゼンしていくヒントにしようかなと思いました。

関係ないけどみんとちゃんがGUI派から割とすぐにCUI派に転向していくのに成長スピードの速さを感じました。

喜怒哀楽の大きさは最初から健在で読んでて楽しいです。

まんがでわかるLinux シス管系女子3 がめっちゃイイ

タイトルの書籍を読み終わりましたのでレビューを書きます。

まんがでわかるLinux シス管系女子3 (日経BPパソコンベストムック)

まんがでわかるLinux シス管系女子3 (日経BPパソコンベストムック)

読み始めたきっかけ

友人がパーソナリティを務めているPodcast「しがないラジオ」で、この書籍の著者がゲストとして出演していた回を聞いたのがきっかけです。

shiganai.org

確かその中で著者のPiroさんが、「ただコマンドを列挙しているだけではなく、実際に使う場面が想像しやすいように描いた」ということをおっしゃっていた(気がする)ので、いつか読んでみたいなと思っていました。

レベル感

Linux触り始めたけど、仕組みがよくわからない、実際のところ何ができるのかもっと知りたい、そんな人向けかなと思います。もっというと私向けでした。

Amazonのレビューを見ると1,2巻よりは難しくなっているようです。

ちなみに帯には「かけだしITエンジニア必読!」と書いてあります。私がかけだしです。

感想(内容)

「ネットワーク & セキュリティ入門」とサブタイトルにあるように、そのような話題が中心になります。

特にトンネリングの話は非常にためになりました。

第6話・第7話はトンネルを掘って目的のサーバーに接続しに行く話です。それぞれ、手元PCのターミナルからファイルコピー、ウェブブラウザからウェブサーバーへの接続になります。

第7話のセリフを引用しますが、

「トンネルを通す」っていうのは、あくまでそのサービスで通常使われるポート番号とは違うポートを使ってサービスに接続するってことだけのことなの
接続に使うクライアントアプリケーションによってポート番号を指定する方法は違うのよ

クライアントアプリケーションは他にもあるでしょう。例えば私が普段使っているIntelliJ IDEAはデータベースに接続する機能があります。ここでトンネルを使うと、例えば踏み台サーバーを経由してプライベートサブネットにおいてあるRDSの中身を参照することができます*1。IDEAで設定する設定先は、「localhost:53306」とかになります。

感想(その他)

たくさんあるので箇条書きで。

  • 内容盛りだくさん!
    • 字が漫画にしては小さめで「うおっ、これは気合い入れて読まねば……」となりました
  • 1話8ページでうまくまとまっている
    • 描かれているトピックの取捨選択が巧みなのでしょう
  • ストーリー仕立てになっているのも良い
  • 海上で船に乗って目的のネットワークまでアクセスしにいくのがめっちゃ分かりやすい
    • 漫画のメリットを最大限に生かしている感じです
  • みんとちゃんがかわいい
    • 服装が毎回違うのはめっちゃいい
    • ワンピース着すぎ問題(私も好きです)

次は1巻を読みたいですね。ただ書店だともう売ってないのでAmazonかな。

*1:接続できるのは、手元PCから踏み台サーバーに接続している間だけ

AWSomeDAY 参加感想

AWSomeDAYという、AWSのオフラインセミナーに参加しましたので、つらつら書きます。

私自身は最近AWSを触り始めて、ソリューションアーキテクトの資格も取ったという状況で、レベル感を確かめるために参加しました。

ちなみに無償で開催されていました。調べるとしばしば無料のセミナーが開催されているようです。

取り上げられていたサービスを挙げると以下の通りになります。

  • EC2
  • EBS
  • S3
  • VPC
  • IAM
  • RDS
  • DynamoDB
  • ELB
  • CloudWatch
  • Trusted Adviser

基本的なものが抑えられていると思います。個人的にはIAMあたりは弱いなと思っていたので今回知識補強できてよかったです。IAMロールの実演がありましたがこれが非常に良くて、IAMの中ではIAMユーザーや、IAMグループに比べて分かりづらいIAMロールについてその使い方を端的に見せていただけました。

同様にTrusted Adviserとかどちらかというと守りのサービスも知らなかったことが結構ありました。とりあえずコンソール上で、ビックリマークが出ていたら注視するようにしましょう。

参加者数は今回は200人ほどでした。ハンズオンもなかったためか、PCを持ってきていない人も結構いました。

最後のセッションでAWS資格(ソリューションアーキテクト)保持者がいるか講師が尋ねました。だいたい5人ほどが手を上げていたようです。

その流れで、開発案件を受注するにあたって資格保有者が何名以上というのが条件に上がることがあるという話がありました。

全般としては経験が浅い人向けで、それ以上のレベルに行きたかったら、セミナー中でも紹介されていましたが有償のセミナーに参加してくださいという感じかなと思いました。

ちなみに個別の質問タイムで最近行き詰まった点を質問させていただいたのですが、あんまりいい解決案はいただけませんでした*1。まあもうちょい時間取ってちゃんと見てみたいと思います。

*1:普通にやってたらそんな不具合起きないよ?という感じ

デザインパターン「template method」「Strategy」

最近デザインパターンをまた勉強していたのでその考察点を記載します。

ソースは基本的に結城浩『増補改訂版Java言語で学ぶデザインパターン入門』(デザパタ本)から引用しています。

継承を用いる「Template Method」

Template Methodパターンは、abstractクラスにな抽象メソッドを記載し、それを継承したサブクラスに実装を強制するパターンです。 すると、似たような動きをするメソッド群を一つのabstract classの下に集結させることができます。

public abstract class AbstractDisplay { 
    public abstract void open();        
    public abstract void print();       
    public abstract void close();       
    public final void display() {       
        open();                             
        for (int i = 0; i < 5; i++) {       
            print();                    
        }
        close();                            
    }
}

継承したサブクラスは以下のようになります。

public class CharDisplay extends AbstractDisplay {  
    private char ch;                                
    public CharDisplay(char ch) {                   
        this.ch = ch;                               
    }
    public void open() {                           
        System.out.print("<<");                     
    }
    public void print() {                           
        System.out.print(ch);                       
    }
    public void close() {                           
        System.out.println(">>");                  
    }
}

これにより何が嬉しくなるかというと、Displayクラス群を他の場所で使いたい場合、それが具体的にどのサブクラスなのかを気にしなくてよくなります。

public class Main {
    public static void main(String[] args) {
        AbstractDisplay d1 = new CharDisplay('H');                  
        AbstractDisplay d2 = new StringDisplay("Hello, world.");    
        d1.display();                                               
        d2.display();                                               
    }
}

Mainクラスで AbstractDisplayクラスに代入する必然性は、これだけでは見えづらいように見えますが…。

委譲を用いる「Strategy」

Template Methodの関連パターンとして紹介されているのが、Strategyパターンです。extendsではなくimplementsが使われています。

デザパタ本では、じゃんけんを例に手の出し方を決めるStrategyインタフェースを記載しています。

public interface Strategy {
    public abstract((別にここはabstractでなくてもいい気がする)) Hand nextHand();
    public abstract void study(boolean win); // 勝敗に応じて手を変えることを想定
}

出す手を決めたり、勝敗数を保持したりするPlayerクラスは以下になります。

public class Player {
    private String name;
    private Strategy strategy;
    private int wincount;
    private int losecount;
    private int gamecount;
    public Player(String name, Strategy strategy) {        
        this.name = name;
        this.strategy = strategy;
    }
    public Hand nextHand() {                                
        return strategy.nextHand();
    }
    public void win() {                 
        strategy.study(true);
        wincount++;
        gamecount++;
    }
    public void lose() {                
        strategy.study(false);
        losecount++;
        gamecount++;
    }
    public void even() {               
        gamecount++;
    }
    public String toString() {
        return "[" + name + ":" + gamecount + " games, " + wincount + " win, " + losecount + " lose" + "]";
    }
}

Strategyインタフェースを実装したクラスは省略します。

「継承より委譲」の理解とデフォルトメソッド

やっていることが類似している継承と委譲ですが、調べてみると「多くの場面で、継承より委譲を用いるべき」という主張(定説?)がありました。 が、これが元を辿ろうとするとはっきりした記述をネット上で見つけられず、一旦保留とします。

僕が言えそうなのは疎結合にできるならするべきだし、委譲ならそれが実現しやすかったよねということです。

しかし、Java8ではデフォルトメソッドが登場したことにより、ますます両者の区別が難しくなったように見えます。

d.hatena.ne.jp

導入の背景について調べてみましたがこれしか出てきませんでした。

Java SE 8のラムダ式の基礎──なぜ必要なのか? 従来記法のリファクタリングを通して、その本質を理解する - page3 - builder by ZDNet Japan

これってJava側の都合では?って印象を受けました。まあしかし深いところについては分からず……。

『Clean Code アジャイルソフトウェア達人の技』を読んで心に残った3つのフレーズ

こちらの技術書をざっと読みましたので、心に残った3つのフレーズを紹介していこうと思います。

Clean Code アジャイルソフトウェア達人の技

Clean Code アジャイルソフトウェア達人の技

コメントとは常に失敗なのです。

おそらくこの本を今回読んでいて最もハッとしたのが4章の冒頭にある上の一文です。

コメントを書く目的は、読んでも分かりづらいコードの内容を補足説明するためだと思いますが、コメントなんかなくてもコードを読んでわかるようにできればそれが一番いい、というのが作中での主張です。

「読解しづらいコードになったからコメントを書こう」ではなく、「コメントを書かずに済むようにコードを改良できないか?」と考えるべきなのです。

懇切丁寧なコメントを書くことがよいプログラムへの第1歩だとなんとなく思っていた僕にとっては、かなり衝撃的な主張で、これ以降を真面目に読み進めるようになりました。

ちなみにコメントについては当たり前というか笑ってしまうような記載もありました。例えば「 /* add by alek3 */ やめろ」みたいなことが書いてあり、昔常駐していたプロジェクトに思いを馳せました。

熟練したプログラマなら、オブジェクト指向が常に優れているという考え方が神話であることを理解しています。

「手続き型っぽいコードの書き方と、オブジェクト指向っぽい書き方がある*1」というのはプログラムを書くようになるとすぐに耳にしますが、その分かりやすい例が紹介されていました。 まずは手続き型っぽい書き方は以下のとおりです。

public class Square {
    public Point topLeft;
    public double side;
}

public class Rectangle {
    public Point topLeft;
    public double height;
    public double width;
}

public class Circle {
    public Point center;
    public double radius;
}

public class Geometry {
    public final double PI = 3.141592;

    public double area(Object shape) throws NoSuchShapeException{
        if (shape instanceof Square){
            Shape s  = (Square)shape;
            return s.side * s.side;
        }
        else if (shape instanceof Rectangle) {
            // 四角形面積計算処理
        }
        else if (shape instanceof Circle){
            // 円の面積計算処理
        }
        throw New NoSuchShapeException();
    }
}

次にオブジェクト指向っぽい書き方です。

public class Square implements Shape {
    private Point topLeft;
    private double side;

    public double area() {
        return side * side;
    }
}

public class Rectangle implements Shape {
    private Point topLeft;
    private double height;
    private double width;

    public double area() {
        return height * width;
    }
}

public class Circle implements shape {
    // 略
}

この2つの書き方で、実現できることは同じですが、拡張のしやすい点が異なります。手続き型の場合、新たな関数の追加は容易ですが、新しいクラスを追加するのは手間です。例えば、周りの長さを求める関数 around を追加するのは容易ですが、三角形のクラス Triangle を追加するためには関数を書き換える必要があります。オブジェクト指向の場合は逆になります。

「複雑なシステムでは、新たな関数を追加することよりも、新たなデータ型を追加することのほうが多い」ため、オブジェクト指向を採用したほうがいい場合が多いというロジックです。

小さいこと!

関数であれクラスであれ、とにかく小さく分割することを主張していました。大きい関数やクラスは複雑化し、あとでメンテする人が大変な思いをすることになります。関数に関してはさらに、引数を減らすことも大事です。

クラスを分割する指針として、SRP(Single Responsibility Principle、単一責務の原則)の話も出てきます。どういう状態がSRPであるか、読んでいるだけでは今ひとつわかりませんでしたが、

  • クラスの概要を日本語でおよそ100字以内で表せること
  • 「もし」「そして」「あるいは」「しかし」といった単語が含まれないこと

この2つが満たされているべきと述べられています。

補足

発行日付

この書籍自体の発行は2017年ですが、原書は2008年であり、一部情報が古いところがあります。例えばMapに関する記述であったり、フレームワークの記述であったりです。

デザインパターン

本書ではデザインパターンがいくつか登場しています。例えば、

  • Adapter
  • Decorator
  • Factory Method
  • Template Method

があります。デザインパターンは20以上あり、全部一度に覚えようとするとなかなか大変*2なのですが、今回のように数個再登場するのでいいタイミングで復習することができました。

*1:関数型言語については記述がなかったと思います

*2:Javaを書き始めたころ、結城浩デザインパターン本を読んで挫折した