読者です 読者をやめる 読者になる 読者になる

2016振り返りと2017目標

毎年恒例になってきた。
2015振り返りと2016目標

Run

  • 目標
    • 600km ( 月50km )
  • 結果
    • 274km ( 月50km達成は1ヶ月 )
    • 昨年との差3.1km
      • もしかしたら、270kmくらいが自身の限界なのか?!
    • 4月にジムに入会し、出社前にトレッドミルのランに挑戦したが3ヶ月目で失速
      • 出社前にジムにいくという習慣を2ヶ月くらい続けられたのは楽しかった

Learn ( TOEIC )

  • 目標
    • over 600
  • 結果
    • 520どまり

Learn ( Other )

  • 目標と結果 ( 2015のブログから )
    • ハミガキ習慣の更新
      • なんだそのアプリという状態
    • Lomdの開発を進めたい
      • 特に理由はないが、進めるモチベーションがゼロだった
    • 実装方法、種類を学ぶ
      • OOP / UML
        • OOPに関してはPHPの復習とデザインパターンの理解
        • UMLについては、特に意識しては取り組んでいない。パターンの説明で確認したくらい
      • Write Code Everyday
        • 特に意識せずで、10月半ばくらいから11月にかけて少々
        • 2016 のGithubでは141Contributions(PublicRepo)
        • BitBucketにも少々
  • 目標にない部分
    • AppleWatchアプリの実装
      • Swift3 + Kanna + Alamofireを利用してWatchアプリで遊んでみた
    • Ruby関係
      • Railsチュートリアルを進めた(未完走)
        • Rails5Verになったので、今年再度試してみる
      • TokyoRubyKaigi, RubyKaigi(京都)に初参加
        • Ruby書いてないのに、結婚後初の1人旅行の言い訳?として京都に行ってきた

他に年始に考えていた事

  • 環境変化
    • 2016/7に引っ越し
    • 2016/11より新しい職場への転職
  • 家族
    • 育休は取得せずに退職し、新しい仕事までの間に意図的に多くの休みを挟んだ
    • 目的は2つ
      • 育休のような期間を作り、少しでも家族との時間を作りたかった
        • 両実家に帰省し、多くの時間と思い出を作る事が出来た
      • 前々から時間をかけて学びたかったフレームワークや、テストとCI、実装方法を理解する

2017目標

  • 追記予定

雑感

いろいろ考えながら振り返ってたら考えがまとまらず時間オーバー
続きは近日

今年の書き初めはPHPでした

昨年はJavaで書いたと思うが、今年はPHP

PHP5.4から利用できるTrait(Scalaでも同名)とInterfaceを利用した場合、 お作法としてTraitとInterfaceはセットで定義しておく。

理由としては、Traitは型宣言に利用できない(タイプヒント出来ない)為、 メソッドが特定の型を要求する場合は、タイプヒントする為にInterfaceを定義しておく必要がある。 (独習PHP10.5.4より参照で、この文の意味が理解不足)

・型を継承するインターフェース
・実装を継承するトレイト

この違いは理解したと思うが、メソッドが特定の型を要求する場合の為にInterfaceを定義しておくという 説明についてはコードレベルで理解出来ていない。

<?php

// 型を定義
interface IFax {
    function send();
}

interface IPrinter {
    function printer();
}

// 実装を定義
trait FaxTrait {
    public function send() {
        print 'sending Fax...sended!';
    }
}

trait PrinterTrait {
    public function printer() {
        print 'printing ... complete!';
    }
}

class FaxPrinter implements IFax, IPrinter {
    use FaxTrait, PrinterTrait;

}

$fp = new FaxPrinter();
$fp->send();
$fp->printer();

AppleWatchを活かしたい

ただそれだけ。

最近は完全にSuica端末になりきっているAppleWatch。
走っているときはRunkeeperの子機として十分に役立つが、日常生活では?

完全にFitbitが一枚上手。なぜかといえばバッテリーライフの関係から、睡眠中もつけていられる。
そうなると、睡眠時間のデータもFitbitに入るため、つけない訳にはいかなくなる。

