うごく生ゴミプログラマの備忘録

うごく生ゴミ 〜再臨〜

「UXデザイン入門」読みました

www.amazon.co.jp

↑の「UXデザイン入門」を読んだ。

というのも、UIを作る技術があっても、UIといっしょに語られることが多いUXについてほとんど勉強したことがなかったので。

本の内容としては、UXを設計する過程で行うべきアンケートとかインタビューとかの方法が詳しく解説されていた。

一方で「UXデザイン入門」と言っているだけあり、どういう場合にどういうコンポーネントを使うと効果的とかいう話はほとんどなかった。そもそも、そういう定石みたいなものなんて無いのか。

面白いなーって思ったのは、設計する上で、そのアプリケーションを使用想定するターゲット(ペルソナ)を詳細に(名前や趣味まで)設定すべきっていうところで、はぁーなるほどぉってなった。

まる。

React + gulp サンプル

Material Design Lite

www.getmdl.io

React

facebook.github.io

React使いつつ、マテリアルデザインも使いたいなーと思って、Material Design Lite を組み合わせてみた時のメモ。

ビルドツールには gulp を使用したので、まず gulpfile.js から。

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var plumber = require('gulp-plumber');
var browserify = require('browserify');
var source = require("vinyl-source-stream");
var reactify = require('reactify');
var buffer = require('vinyl-buffer');


