footmark

ひよっこエンジニアの足跡

家計簿アプリから学んだ、物事を続けるために必要な3つのこと

この記事は VOYAGE GROUP Advent Canlendar 16日目の記事です。

はじめまして、ECナビ事業本部でエンジニアをしている15新卒の yukimine です。 新卒として配属されてから半年間、「myMoney」というiOSアプリ開発をしていました。

現在はECナビ事業本部で主にサーバーサイドのコードを書いています。

myMoneyとは?

f:id:yuk4420:20151216091239p:plain

myMoneyは

  • 片手で簡単に入力できる
  • 好きな壁紙に着せ替えられる

が最大の特徴のとてもシンプルな家計簿アプリです。

f:id:yuk4420:20151216091300p:plain

手前味噌ですが、他の家計簿アプリが難しいと感じた方にとって、 最後の家計簿アプリだと思っています。 (これ以上簡単なのはないよ!という気持ちを込めて)

何かを始めようとして三日坊主になってしまった

こんな経験、ありませんか?

早起き、筋トレ、日記なんでも構いません。 ちなみに僕は上記3つを三日坊主で終えた経験があります! あるあるですね!(?)

そんな僕が「myMoney」という家計簿アプリをドッグフーディングしていて学んだ、物事を続けるために必要なことを3点紹介させていただきます。

※ 個人の感想であること、故にチラ裏感満載であることをご理解願いますm( )m

1. 「完璧」を捨てる

「継続は力なり」

「千里の道も一歩から」

いろんなことわざにもある通り、何かを新しく始めたときは質よりもまず続けることが大切だと思い、そのために「ラフさ」を意識することから始めました。 (もともと三日坊主気質なので、できるだけハードルを下げようという意図もありました)

具体的に意識したこと
  • 10円未満を切り捨てる(金額が大きいときは1000円未満を切り捨ててました)
    • 108円のおにぎりを100円でつける
  • 金額を忘れてしまった場合は大雑把につける
    • んー、だいたい3000円だっけ
  • 一日書き忘れても気にしない
    • 今日からまた続けよう

2. こまめにやる

「完璧」を捨てても、こまめにやる習慣をつけなければ家計簿は続きませんでした。 実際、家計簿をつけるのが面倒なときは、あとでつけようとレシートをもらっておいたのですが、結局つけず終いに。

とはいえ「こまめにやる」というのは口で言うほど簡単ではありませんよね。 「こまめにやる」という意思以上に、こまめにやれる環境作りが重要なのかもしれません。

具体的な環境作り
  • iPhoneのホーム画面の分かりやすい位置に家計簿アプリを置いておくなど

楽器練習を例に出すと、僕はギターをケースにしまわず枕元に立てかけておくことで、自然と触る(練習する)機会が増えました。 これも環境作りですよね。

3. 結果を求め過ぎない

ある程度、続けることができると、「労力に見合った見返りがない」と思うことがありました。 こんなにまめに家計簿をつけいるのに特に何も変わってないな、と。

そのまま数週間家計簿をつけなくなったこともありました。 つけなくなったらつけなくなったで、支出に対して無防備な自分に危機感を覚え、またつけはじめたのですが。

一旦やめてみることで、見えやすい結果を追いかけていると気付かない「続けることのメリット」もあるんだなと。 今回の場合、支出のグラフなど、アプリが出してくれる結果の他にも、こまめに家計簿をつける過程で自分の支出を意識していたんだなと気付きました。

とはいえ、本当にやめてしまっては続けるもなにもありませんよね。

楽器の練習を続けても成果が出ないからといって、練習をやめてしまっては上手くならないのと似ているかもしれません(?)

結果を求め過ぎず、とはいえ結果を出すことを目標に根気よく「続けて」みてはいかがでしょうか。

継続は力なり

  1. 「完璧」を捨てる
  2. こまめにやる
  3. 結果を求め過ぎない

文字に起こしてみると基本的なことばかりで、改めて「続ける」って物事の基本なんだなあと思いました。

この記事を読んで何か一つでも気付きを得ていただければ幸いです。

kotobank.jp

kotobank.jp

さいごに

ドッグフーディング、おすすめです。

家計簿が続くようになったのも、物事を続けるために必要なことを学べたのも、全てドッグフーディングがきっかけ。

皆さん積極的にドッグフーディングを行って、自分も自社サービスもブラッシュアップしていきましょう!

明日の VOYAGE GROUP Advent Canlendar は @at_grandpa さんです!お楽しみに!

2015年、始まりましたが。

年始に書いたやつ。

サクっと2014年振り返り

2014年の抱負