そんな中、社内LTを行うという事があり、これはチャンスと実装をした。
家の近くのバス停に到着するバスの時間を、Webページから取得しWatchに表示するだけの機能。

実際にやってみるといろいろハマった。

ハマったこと

  • そもそもiOS / watch OSと複数のターゲットが存在する(CodeSigning)
  • table view とラベルの紐付け
  • watch OSのデバッグは(process を atach する必要がある)
  • Cocoa Pods を利用する場合は、xxx.xcodeproj -> xxx.xcworkspace を利用する
  • Httpクライアント(Alamofire)の利用方法
  • HTML parser(Kanna)の利用方法
  • 取得したいページがhttpなので、ATS無効
  • 実機で確認する為のXcode + iPhone + Apple Watchの設定というかデバッグする為の設定
  • Apple Watch のイベント(awake -> willActive -> didDiactive)

このあたりは細かくブログに書きたいが、今日はクリスマスという事で家族との時間に充てる。

AppleWatchが認識されない

Xcode8 WatchOS3.1

error 内容

  • Xcode の実機選択で + (paired device unavailable for development)と表示される

対応

このあたりの手順で改善した。 なぜかたまに起こるが、いつのまにか直っている事がおおい。

参考記事

PHPでTemplate Method パターン

DBへの接続オブジェクトを継承した各テーブル毎のクラスでinsert() / update() 実装を想定

  • ハリウッドの法則
    • 親クラスが子クラスのメソッドを必要なタイミングで呼ぶ
    • 今回でいくと、regist(親クラス)から子クラスで実装したinsert / update をcallする
  • 同じ処理を集約し、抽象クラス、抽象メソッドとしてインターフェースを用意する
<?php

// DBへの接続、validateを行うようなDB処理のスーパークラスを想定
abstract class DBObject {
    private $target_object;
    public function __construct($obj) {
        $this->target_object = $obj;
    }

    public abstract function insert();
    public abstract function update();
    public function regist() {
        if ($this->target_object->id) {
            $this->update();
        } else {
            $this->insert();
        }
    }
}

// 各テーブルへの実装を、具象クラスでテーブル毎に行う想定
class ObjectA extends DBObject {
    public function insert() {
        // insert 処理
        echo "--insert--" , PHP_EOL;
    }

    public function update() {
        // update 処理
        echo "--update--" , PHP_EOL;
    }
}

// 実際に利用する場合は、idの有無でinsert / update を判定する事を想定
$sample = new stdClass();
$sample->id = 111; // idがありのため、updateを行う
//$sample->id = null;

$obj = new ObjectA($sample);
$obj->regist(); // cliantからはオブジェクトを生成し、registメソッドをcallするのみ。

雑感

さっと思った事を実装してみたが、Template Methodパターンにマッチする仕様なのか不明な部分が残る
他パターンをサンプル実装していく中で、戻って修正する事もあると思う
何か気になる箇所があったら是非コメント下さい

PHPでStrategyパターン

使うメリット

  • メール、SMS、プッシュ通知、今後増える可能性がある通知手段を、他実装に影響せず追加が行える

2016/12/11 に追記し、本記事最下部に変更したソースあり

<?php

// 抽象クラス
abstract class MessageStrategy {
    public abstract function send();
}

// コンテキストクラス
class MessageContext {
    private $strategy;

    public function __construct(MessageStrategy $message) {
       $this->strategy = $message;
    }

    public function send() {
        $this->strategy->send();
    }
}

// 具象クラス
class ConcreteMailMessage extends MessageStrategy {
    public function __construct() {
        // 前処理
    }

    public function send() {
        echo 'mail'.PHP_EOL;
    }
}
class ConcreteSMSMessage extends MessageStrategy {
    public function __construct() {
        // 前処理
    }

    public function send() {
        echo 'sms'.PHP_EOL;;
    }
}
class ConcretePushNotificationMessage extends MessageStrategy {
    public function __construct() {
        // 前処理
    }

    public function send() {
        echo 'push'.PHP_EOL;;
    }
}

$strategy = new ConcreteMailMessage();
$contextMessage = new MessageContext($strategy);
$contextMessage->send();