gulp.task('dist', function(){
  var bundler = browserify('./script/src/main.jsx', { debug: true });
  return bundler
        .transform(reactify)
        .bundle()
        .pipe(plumber())
        .pipe(source('build.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('./script/dist/'));
});


gulp.task('watch', function() {
    gulp.watch('./script/src/*.js', ['dist']);
    gulp.watch('./script/src/*.jsx', ['dist']);
    gulp.watch('./script/src/**/*.js', ['dist']);
    gulp.watch('./script/src/**/*.jsx', ['dist']);
});


gulp.task('default', ['dist', 'watch']);

次に HTMLファイル。 body要素の最後で、ビルド後のjsファイルを読み込むようにする。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>test</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link href="./style/material.min.css" rel="stylesheet">
    <link href="./style/style.css" rel="stylesheet">
  </head>
  <body>
    <noscript>JavaScriptを有効にして下さい。</noscript>
    <div id="appView"></div>
    <script src="./script/dist/build.js"></script>
  </body>
</html>

エントリーポイントとなる main.jsx 3行目で、Material Design LiteのJavaScriptを読み込んでいる。 6行目で読み込んでいる AppView.jsx がルートコンポーネント

(function () {
    'use strict';
    var mdl = require('material-design-lite');
    var React = require('react');
    var ReactDOM = require('react-dom');
    var AppView = require('./component/AppView.jsx');

    // アプリケーション全体のコンポーネントを表示
    ReactDOM.render(
        <AppView />,
        document.getElementById('appView')
    );

}());

Go言語インストールからHelloWorld、あと特徴とか忘れないうちにメモっとく

インストール手順

MacにHomebrewを使ってインストールした。Homebrewはインストール済の前提。

$ brew install go

バージョンを確認

$ go version

Hello World!

package main

import (
  "fmt"
)

func main() {
  fmt.Println("Hello World!")
}

Hello World 実行手順

自分は以下のような sh ファイルを作った。

今回はとりあえず test.sh という名前で保存した。

export GOPATH=任意のパス
export PATH=$PATH:$GOPATH/bin
cd ${GOPATH}
go install ./src/github.com/jsuzuki20120311/go_test

Hello Worldのソースが書けたら、

$ ./test.sh

その後、別窓でターミナルを開いて

$ ./go_test
Hello World!

Hello World! が出力されればめでたしめでたし。

その他、Hello Worldやる過程で調べてわかったこととかメモ

クラスなんてものは無い 代わりに 構造体 なるものがある

実際に書いてみた。

    type box struct {
        width int
    }
     
    func (b *box) get_width() int {
        return b.width
    }
     
    func main() {
        b := box{width: 10}
        fmt.Println(b.get_width())
    }

他、継承なんてない。コンポジッション関係を使え。あとインタフェースはある。 このあたりを箇条書きにすると

  • is - a 関係 : × 代わりに has - a 使え
  • has - a 関係 : ○
  • can do 関係 : ○

また別の日にもう少し詳しく整理して書こうと思う。

自前でクライアントサイドMVCのModelとView用ライブラリ作った

自前でクライアントサイドMVCのModelとView用ライブラリ作った。

github.com

コンセプトは、以下のような見慣れたクラス定義の書き方を崩さずかけるようにすること。

/**
 * サンプルクラス
 */
var SampleClass = function () {
    // 何か処理
};


/**
 * サンプルメソッド
 */
SampleClass.prototype.sampleMethod = function () {
    console.log('sampleMethod');
};

今回作ったBellTreeMVを使用する場合、例えばModelを定義する場合以下のように書く。

/**
 * サンプルModel
 */
var SampleModel = function () {
    BellTreeMV.Model.call(this);
};

BellTreeMV.inheritPrototype(SampleModel.prototype, BellTreeMV.Model.prototype);

SampleModel.prototype.sampleMethod = function () {
    console.log('sampleMethod');
};

必須なのは

    BellTreeMV.Model.call(this);

BellTreeMV.inheritPrototype(SampleModel.prototype, BellTreeMV.Model.prototype);

の行のみ。 あとは昔からある見慣れたコンストラクタ関数の定義と、prototypeにメソッドを定義しているだけ。

まだまだライブラリと呼ぶにはあまりに拙く機能もすくないけど、わりと自己満足はできてるし、オブザーバパターンの良い勉強になった。

React + browserify 用 gulpfile メモ

React で browserify を使用する場合用のgulpfileを作ったのでメモ。 99%自分のメモ用。

uglify がファイルを縮小させるやつ。 plumber がビルドで失敗しても、ファイル変更の監視をやめないようにするやつ。 reactify がJSXをJavaScriptに変換するやつ。

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var plumber = require('gulp-plumber');
var browserify = require('browserify');
var source = require("vinyl-source-stream");
var reactify = require('reactify');
var buffer = require('vinyl-buffer');


gulp.task('dist', function(){
  var bundler = browserify('./script/src/main.jsx', { debug: true });
  return bundler
        .transform(reactify)
        .bundle()
        .pipe(plumber())
        .pipe(source('build.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('./script/dist/'));
});


gulp.task('watch', function() {
    gulp.watch('./script/src/*.js', ['dist']);
    gulp.watch('./script/src/*.jsx', ['dist']);
    gulp.watch('./script/src/**/*.js', ['dist']);
    gulp.watch('./script/src/**/*.jsx', ['dist']);
});


gulp.task('default', ['dist', 'watch']);

Effective Java の BuilderパターンをJavaScriptで書いてみた

Javaの参考書のなかでよくおすすめと言われている Effective Java で紹介されている Builder パターンを、JavaScript で書いてみた。

Effective Java ってなんやそれ、っていう方はこちら。

Amazon.co.jp: EFFECTIVE JAVA 第2版 (The Java Series): Joshua Bloch, 柴田 芳樹: 本

普通に Java で書かれたコードについてはこちら。Effective Java で紹介されているBuilderパターン意外も紹介されています。とてもわかりやすかったです。

Javaで書くBuilderパターンのパターン - Qiita

Builder パターンを使用しない場合

ここでは、以下のユーザ情報を登録できるシステムを想定して、ユーザ情報を保持するオブジェクトの生成を例にみていく。 * 名前(必須項目) * 年齢 * 郵便番号 * 住所 * 血液型 * 星座 * 好きな食べ物

以下 Builder パターンを使用しない場合のコード。 引数ですべての属性を指定している。

/**
 * ユーザクラス
 * @param {String} name          
 * @param {Number} age           
 * @param {String} postalCode    
 * @param {String} address       
 * @param {String} phoneNumber   
 * @param {String} boodType      
 * @param {String} constellation 
 * @param {String} favoriteDish  
 */
var User = function (name, age, postalCode, address, phoneNumber, boodType, constellation, favoriteDish) {
    'use strict';

    if (!name) {

        throw new Error('必須項目[名前]が未設定です。');
    }

    this.name = name;
    this.age = age;
    this.postalCode = postalCode
    this.address = address;
    this.phoneNumber = phoneNumber;
    this.bloodType = boodType;
    this.constellation = constellation;
    this.favoriteDish = favoriteDish;
};

User.prototype.toString = function () {
    'use strict';
    var string = (' 名前: ' + this.name 
        + ' 年齢: ' + this.age 
        + ' 郵便番号: ' + this.postalCode
        + ' 住所: ' + this.address
        + ' 電話番号: ' + this.phoneNumber 
        + ' 血液型: ' + this.bloodType
        + ' 星座: ' + this.constellation
        + ' 好きな食べ物: ' + this.favoriteDish)
        ;
    return string;
};

// 新規のユーザを作成
var user = new User('数多の世界を救済した勇者 ああああ', 60, 'XXX-XXXXX', '勇者の城(旧魔王の城)', 'XXX-XXXX-XXXXX', 'AB', '乙女座', '牛ヒレ肉とフォアグラのロッシーニ');

このコードの悪いところ (1つめ)

オブジェクトを生成するタイミングで、引数の順番を間違いやすい。 第二引数くらいまでは、まぁ間違わないでしょう。 ただ、第7引数、第8引数にあたりになると、どっちに「星座」で、どっちに「好きな食べ物」設定するんだ?ってなる。

// 新規のユーザを作成
var user = new User('数多の世界を救済した勇者 ああああ', 60, 'XXX-XXXXX', '勇者の城(旧魔王の城)', 'XXX-XXXX-XXXXX', 'AB', '乙女座', '牛ヒレ肉とフォアグラのロッシーニ');

// ↑ こんなに順番覚えていられない。やってられっかばーか ってなる。
このコードの悪いところ (2つめ)

「名前」と「好きな食べ物」だけ設定したい場合も第2引数〜第7引数を指定しなければならない。 コードにすると以下のようになる。

// 新規のユーザを作成
var user = new User('数多の世界を救済した勇者 ああああ', undefined, undefined, undefined, undefined, undefined, undefined, '牛ヒレ肉とフォアグラのロッシーニ');

// こんなの絶対おかしいよ

Builder パターンを使用した例

Builder パターンを使用して、以下のようにコードを改修した。

/**
 * ユーザクラス
 * @param {Builder} builder 
 */
var User = function (builder) {
    'use strict';
    this.name = builder.name;
    this.age = builder.age;
    this.postalCode = builder.postalCode;
    this.address = builder.address;
    this.phoneNumber = builder.phoneNumber;
    this.bloodType = builder.bloodType;
    this.constellation = builder.constellation;
    this.favoriteDish = builder.favoriteDish;
};

User.prototype.toString = function () {
    'use strict';
    var string = (' 名前: ' + this.name 
        + ' 年齢: ' + this.age 
        + ' 郵便番号: ' + this.postalCode
        + ' 住所: ' + this.address
        + ' 電話番号: ' + this.phoneNumber 
        + ' 血液型: ' + this.bloodType
        + ' 星座: ' + this.constellation
        + ' 好きな食べ物: ' + this.favoriteDish)
        ;
    return string;
};

/**
 * ユーザインスタンスを生成するためのビルダークラス
 */
User.Builder = function () {};

/**
 * 名前を設定します。
 * @param   {String} name 
 * @returns {Builder}
 */
User.Builder.prototype.name = function (name) {
    'use strict';
    this.name = name;
    return this;
};

/**
 * 年齢を設定します。
 * @param   {Number} age 
 * @returns {Builder}
 */
User.Builder.prototype.age = function (age) {
    'use strict';
    this.age = age;
    return this;
};

/**
 * 郵便番号を設定します。
 * @param   {String} postalCode 
 * @returns {Builder}
 */
User.Builder.prototype.postalCode = function (postalCode) {
    'use strict';
    this.postalCode = postalCode;
    return this;
};

/**
 * 電話番号を設定します。
 * @param   {String} phoneNumber 
 * @returns {Builder}
 */
User.Builder.prototype.phoneNumber = function (phoneNumber) {
    'use strict';
    this.phoneNumber = phoneNumber;
    return this;
};

/**
 * 住所を設定します。
 * @param   {String} phoneNumber 
 * @returns {Builder}
 */
User.Builder.prototype.address = function (address) {
    'use strict';
    this.address = address;
    return this;
};

/**
 * 血液型を設定します。
 * @param   {String} bloodType 
 * @returns {Builder}
 */
User.Builder.prototype.bloodType = function (bloodType) {
    'use strict';
    this.bloodType = bloodType;
    return this;
};

/**
 * 星座を設定します。
 * @param   {String} constellation 
 * @returns {Builder}
 */
User.Builder.prototype.constellation = function (constellation) {
    'use strict';
    this.constellation = constellation;
    return this;
};

/**
 * 好きな食べ物を設定します。
 * @param   {String} favoriteDish 
 * @returns {Builder}
 */
User.Builder.prototype.favoriteDish = function (favoriteDish) {
    'use strict';
    this.favoriteDish = favoriteDish;
    return this;
};

/**
 * ユーザインスタンスを生成して返します。
 * @throws {Error} 
 * @returns {User} 
 */
User.Builder.prototype.build = function () {
    'use strict';

    if (!this.name) {

        throw new Error('必須項目[名前]が未設定です。');
    }

    return new User(this);
};


var userBuilder = new User.Builder();
var user;
userBuilder
    .name('数多の世界を救済した勇者 ああああ')
    .age(60)
    .address('勇者の城(旧魔王の城)')
    .phoneNumber('XXX-XXXX-XXXXX')
    .postalCode('XXX-XXXXX')
    .favoriteDish('牛ヒレ肉とフォアグラのロッシーニ')
    .constellation('乙女座')
    .bloodType('AB')
    ;
user = userBuilder.build();
ポイント

setter的なメソッド ↓ で builder 自身を返しているところ。

/**
 * 好きな食べ物を設定します。
 * @param   {String} favoriteDish 
 * @returns {Builder}
 */
User.Builder.prototype.favoriteDish = function (favoriteDish) {
    'use strict';
    this.favoriteDish = favoriteDish;
    return this;
};

これにより、jQueryメソッドチェーンとか、Java の StringBuilder の append("~").append("~~~~~").append("") みたいに書けるようになる。イケメン。

改修前のコードの問題が解決されているか

改修前のコードの以下の問題が解決できているかみてみる。

  • 引数の順番を覚えておかないといけない
  • 設定不要なパラメータも指定しなければいけない
var userBuilder = new User.Builder();
var user;

// 各属性を設定する場合、その属性に設定するためのメソッドを呼べばよいため、
// 順番をきにする必要はなくなっている。


// また、設定したくない属性がある場合、
// その属性を設定するためのメソッドを呼ばなければよいため2つ目の問題も解決されている。

userBuilder
    .name('数多の世界を救済した勇者 ああああ')
    .age(60)
    .address('勇者の城(旧魔王の城)')
    .phoneNumber('XXX-XXXX-XXXXX')
    .postalCode('XXX-XXXXX')
    .favoriteDish('牛ヒレ肉とフォアグラのロッシーニ')
    .constellation('乙女座')
    .bloodType('AB')
    ;
user = userBuilder.build();
結論

やっぱりBuilderパターンってすげーや。