昨晩、友達の部屋で七草粥を食べました。 正月気分から抜け出し、2014年を全力疾走したいです。 2014年の抱負ですが、 「誠実」 を掲げることに決めました。 今年は成人して2~3年目の年になりますが、与えられた権利に対する責任への意識がまだまだ低く感じます。 自分を見つめ直し、また自分に厳しくあることで、「誠実」を追い求める1年にしたいです。 今年もよろしくお願いします。

これは2014年1月8日にFacebookへ投稿した抱負です。

超サクっと感想を書くと、なんか保守的だったなー です。もっとがむしゃらになりたい。なろう。

とは言ったものの、それなりに充実していました。例えば、

  • 研究(中間発表前と年末)
  • 内定先の研修
  • ユメオチ(オリジナルの弾き語り)
  • ギカダイカンフージェネレーション(アジカンのコピバン)
  • サブ研究室的なもの
  • 友達の結婚式
  • 親戚の金婚式

(超絶箇条書き)

脳内ザッピングしただけなので、きっといろいろ抜けてると思います。

2015年の抱負

スピード覚悟 です。

スピードはがむしゃら感。

覚悟は社会人としての、また内定先のクルーとしての腹くくり。

です。

今年もよろしくお願いします。

【PHPUnit x MySQL】データベースのテスト

PHPでデータベースのテストをするためのメモ。

データベーステストの四段階

データベーステストは次の四段階を踏む必要があります。