これから調べる事

  • 送信時にユーザクラスからmail/tel/token などを取得したいが、どのクラスで行うか
  • Userクラスに依存するので、Strategyパターンを使うのではなく、違うパターンが正解かもしれない

追記 2016/12/11

  • Uesrクラスは具象クラスにコンストラクタインジェクションする事にした
    • コンストラクタで注入する事で、各通知処理の前処理が行えると考えた
    • 仮にアプリユーザというクラス(mail / name を持たずtokenだけ持つクラスを利用する事があっても、具象クラスのみ影響があるため、他クラスは影響を受けないと考えた
    • テストコードを追加したい
<?php

// 送信対象のUserクラス
class User {
    private $name;
    private $mail;
    private $tel;

    // 仮に利用するpropertyを定義
    public function __construct($name, $mail, $tel) {
        $this->name = $name;
        $this->mail = $mail;
        $this->tel  = $tel;
    }

    // 仮に名前だけ出力するためにgetter設置
    public function getName() {
        return $this->name;
    }

}

// 抽象クラス
abstract class MessageStrategy {
    protected $user;
    public abstract function send();
    public abstract function __construct(User $user);
}

// コンテキストクラス
class MessageContext {
    private $strategy;

    public function __construct(MessageStrategy $message) {
        $this->strategy = $message;

    }

    public function send() {
        $this->strategy->send();
    }
}

// 具象クラス(Mail)
class ConcreteMailMessage extends MessageStrategy {
    public function __construct(User $user) {
        $this->user = $user;
        // mailに関する前処理
        // ...
    }

    public function send() {
        echo 'mail->to('. $this->user->getName(). ')'. PHP_EOL;
    }
}

// 具象クラス(SMS)
class ConcreteSMSMessage extends MessageStrategy {
    public function __construct(User $user) {
        $this->user = $user;
        // smsに関する前処理
        // ...
    }

    public function send() {
        echo 'sms->to('. $this->user->getName(). ')'. PHP_EOL;
    }
}

// 具象クラス(PushNotification)
class ConcretePushNotificationMessage extends MessageStrategy {
    public function __construct(User $user) {
        $this->user = $user;
        // Push通知に関する前処理
        // ...
    }

    public function send() {
        echo 'push->to('.$this->user->getName(). ')'. PHP_EOL;
    }
}

// 送信対象のテストUserインスタンス
$user = new User('Pさん', 'test@example.com', '090xxxxyyyy');

// Mail送信
$strategy = new ConcreteMailMessage($user);

// $strategyにどのクラスを代入するかでMail / SMS / PushNotification とsend()の振る舞いを変える
// SMS送信
// $strategy = new ConcreteSMSMessage($user);

// Push通知
// $strategy = new ConcretePushNotificationMessage($user);

// Contextクラスにstrategyクラスを注入
$contextMessage = new MessageContext($strategy);

// 送信処理 注入されたオブジェクトのsend()メソッドをcall
$contextMessage->send();

// mail->to(Pさん) と出力される

TravisCIで実行したPHPUnitの結果がCoverallsに反映されない

TravisCI Build時のRowLogで、environment variablesをSetしろの文言あり。

Read environment variables
Requirements are not satisfied.
  - TRAVIS='true'
  - TRAVIS_JOB_ID='1713xxxxx'
  - CI_NAME='travis-ci'
  - COVERALLS_REPO_TOKEN='********(HIDDEN)'

Set environment variables properly like the following.
For Travis users:

  - TRAVIS
  - TRAVIS_JOB_ID

対応としてTravisCIのEnvironment VariablesにSet

TravisCI Repository > Settings > Environment Variables
参考:php-coveralls issue

export CI_BUILD_NUMBER="$TRAVIS_BUILD_NUMBER"
export CI_PULL_REQUEST="$TRAVIS_PULL_REQUEST"
export CI_BRANCH="$TRAVIS_BRANCH"

f:id:tbrhdys:20161029001340p:plain

こういう場合は、UIからではなく、.travis.yml の before_script; にexport書くのが良いのか。