Gerard Meszaros は、著書 xUnit Test Patterns でユニットテストを次の四段階に分類しています。
1. フィクスチャのセットアップ (Setup)
2. テストしたいシステムの実行 (Exercise)
3. 結果の検証 (Verify)
4. 後始末 (Teardown

PHPUnit マニュアル - 第8章 データベースのテスト

このテストの仕組みを一から作るのは面倒です。
そこで、PHPUnitDBUnit拡張を使います。

DBUnit拡張を使うことによって、データベースの初期化やテストに使用したデータの後始末をうまくやってくれます。

データベース設定を記述

テストに使うデータベースを設定します。
phpunit.xml にデータベース接続に必要な情報を記述します。

phpunit.xml
<?xml version="1.0" encoding="UTF-8" ?>
<phpunit
    bootstrap="src/autoload.php"
    colors="true">
    <testsuite name="tddbc4">
        <directory>tests</directory>
    </testsuite>
    <php>
        <var name="DB_DSN" value="mysql:dbname=tddbc4;host=localhost" />
        <var name="DB_USER" value="user" />
        <var name="DB_PASSWD" value="password" />
        <var name="DB_DBNAME" value="tddbc4" />
    </php>
</phpunit>

テーブルについて

データベーステストで用いるテーブルは予め用意しておく必要があります。
今回用意したテーブルはこんな感じです。

f:id:yuk4420:20141126173906p:plain

(ER図の関連線の引き方よく分かってない)

ちなみに TDDBC お題 のお題4を通して勉強したのでそのようなテーブルになってます。

初期化に用いるデータの準備

次に初期化に用いるデータセットを用意します。
XMLCSV、Array等、様々な形式でデータセットを用意することができます。

今回はMySQL XMLデータセットを使いました。
データベースにテストデータとするレコードが入っている状態で、mysqldump コマンドの --xml オプションでdumpすることで簡単作成できます。

tests/data_set.xml
<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="tddbc4">
    <table_data name="ng_word">
    <row>
        <field name="id">1</field>
        <field name="name">Arsenal</field>
    </row>
    <row>
        <field name="id">2</field>
        <field name="name">悟空</field>
    </row>
    </table_data>
    <table_data name="user">
    <row>
        <field name="id">2</field>
        <field name="name">taro</field>
    </row>
    <row>
        <field name="id">1</field>
        <field name="name">t_wada</field>
    </row>
    </table_data>
    <table_data name="user_ng_word">
    <row>
        <field name="id">1</field>
        <field name="user_id">1</field>
        <field name="ng_word_id">1</field>
    </row>
    <row>
        <field name="id">2</field>
        <field name="user_id">1</field>
        <field name="ng_word_id">2</field>
    </row>
    <row>
        <field name="id">3</field>
        <field name="user_id">2</field>
        <field name="ng_word_id">2</field>
    </row>
    </table_data>
</database>
</mysqldump>

テストコードの記述

データベーステストを行うためにまず、PHPUnit_Extensions_Database_TestCase 抽象テストケースを継承したクラス(今回の場合、Generic_Tests_DatabaseTestCase クラス)を作ります。
さらに、2つの抽象メソッド getConnection()getDataSet() を実装します。
これらのメソッドはデータベース接続と初期化が目的です。

実際のテストコードは Generic_Tests_DatabaseTestCase クラスを継承したクラスに記述します。

tests/DatabaseTest.php
<?php

// =====
// 引用元
// =====
// PHPUnit マニュアル - 第8章 データベースのテスト
// https://phpunit.de/manual/current/ja/database.html
abstract class Generic_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
    // PDO のインスタンス生成は、クリーンアップおよびフィクスチャ読み込みのときに一度だけ
    static private $pdo = null;

    // PHPUnit_Extensions_Database_DB_IDatabaseConnection のインスタンス生成は、テストごとに一度だけ
    private $conn = null;

    final public function getConnection()
    {
        if ($this->conn === null) {
            if (self::$pdo == null) {
                self::$pdo = new PDO( $GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD'] );
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
        }

        return $this->conn;
    }

    public function getDataSet()
    {
        return $this->createMySQLXMLDataSet('tests/data_set.xml');
    }
}

class DatabaseTest extends Generic_Tests_DatabaseTestCase 
{
    /**
     * @test
     */
    public function 指定したng_wordが検閲に引っ掛かった回数を表示できること()
    {
        $filter = new WordFilter();

        $ng_word = '悟空';
        $num_of_ng_word = $filter->get_num_of_ng_word($ng_word);

        $this->assertEquals(2, $num_of_ng_word);
    }
}

あとはREDとGREENを回すだけです。

実際にデータベーステストを行うと、面倒なことを凄く簡単にできている感があります。

参考

GitHubでdotfilesを管理する

先週も書きましたが、dotfilesをGitHubで管理し始めました。

dotfilesってなに

.vimrc.zshrc など .ほにゃらら なファイルの総称です。
そう、設定ファイル。

GitHubでdotfilesを管理する

手元のマシンを1回設定するだけならまだしも(それでもしんどい)、仮想環境やらサーバやらで同じ作業を何回もするのは嫌だ!構築・保守を簡単に!という要望に答える手段の一つが、GitHubでの管理

やることはシンプルで、

  1. dotfiles ディレクトリ(別に何でも構わない)を作る
  2. dotfiles ディレクトリにGitHubで管理したいdotfileを入れる
  3. シンボリックリンクを貼る

です。
シンボリックリンクを一括で貼るシェルスクリプトなんかを dotfiles ディレクトリに含めておくといいと思います。

例えば、こんな感じ。

install.sh
ln -sf ~/dotfiles/.vimrc ~/.vimrc
ln -snf ~/dotfiles/.vim ~/.vim

まあ、詰まる

ここから詰まったことを3つほど。
何事もそんなうまくは行かない。

循環参照ができてしまった

循環参照っていうのは参照先が参照元を指すことです。
例えば、循環参照を黙々と潜って行くと、
dotfiles/.vim/.vim/.vim/.vim/.vim
みたいな感じになります。

これ(循環参照)、できない方がいいと思うんですが、先のシンボリックリンクを作るとき、ディレクトリへのシンボリックリンクに対して n オプションを付けずに実行すると循環参照が生まれました。

# ディレクトリへのシンボリックリンクに対してnオプションなし
ln -sf ~/dotfiles/.vim ~/.vim

付けましょう、n オプション。

参考

Gitリポジトリの中でGitリポジトリの管理ってどうやるの?

これ、知りませんでした。

プラグインなんかを扱っていると、dotfiles リポジトリの中にGitリポジトリが入ってくると思います。
ですがこれをそのまま push しても「Gitリポジトリです」みたいなアイコンの開けないディレクトリがあがるだけです。
そしてこれを clone しても空のディレクトリが作成されるだけ。

自分で clone すれば解決ですが、それじゃあ楽になりません。

これを解決する方法の一つは git submodule を使うです。

git submodule は癖が強いとかなんとか聞きますが、git submodule しか使ったことがないのでよく分かりません。

git submoduleの使い方

dotfiles ディレクトリ内で

git submodule add [追加したいリモートリポジトリのURL] [ローカルリポジトリのパス]

を叩くと、.gitmodules ファイルと .git/modules ディレクトリにsubmoduleの情報が書き込まれます。

submoduleが管理するのは submoduleに設定したGitリポジトリが現在どのコミットを指しているか です。

これらの情報をdotfiles リポジトリでコミットし、リモートリポジトリにもあげておきます。

clone 後は dotfiles リポジトリ

$ git submodule init
$ git submodule update

を叩くことにより、dotfiles リポジトリで指定されているコミットが設定・pull されます。

submoduleで管理しているGitリポジトリに変更を加えたい

ブランチ切って変更すればいいんじゃね?と思いましたが、管理するリモートリポジトリが存在しないため、clone して新しく環境を作ろうとしたときに困ります。

そこで、submoduleで管理している(しようとしている)GitリポジトリをForkし、それをsubmoduleで管理します(ややこしい)。

Forkってこうやって使うのかと学びました。

僕のdotfiles

そんなこんなで作ったdotfilesがこちらです。

yukimine/dotfiles

YosemiteにしたらHomebrew死んだ

dotfilesをGitHubで管理し始めたので(これもその内メモりたい)Macにもリポジトリをクローンしようと git clone を叩いた矢先!!!

$ git clone git@github.com:yukimine/dotfiles.git
xcode-select: note: no developer tools were found at '/Applications/Xcode.app', requesting install. Choose an option in the dialog to download the command line developer tools.

何じゃこりゃああああ!!!

素直にエラー文を読めばどうってことないんですが、
「あーはいはい。Git入れればいいのね。(あれ?入れてなかったっけ?まあいっか)」
と未読スルーしてしまったのでこの後無駄足を踏むことになります。
(そのおかげでHomebrewが死んでいることに気付けたので良かったのですが。)

MacにGitを入れる方法はいくつかありますが、楽だろうということでHomebrewを選択。
で、コマンドを叩くと。。。

$ brew install git
/usr/local/bin/brew: /usr/local/Library/brew.rb: /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby: bad interpreter: No such file or directory
/usr/local/bin/brew: line 21: /usr/local/Library/brew.rb: Undefined error: 0

エラー文を見た瞬間悟りました。 ああ、これが先輩の言ってた、YosemiteにしたらHomebrew死ぬ現象か と。

続きを読む

【Onsen UI】ページナビゲーション

どうしてもOnsen UIのページナビゲーションを使ってみたかったので、ディスコグラフィページに用いてみます。

続きを読む

Onsen UIでスマホサイトを作る その2

今回は Onsen UI テーマローラーページ をベースに各ページを作成し、スライドメニューコンポーネントを使ったリンクを貼ってみます。

作成するページ

作成するのは音楽活動のサイトなので、必要なページは

  • トップ
  • お知らせ
  • ライブ日程
  • バイオグラフィ
  • ディスコグラフィ
  • ダウンロード
  • お問い合わせ

といった感じでしょうか。

実際にバイオグラフィページを作成してリンクを貼ってみましょう。

スライドメニューからリンクを貼る

まずはスライドメニューに項目を追加し、リンクを貼ります。

Sliding Menuパターンのソースを表示する

先週の復習になりますが、Onsen UI テーマローラーページ を開き、Patternsタブを選択します。
次にSliding MenuパターンのShow Sourceを選択し、ソースを表示します。

ページを分ける

表示したソースはスライドメニューを表示するページ(メインページ)とスライドメニューページが同一ファイルに書かれています。
もちろん、このままの形式で進めていっても良いのですが、このままでは最終的にファイルがものすごく長くなってしまうので、ページごとに分けます。
複数ページを同一ファイルに書く記述である、<ons-template> タグ以下で分けます。
<ons-template> タグは含まない)

ページ遷移の処理に書き換える

表示したソースではメニュー項目をクリックした時の処理が、ng-click="menu.close()" になっています。
これではメニューを閉じるだけでページ遷移が行われないので、ng-click="menu.setAbovePage('[遷移先ファイル名]', {closeMenu: true})" もしくは、onclick="menu.setAbovePage('biography.html', {closeMenu: true})" に書き換えます。

アイコンを選ぶ

Onsen UIの公式ページにもある通り、Font AwesomeIonicons のアイコンを使うことができます。

Onsen UIは、Font Awesomeの400以上のアイコン、そしてIoniconsの500以上のアイコンを使うことができます。

Onsen UIガイド | Onsen UI

アイコンを使うには <ons-icon icon="[任意のアイコン名]"> に書き換えます。

コード例

上記、

  1. ページを分ける
  2. ページ遷移の処理に書き換える
  3. アイコンを選ぶ

の処理を行ったコードが次です。

index.html(メインページ)
<!doctype html>
<html>
    <head>
        <link rel="stylesheet" href="bower_components/onsenui/build/css/onsenui.css">
        <link rel="stylesheet" href="styles/onsen-css-components.min.css">
        <link rel="stylesheet" href="styles/sliding_menu.css">

        <script src="bower_components/onsenui/build/js/angular/angular.js"></script>
        <script src="bower_components/onsenui/build/js/onsenui.js"></script>
        <script>
            ons.bootstrap();
        </script>

    </head>
    <body>

        <ons-sliding-menu main-page="top.html" menu-page="menu.html" max-slide-distance="260px" type="push" var="menu">
        </ons-sliding-menu>

    </body>
</html>
menu.html(メニューページ)
<!doctype html>
<ons-page modifier="menu-page">
    <ons-toolbar modifier="transparent">
        <div class="right">
            <ons-toolbar-button class="menu-close" ng-click="menu.close()">
                </ons-icon>Close
            </ons-toolbar-button>
        </div>
    </ons-toolbar>

    <ons-list class="menu-list">
        <ons-list-item class="menu-item" onclick="menu.setAbovePage('top.html', {closeMenu: true})">
            <ons-icon icon="ion-home"></ons-icon>
            Top
        </ons-list-item>

        <br />

        <ons-list-item class="menu-item" onclick="menu.setAbovePage('information.html', {closeMenu: true})">
            <ons-icon icon="ion-information"></ons-icon>
            Infomation
        </ons-list-item>

        <ons-list-item class="menu-item" onclick="menu.setAbovePage('live.html', {closeMenu: true})">
            <ons-icon icon="ion-mic-c"></ons-icon>
            Live
        </ons-list-item>

        <ons-list-item class="menu-item" onclick="menu.setAbovePage('biography.html', {closeMenu: true})">
            <ons-icon icon="ion-person"></ons-icon>
            Biography
        </ons-list-item>

        <ons-list-item class="menu-item" onclick="menu.setAbovePage('discography.html', {closeMenu: true})">
            <ons-icon icon="ion-music-note"></ons-icon>
            Discography
        </ons-list-item>

        <ons-list-item class="menu-item" onclick="menu.setAbovePage('download.html', {closeMenu: true})">
            <ons-icon icon="ion-cloud"></ons-icon>
            Download
        </ons-list-item>

        <ons-list-item class="menu-item" onclick="menu.setAbovePage('contact.html', {closeMenu: true})">
            <ons-icon icon="ion-paper-airplane"></ons-icon>
            Contact
        </ons-list-item>

    </ons-list>
</ons-page>
スクリーンショット

f:id:yuk4420:20141026205538p:plain

バイオグラフィページを作る

スライドメニューを作ったので、リンク先となるバイオグラフィページを作ります。

バイオグラフィページに使うパターンを選ぶ

再度、Onsen UI テーマローラーページ を開き、Patternsタブを選択します。
この中からバイオグラフィページに使えそうなパターンがあれば、それがそのままテンプレートとして使えるわけです。

名前からしてまんまですが、Profileパターンが使えそうですね。
早速Show Sourceを選択してソースを表示します。

コードをコピーし編集する

メニューページと同じように biography.html というファイルを作って <ons-template> タグ以下を貼り付けます。

ただし、この方法だと index.html からではなく biography.html に直接アクセスした際、Onsen UI等々が読み込まれないので、index.html は検索エンジンのクロールを許可しないよう設定したり、 <head> タグ周りもきちんと記述したりといった工夫が必要かと思います。

コード例

biography.html(プロフィールページ)
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">

        <link rel="stylesheet" href="styles/profile.css">

    </head>
    <body>

        <ons-page>
            <ons-toolbar>
                <div class="left">
                    <ons-toolbar-button ng-click="ons.slidingMenu.toggle()">
                        <ons-icon icon="ion-navicon" size="28px" fixed-width="false"></ons-icon>
                    </ons-toolbar-button>
                </div>
                <div class="center">Biography</div>
            </ons-toolbar>

            <div class="profile-card">

                <img src="img/yuk.jpg" class="profile-image">
                <div class="profile-name">ユキミネ</div>
                <div class="profile-desc">Vocal, Guitar, Bass, Cajon, Programming</div>

            </div>

            <ons-list modifier="inset" style="margin-top: 10px">
                <ons-list-item>
                    Twitter
                </ons-list-item>

                <ons-list-item>
                    Instagram
                </ons-list-item>
                
            </ons-list>

            <br>


        </ons-page>

    </body>
</html>

スクリーンショット

f:id:yuk4420:20141026205548p:plain

まとめ

といった感じでOnsen UIを使うとスマホスマホしたサイトが簡単に作成できます。
「Onsen UIでこんなことした!」というのがあればまた紹介したいと思います。

P.S.

いわゆるテンプレートサイトって今どんなのになってるんですかね。
サイトを簡単に作れるサービスなんかがあってテンプレート配布サイトとかはもうないとか?