IM共通マスタの期間化を利用してみよう

ご挨拶

みなさま初めまして、マサキと申します。
理系出身のSE・プログラマでありながら、小説を書くのが好きだという変な技術者です。

今年から株式会社グローバル・ソリューション(以下GSOL)に中途入社致しまして、このたび本ブログの投稿を任せていただきました。

今回のテーマ

さて、今回の記事のテーマですが、intra-martが持つIM共通マスタの『期間化』についてご紹介していきます。
intra-martを導入したら、どんなことができるんだろう? とご検討中の方々の一助になれたらと思います。

Tips
intra-martってなんだろう? という方もまだまだ大勢いらっしゃるかと思われますが、気になった方はぜひ検索してみてください。
機会があれば、このブログでもあらためてご紹介するかもしれません。

マスタの期間化

1.IM共通マスタ

intra-martは、そのシステムを円滑に動かすため、『IM共通マスタ』という情報をデータベースに持っています。
マスタとは、ユーザ(社員)情報、会社・組織情報、品目(商品)情報など、システムを稼働させるにあたって欠かせない、基本的な情報のことです。

Tips
マスタについてもっとよく知りたいという方は、マスタデータやトランザクションデータをキーワードとして、調べてみてくださいね。

例えば、intra-martを使って構築した勤怠管理システムであれば、
ひとつの会社の中にいくつもの組織があり、さらにその組織それぞれに大勢の社員が所属している……という情報が、このIM共通マスタに保存されています。

マスタ情報のイメージ図
マスタ情報のイメージ図

ところで、会社ではしばしば組織の統廃合が行われます。となればもちろん、それにあわせてマスタも更新する必要があります。
廃止される組織の情報はどうすればよいでしょうか? 思い切って、データベース上からその組織の情報を物理削除してしまいましょうか?
ですがその場合、後から廃止された組織のことを調べようにも、データはもう存在しませんので、確認が難しくなってしまいます。

そんなときは、IM共通マスタが持つ『期間の分割』と『構成からの除外』という機能を活用しましょう。

2.期間の分割

IM共通マスタ上で、組織情報は期間情報を持っています。つまり、この組織は1970年1月1日から2099年12月31日まで有効ですよ、というような情報を保持しています。
期間の分割とは文字通り、その期間情報を二つに分けます。

組織分割のイメージ図
組織分割のイメージ図

『この組織は1970年1月1日から2018年7月31日で有効であり、さらに2018年8月1日から2099年12月31日まで有効である』というように、期間を分けてしまうのです。
このとき、前者を期間A、後者を期間Bとしましょう。

同じ組織でも、ある日を境に状況が変わったときなどに、この分割は役に立ちます。
この組織が2018年7月31日まで存在し、それ以降は廃止されたとするならば、期間Aをそのままにして、期間Bの情報のみ更新すればいいのです。

組織廃止のイメージ図
組織廃止のイメージ図

これなら廃止後も情報は残っていますので、将来必要になってから情報を取得することも可能です。便利ですね。

3.構成からの除外

組織を廃止する日付で期間を分割したら、廃止される期間の組織情報を修正しなくてはなりません。
通常、不必要な期間は『無効化(論理削除)』してしまえば大丈夫です。
これならば、あとから廃止組織の情報を調べることもできますし、さらに分割した別の期間で廃止組織を復活させることも容易です。組織に所属しているユーザもそのままですので、誰が所属していたかも保持しておけます。

ただし組織に関しては、『構成からの除外(論理削除)』をオススメします。
つまり、組織は有効な状態のままで、階層構造から外してしまうのです。

構成からの除外イメージ図
構成からの除外イメージ図

構成に残したまま無効化すると、組織マスタの操作画面上で組織名が赤字のまま残ってしまいます。

組織を無効化した場合
組織を無効化した場合

ですが構成から除外すれば、画面上からも組織名が消えますので、きれいに整理できますね。

組織を構成から除外した場合
組織を構成から除外した場合

構成から除外した組織は、一般ユーザの目には映らなくなります。
しかしデータとしては有効なままですので、そのまま別の組織の下部組織として配置換えするなどが可能となります。
また、退職した社員データをまとめておくための仮組織として、構成から除外した組織を利用するという手法も考えられます。

4.プログラムからの操作

期間についての操作は、IM共通マスタの各種画面から実行できますが、APIでも同じことができます。
例えば組織であれば、CompanyManagerというAPIを使います。
以下にメソッドを例示します。

メソッド名 役割 利用にあたり必要な情報
getDepartmentTerm 機関の検索 会社・組織検索条件、有効日付
separateTermDepartment 期間の分割 会社・組織検索条件、期間コード、分割日付
moveTermDepartment 期間の変更 会社・組織検索条件、期間情報

これらのメソッドを用いれば、マスタメンテナンス画面上でできるほとんどのことが、Javaプログラムでも実行できます。

Javaプログラムで操作できるということは、例えば休職申請ワークフローの案件終了時に自動で休職期間をマスタ登録したり、IM-FormaDesignerやTERASOLUNAを使って独自に作った画面上で期間の操作を行ったりもできます。
夢が広がりますね!

夢が広がっている図

Tips
APIの詳しい機能については、公式リファレンスをご覧ください。
https://www.intra-mart.jp/apidoc/iap/javadoc/im_master_apidocs/jp/co/intra_mart/foundation/master/company/CompanyManager.html

まとめ

それでは、今回のまとめです。

  • intra-martの持つマスタ情報は期間化できる!
  • 期間を分割して、過去の情報を保持できる!
  • 廃止組織は『構成から除外』しよう!

いかがでしたでしょうか?
今後は、intra-martの紹介や小ネタの共有、最新技術やITニュースにちょっと触れてみたり、弊社GSOLのお話もしていけたらと思います。

私もまだまだ勉強中の身ではございますが、これからもどうぞよろしくお願いいたします。

Final Tips
intra-martは日々進化しておりますので、今後のアップデートで仕様が変わる可能性があります。

今年も内定者の研修にProgateを使ってみた話

開発部の高橋です。
一年近く更新をさぼっていましたが、再開します。

去年に引き続き、今年も新入社員の研修(今回は内定者研修)にProgateを使ったので、 継続して利用したことで気づいたことや、弊社の新入社員への研修内容について共有したいと思います。

ちなみに1年前に導入した時の所感についての記事は以下になります。

gsol.hatenablog.com

Progateとは

prog-8.com

Progateの解説は数多存在するため詳細は割愛しますが、イラスト中心の直感的なスライド資料と実践的な演習問題の添削によって、初学者でも楽しくプログラミングの基本の「き」を学べるサービスです。

今回は内定者研修の教材として、以下のレッスンを3ヶ月かけて受講してもらいました。

Progateによる内定者研修

今年の内定者研修は1月から3月に実施しました。
研修では内定者の時間的都合を尊重して、特に弊社側で厳守すべきスケジュールを設けずに個人のペースでProgateのレッスンを進めてもらいました。
※とはいえ流石に基準となるスケジュールがないと予定通り進めるのも難しいので、毎週5時間程度の受講で上記の全コースが完了できる点と、レッスンを受ける際の適切な順番(フロントエンド→バックエンド→その他の順番)を内定者に伝えています。

去年はあまり効果を実感できず…

ちょっと余談ですが、去年Progateを利用した時は情報系出身のとても優秀な学生が受講者だったこともあり、Progateの効果がいまいち把握できませんでした…
優秀な学生が入社してくれることはとても嬉しいのですが、Progateの全レッスンをすぐに完了させてくれる等、中々に研修担当者泣かせの子でした。

今年は効果を実感できた!

今年は内定者の子にプログラミング未経験の文系の学生がいて、Progateを通じて初学者からエンジニア見習いレベルまで成長していることを確認できたので、良い効果があることを実感できました。
内定者の子には3月からアルバイトとして本社で働いてもらっているのですが、先輩社員と技術的な会話が成立する程度には成長できています。
新卒採用の一次面接の時点で、「プログラミング未経験ですが大丈夫ですか?」といった質問をしていたことを思い出すと、今年もProgate使ってよかったなあとしみじみと感じます。

Progateのどの辺りでスキルを付けることができたかを内定者の子に聞いてみたところ、
コースの後半で難易度が飛躍的に上がる箇所があり、そこを自力で調べて解決することでスキルを付けることができたという感想を聞くことができました。
技術的な問題を如何に調べるかがエンジニアにとって最も重要なスキルなので、そのスキルを初学者の時点から身に着けられるサービスであるという点が、Progateがここまで支持されている理由なのかなと感じました。

仲間募集中!

グローバル・ソリューションズでは、新卒採用で仲間を募集しています。弊社は初学者の方に成長できる環境、様々なことを経験、チャレンジできる環境を提供できます。興味のある方は、以下から説明会にエントリーしてみてください。

job.rikunabi.com

またWantedlyでは、新サービスの開発コアメンバーとして大いに力を発揮してくれる方を募集しています(昨日募集を開始しました)。新卒中途は特に問いませんので、弊社のサービス開発に少しでも興味のある方は以下からエントリーお願いします!

www.wantedly.com

新入社員の研修にProgateを使ってみた話

開発部の高橋です。

4月からの新入社員研修にProgateというサービスを使ってみました。Webサービスを利用した新入社員研修は初めての試みだったので、私個人の所感も交えて紹介しようと思います。

Progateとは

prog-8.com

初学者向けのオンラインプログラミング学習サービスです。以前から新入社員研修で使ってみたいと思っていたので、今年度から試験的に導入してみました。

f:id:gsol-dev:20170501101523p:plain

学習資料のスライドが初学者向けにとてもわかりやすく記載されてます。画像はProgateトップページより引用しています。

f:id:gsol-dev:20170501101529p:plain

学習資料に対応した演習をこなしながら学習を進めていく形式となっています。この画像もProgateトップページからの引用です。

実際に利用してみた感想

以下、私個人の所感です。

初めてのプログラミング向き

学習スライドが読みやすいように図が多め、文章少なめだったり、演習にヒントがついていたりと、とにかくプログラミング初心者に優しいサービスの作りになっている印象です。本を買って勉強する場合と比べて、かなり勉強しやすいと思います。

場合によっては他の研修と併用が必要

言語によっては学習範囲が狭いため、他の教材(本とか)での学習が必要になると思います。例えば自社の場合、クライアントサイドの研修に関してはProgateのHTML&CSSjQueryで新人の研修教材として十分でしたが、サーバー言語のJavaJavaScriptについてはProgateの内容では不十分そうだったので、Progate学習後に本を読んで勉強をしてもらっています。

ちなみに自社の開発にRailsを使っている場合は、HTML&CSS + jQuery + Ruby on Railsで新人研修としては十分な印象です。

まとめ

以上、Progateの紹介と新入社員研修に使用した感想でした。最初にプログラムに触る教材としてはとても良いサービスなので、来年度も新入社員研修に使ってみようと思います。

CentOS Dockerコンテナの日本語ロケール設定方法

開発部の高橋です。

今回はCentOSのDockerコンテナで日本語ロケール設定方法について紹介します。

CentOSでのロケール設定方法

以下Dockerfileのサンプルです。

FROM centos:centos7

RUN rm -f /etc/rpm/macros.image-language-conf && \
    sed -i '/^override_install_langs=/d' /etc/yum.conf && \
    yum -y reinstall glibc-common && \
    yum clean all

ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

CMD bash

補足

これまでは以下の様なDockerfileでもロケールの設定ができていたのですが、Bug 1392855 – build-locale-archive: build-locale-archive.c:301: fill_archive: Assertion `used < head->namehash_used' failed.で報告されている不具合によって、去年末頃からロケールの設定ができなくなっています。

FROM centos:centos7

RUN yum -y update && \
    yum -y reinstall glibc-common && \
    yum clean all

ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

CMD bash
# コンテナ内でlocale -aを実行してもCロケールとPOSIXロケール以外が存在しない。コマンド実行する度にwarningログが出力される。
$ locale -a
/bin/sh: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
C
POSIX

そのため、glibc-commonを再インストールする前にrm -f /etc/rpm/macros.image-language-confsed -i '/^override_install_langs=/d' /etc/yum.confを実行することで不具合を回避しています。

intra-martのエラー発生時にSlackに投稿する方法の紹介

開発部の高橋です。

今回はlogbackの機能を使って、intra-martでエラーが発生した時にSlackにエラー内容を投稿する方法を紹介します。

Slackの設定

SlackのIncoming Webhooks機能を使って、 特定のチャンネルにintra-martのエラー内容を投稿するためのWebhook URLを発行します。 (手順の紹介は省きます)

自社ではエラーが発生すると、:imp:の絵文字で投稿するように設定しています。

f:id:gsol-dev:20170123201536p:plain

Appenderの実装

Appenderによって、エラーログをSlack APIの仕様に基づいたJSON形式に変換し、Webhook URLに対してPOST送信します。 長文のエラーログをSlackに投稿できるように、attachments属性にエラーログを設定しています。

以下Appenderのソースです。

package jp.co.gsol.logback.appender;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.UnsynchronizedAppenderBase;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.arnx.jsonic.JSON;

public class SlackAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

    private static final String PRETEXT = "【社内システム】iAPエラーログ";
    private String url;
    private String channel;
    private Layout<ILoggingEvent> layout;
    private int timeout = 10000;

    @Override
    protected void append(final ILoggingEvent event) {
        try {
            final URL apiUrl = new URL(url);
            final StringWriter w = new StringWriter();
            w.append("payload=").append(URLEncoder.encode(createAttachmentsStr(layout.doLayout(event)), "UTF-8"));
            final byte[] bytes = w.toString().getBytes("UTF-8");

            final HttpURLConnection con = (HttpURLConnection) apiUrl.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setConnectTimeout(timeout);
            con.setReadTimeout(timeout);
            con.setFixedLengthStreamingMode(bytes.length);
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            final OutputStream os = con.getOutputStream();
            os.write(bytes);

            os.flush();
            os.close();
        } catch (IOException e) {
            addError(channel + "投稿時にエラーが発生しました", e);
        }
    }

    /**
     * ログフォーマットをJSON形式に変換
     * @param text
     * @return
     */
    private String createAttachmentsStr(final String text) {
        List<Map<String, Object>> attachments = new ArrayList<>();
        Map<String, Object> attachment = new HashMap<>();
        attachment.put("pretext", PRETEXT);
        attachment.put("text", text);
        attachments.add(attachment);
        Map<String, Object> map = new HashMap<>();
        map.put("attachments", attachments);
        return JSON.encode(map);
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(final String url) {
        this.url = url;
    }

    public String getChannel() {
        return channel;
    }

    public void setChannel(final String channel) {
        this.channel = channel;
    }

    public Layout<ILoggingEvent> getLayout() {
        return layout;
    }

    public void setLayout(final Layout<ILoggingEvent> layout) {
        this.layout = layout;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }
}

im_logger.xmlの設定

im_logger.xmlにSlackAppenderの設定を行います。 intra-martのログ仕様書に基づいて、 ログ出力したい情報を<layout>タグに設定します。<url>タグにはSlackのWebhook URLを設定します。

以下、自社のim_logger.xmlの設定の抜粋です。

    <appender name="SLACK" class="jp.co.gsol.logback.appender.SlackAppender">
        <channel>#in-house-error-log</channel>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}]
thread: [%thread]
level: [%-5level] logger: [%logger{255}]
tenant id: [%X{tenant.id}] log id: [%X{log.id}] request id: [%X{request.id}]
user type: [%X{user.type}] authenticated: [%X{authenticated}] user cd: [%X{user.cd}]
log message code: [%X{log.message.code}]    message: %msg%n
%ex{full}
            </pattern>
        </layout>
        <url>https://hooks.slack.com/services/XXXXXXX/YYYYYYY/ZZZZZZZZZZZZZZZZZZZZZ</url>
    </appender>

    <appender name="ASYNC_SLACK" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="SLACK" />
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <root>
        <level value="info" />
        <appender-ref ref="ASYNC_SLACK" />
    </root>

Slackに投稿される内容

intra-martでエラーが発生すると、Slackに↓の様な投稿が自動で行われます。

f:id:gsol-dev:20170126195917p:plain

投稿を展開するとExceptionの詳細が見れます。

f:id:gsol-dev:20170126195941p:plain

Exceptionが長すぎると、途中で省略されてしまうので、いつか修正したいです。

以上、intra-martのエラー発生時にSlackに投稿する方法の紹介でした。

JavaScriptを使った開発に便利な定番ライブラリ

開発部の佐野です。

JavaScriptの定番ライブラリについて紹介します。

lodash.js

非常に幅広く便利な機能を提供してくれるライブラリです。 主にコレクションやオブジェクトに関しての機能が中心で、かゆいところに手が届くようなユーティリティをたくさん備えています。

Moment.js

日付や時刻に関する機能を提供するライブラリです。 JavaScript標準の機能だと、日付の操作に不便なことが多々あります。 このライブラリは、そんな日付関係の処理を補ってくれるため、非常に便利です。

この2つで、細かな使い勝手がかなり改善されます。 画面構築と操作に関しては、jQueryやAngular.js、最近ではReact.jsなど様々な選択肢がありますが、この2つのライブラリはどの場合でも役に立つと思います。

当然使い方を覚える必要はありますが、それを補って余りあるメリットがあると思うので、ぜひ活用してみてください。

docker-compose runでport mappingされず小一時間悩む

開発部の高橋です。

docker-composeを使っていたらタイトル通りの内容で悩みました。結論としてはドキュメントをよく読んで使おうって話なだけなのですが。。。

経緯

以下の様なdocker-compose.ymlを作って、dockerコンテナ上でNode.jsプロジェクトのインストール、起動すると、コンテナ内で起動しているサーバーにアクセスできずに悩みました。。。

# docker-compose.yml
version: '2'
services:
  graphql:
    image: node:alpine
    volumes:
      - .:/usr/src
    ports:
      - "3000:3000"
    privileged: true
# Node.jsプロジェクトをcheckout
git clone https://github.com/kadirahq/graphql-blog-schema.git
cd graphql-blog-schema
git checkout build-schema

# 作成したdocker-composeでインストール、起動
docker-compose run --rm graphql npm install --prefix=/usr/src
docker-compose run --rm graphql npm start --prefix=/usr/src

# 別ターミナルでコンテナ内のサーバーにアクセスするとConnection refused
curl http://localhost:3000
curl: (7) Failed to connect to localhost port 3000: Connection refused

原因と解決

調べてみると(というかリファレンスに書いてありました)、docker-compose run --service-portsとしないと、docker-compose.ymlファイルのport mappingが無視されるようです。以下引用です。

The second difference is the docker-compose run command does not create any of the ports specified in the service configuration. This prevents the port collisions with already open ports. If you do want the service’s ports created and mapped to the host, specify the --service-ports flag:

docker-compose run --service-portsを指定して無事動きました。

docker-compose run --rm --service-ports graphql npm start --prefix=/usr/src

# curlでコンテナ内のサーバーにアクセスできる
curl http://localhost:3000
<html>
  <head>
    <title>Sample App</title>
    <link rel="stylesheet" type="text/css" href="/static/graphiql.css">
  </head>
  <body>
    <div id='root'>
    </div>
    <script src="/static/bundle.js"></script>
  </body>
</html>

以上、ドキュメントをよく読んで使おうという話でした。

JavaScriptのアロー関数について

開発部の佐野です。

JavaScriptのECMAScript6で追加されたアロー関数を紹介します。

これは、要は関数を定義する構文です。 従来のfunctionと書く定義とは少し挙動が違います。 それに加えて、より短く簡単に関数を定義できるというのもメリットになります。

ただ、このアロー関数は括弧を省略できたりして、意外と覚えにくい機能です。 特にES6の新しい構文に慣れていない人は混乱しがちです。

例えば、以下の書き方は全て同じ結果になります。

name => 'Hello ' + name;
name => { return 'Hello ' + name; };
(name) => 'Hello ' + name;
(name) => { return 'Hello ' + name; };

左右どちらの括弧も省略できるため、結果的に4パターンの書き方があります。 引数が複数の場合や、処理が複数行の場合は省略できません。

アロー関数はES6の構文で書く場合は必須となる構文なので、覚えると将来役に立つでしょう。 また、ES6で書かれたJavaScriptが読めない人の原因は、大抵このアロー関数が理解できない場合が多い気がします。 逆にこれさえ分かれば、敬遠しがちだった最新のJavaScriptソースコードもグッと理解しやすくなると思います。

以上、アロー関数の紹介でした。

JavaScriptのテンプレート文字列について

開発部の佐野です。

今回は、JavaScriptのテンプレート文字列について紹介します。

これはECMAScript6で組み込まれた新しい機能です。 他にも様々な機能が追加されていますが、テンプレート文字列は汎用性が高く、様々な場面で使える機能です。

「`」(バッククォート)で囲うと利用できます。 内部に変数などを埋め込んで表示できるのが特徴です。

例えば、以前は文字列の途中で変数を入れるにはこのように書いていました。

var name = 'GSOL';
console.log('Hello ' + name + ' !!');

これをテンプレート文字列にすると、

var name = 'GSOL';
console.log(`Hello ${name} !!`);

と書けます。

地味ですが、きれいに書けるので開発者的には嬉しい機能です。

以上、簡単ですがテンプレート文字列の紹介でした。

markdownエディタの紹介

開発部の佐野です。

今回は、markdownエディタについて紹介します。

markdownは書きやすくで便利なので、よく使っています。 しかしローカル上のmarkdownファイルを編集するエディタは、意外と定番のものが無い気がします。 なので個人的に使ってみたmarkdownエディタを紹介してみます。

Haroopad

非常にシンプルで使いやすいと思います。 メモ帳にmarkdownのプレビュー画面が追加されたような感じです。 後述するAtomなどは多機能でタブなども使えますが、もっとシンプルに使うならこちらのほうが良いと思います。 すこしフォントが微妙ですが、設定で変えることができます。

Atom

markdown専用のエディタではなく、様々なプログラミング言語の編集に使えるエディタです。 多機能でカスタマイズも柔軟にでき、様々な機能の追加パッケージが公開されています。

Typora

markdownかつWYSIWYGというユニークなエディタです。 markdownの記法を書くと、自動的に表示が更新されていきます。 普段直接markdownを書くとテーブルなどが少し書きづらいのですが、Typoraはテーブルを作ると専用の操作メニューが表示されて、非常に簡単に編集ができるようになっています。 いきなり表示が更新されることなどから、若干操作しにくい感じはありますが、おもしろいエディタだと思います。

markdownエディタの紹介は以上です。

markdownはシンプルで覚えやすく、日常のメモ書きから開発資料まで幅広く役立ちます。 このブログも含めてmarkdownで書けるサービスも数多くありますので、試してみてはいかがでしょうか。

自社githubアカウントの紹介

開発部の高橋です。

自社githubアカウントについて簡単に紹介しようと思います。

自社githubアカウント

github.com

github上で公開しているリポジトリ

自社intra-martソリューション関係

IMBoxデスクトップ通知、iACスケジュール連携ソリューションのユーティリティやプラグインgithub上に公開しています。

PeerJS

PeerJSからForkして一部修正を加えてます。 Web会議ソリューションのSignalingサーバー使用しています。

Dockerfile

社内の開発等に使用しているDockerfileを公開しています。 Docker Hubでimageも公開してます。自社Docker Hubのページ

以上、自社github(とDocker Hub)アカウントの簡単な紹介でした。

react.jsの入門書を購入しました

開発部の高橋です。

以前から探していたReactの入門書が先日発売したので、 会社の経費で1冊購入しました。 (お願いしたら二つ返事で購入してくれる会社に感謝です)

WebデベロッパーのためのReact開発入門 JavaScript UIライブラリの基本と活用

WebデベロッパーのためのReact開発入門 JavaScript UIライブラリの基本と活用

Reactって何?って開発メンバーもまだいるような状況なので、 この本でReactの基本を固めてサービス開発を進めていきたいと思います。

現在WantedlyでReactを使ってサービスの開発したい方を募集してますので、 興味がある方はぜひ応募してみてください。 上で書いたように社内は現在React勉強中なので、 Reactに興味があって少し触ったことのあるレベルの方でも大歓迎です。

www.wantedly.com

HTML5の新機能紹介 ~WebStorage~

開発部の真崎です。

今回は、HTML5で導入された新機能の1つ、WebStorageについての紹介です。

WebStorageとは

WebStorageとは、HTML5で導入されたブラウザでデータの永続化を行う仕組みのことです。 特徴としては、 * 比較的大容量の文字列データを保存できる * Key-Value型のシンプルなインターフェイス * 保存/取得処理に通信を伴わない などがあります。 今までは、毎回サーバにアクセスし、保存/取得処理されていたブラウザ固有のデータをブラウザ内で完結させることができます。 また、最近使われている大多数のブラウザで使用できる(ChromeFireFoxSafariOpera、IE8~)ので、安心して使えます。

Cookieとの違い

WebStorageと似た技術で、今まではCookieがありました。違いについて、簡単にまとめてみました。 (localStorageとsessionStorageの違いは、後で説明しています)

WebStorage Cookie
Origin毎の保存容量 5MB (仕様上) 4KB
有効期限 なし (localStorage) あり
通信 jsで実装する必要がある 勝手に送信される
個数制限 なし 20個 (仕様上)
pathの設定 Originで共通 できる
標準API 比較的簡単 煩雑な文字列操作
ウィンドウ間でのデータの共有 できる (localStorage) できる
スコープ Origin単位 host/path単位

有効期限を設定したい場合や常にデータを送信したい場合、特定のpath以下のみのアクセスを許可したい場合など、 Cookieでしかできないこともありますが、データ保存に関しては、WebStorageに利点が多いです。

WebStorageの種類

WebStorageには、用途に応じて2種類のストレージが用意されています。違いについて、簡単にまとめてみました。

locakStorage sessionStorage
有効期限 なし(削除されるまで) ウィンドウ(タブ)を閉じるまで
ウィンドウ(タブ)間での
データの共有
できる できない

基本的な機能については、共通です。1点だけ異なっており、
localStorageは、Origin(scheme://hostname:port/)にスコープしており、
sessionStorageは、更にTop-level browsing context(ウィンドウ、タブなど)にスコープした Storageである点が差異です。(※sessionStorageは、Webアプリなどのログインセッションとは同期してないです)

用途としては、localStorageはデータの永続化、sessionStorageは一時データの保存になると思います。

WebStorageの使い方

コードを示しながら、説明します。 (localStorageもsessionStorageも同じインターフェイスを備えてます。ここでは、sessionStorageをサンプルとします。)

// sessionStorageが使えるかどうか
if (typeof sessionStorage === 'undefined')
    alert('sessionStorage is not found');

// 文字列データの操作は、hashを操作するように行えます。
sessionStorage['key'] = 'value';
console.log(sessionStorage['key']); // => 'value'
// 次の書き方もできます
//sessionStorage.setItem('key', 'value');
//console.log(sessionStorage.getItem('key'));
//sessionStorage.key = 'value';
//console.log(sessionStorage.key);

// Objectの保存には、JSON.stringifyなどで、シリアライズする必要があります。
sessionStorage['objKey'] = JSON.stringify({key: [1, 2, 3]});
// 取得時には、デシリアライズしてください。
console.log(JSON.parse(sessionStorage['objKey'])); // => {key: [1, 2, 3]}

// データを消したいとき、次のようにできます。
//sessionStorage.clear(); // 全件削除(Originに紐づく全件が削除されるので注意)
sessionStorage.removeItem('key'); // 'key'で登録されているデータが削除されます
// OriginでStorageが共有されているので、次のようにnamespaceを分けると削除しやすいです。
sessionStorage['prefix.key'] = 'value'; // 一意なprefixを付加
Object.keys(sessionStorage)  // -> ['objKey', 'prefix.key']
      .filter(function(k) { // prefixが一致するデータをfilter
          return k.split('.')[0] === 'prefix';
      }).each(function(k) { // filterされたデータを削除
          sessionStorage.removeItem(k);
      });

// その他のStorage interface
// n番目のkeyを戻します
sessionStorage.key(0); // -> 'objKey'
// Storageに保存されている件数(正確には、Storage自体のinterfaceではないですが)
sessionStorage.length; // -> 1
// 登録されているkeyの一覧
Object.keys(sessionStorage); // -> ['objKey']

// 他のタブからStorageの変更があった場合、eventが発火します
// (sessionStorageは仕様上、発火しないので、localStorageをサンプルにします)
localStorage['key'] = 'old';
// listenerを設定
window.addEventListener('storage', function(e) {
    console.log(e);
});
// 他のタブから
// localStorage['key'] = 'new';
// 登録、更新、削除など、Storageに変更があれば、eventが発火します
// => key: 'key', newValue: 'new', oldValue: 'old', ...

※Storageのデータは、Originで共有されるので、複数の機能で使用する場合、削除や上書きに気をつけてください。

使い分け

Cookie、localStorage、sessionStorageの違いを簡単に説明してきました。ここでは、それぞれの用途について考察してみたいと思います。

Cookie

容量が少なく、常にサーバとデータを共有しているCookieはログインセッションの管理が主な用途になると思います。

localStorage

ブラウザ毎にデータを永続的に保存できるので、設定の保存目的や、大容量なのを活かし、下書き保存などに使えると思います。 また、Storage変更時に、eventが発火するので、タブ間の同期などにも使えます。

sessionStorage

タブ毎にスコープが分かれているので、タブで行った作業結果の一時保存や、タブを閉じたあと必要がない閲覧情報などの保存に使えると思います。

まとめ

HTML5で導入されたWebStorageについて、Cookieとの比較を行い説明しました。 また、使い方について、サンプルコードを元に説明を行いました。 サーバに送らなくてもいいデータなどの保存に使用すると、画面遷移の高速化が期待できます。 サーバとの無駄な通信量が多い時などいかがでしょうか?

複数のバージョンのjQueryを読んでしまったときの共存のさせ方

新人の真崎です。今週もよろしくお願いします。

今回は、複数のバージョンのjQueryを読まないといけないときの対処方法について書きたいと思います。1.7系でしか動かないコードがあるけど、1.10系も使ってみたい場合やajaxで取得したページにjQueryを再取得してしまってる場合などにお試しください(※推奨できる方法ではないので、実装を見直すべきですが)

2個目のjQueryを読む前に処理したい場合

古いjQueryを別の変数に退避させて、新しいjQueryを読む方法です。

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$old = jQuery;
</script>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
console.log($old().jquery); // => 1.7.2
console.log($().jquery); // => 1.10.2
console.log(jQuery().jquery); // => 1.10.2
</script>

2個目のjQueryを読んだあとに処理したい場合

新しいjQueryを読んだあとに、noConflict([removeAll])で古いjQueryを復活させる方法です。removeAllのオプションにtrueを渡すと$オブジェクトだけではなく、jQueryのオブジェクトも元に戻されます。

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
$new = jQuery.noConflict(true);
console.log($().jquery); // => 1.7.2
console.log(jQuery().jquery);
// removeAll is true => 1.7.2
// removeAll is false => 1.10.2
console.log($new().jquery); // => 1.10.2
</script>

まとめ

複数のバージョンのjQueryを読まないといけないときの対処方法について紹介しました。どうしても複数のバージョンのjQuery共存させないといけないときなどにご活用ください。

javascriptで日付を扱うときに便利なmoment.jsの紹介

新人の真崎です。 このアドベントカレンダーもなんとか1周間続けることができました。残り3週間がんばっていきたいと思います。

今回は、javascriptで日時を扱うときに便利なライブラリの紹介を行いたいと思います。 javascriptにもDateオブジェクトはあるのですが、使いづらく簡単な処理であればStringで代用してしまったりします。そこで、試してみたいのが、今回紹介するmoment.jsです。

momentオブジェクト生成

日時情報を保持するオブジェクトです。任意のフォーマットパターンで日時文字列をparseすることができます。

moment();
// => 現在日時のオブジェクト

moment("2013/12/8", "YYYY/M/D");
moment("Dec 8, 2013", "MMM D, YYYY");
moment("8 12 2013", "D M YYYY");
// => 2013年12月8日のオブジェクト

フォーマット出力

任意のフォーマットパターンでStringを出力できます。

moment().format("MMM D YYYY ddd, hh:mm:ss a Z");
// => "Dec 8 2013 Sun, 09:05:04 pm +09:00"

日本語化

langs付きのmomentなら、lang("ja")で日本語に出力してくれます。また、langの設定を別に行うこともできます。

moment.lang("ja", {
    weekdaysShort: ["日","月","火","水","木","金","土"]
});
moment.format("ddd");
// => 日

まとめ

javascriptで日時を扱うときに便利なライブラリであるmoment.jsの簡単な紹介を行いました。 moment.jsには、他にも日付のマニピュレーションの機能が豊富にあったりするので、日付関係で困ったときは試してみてはいかがでしょう。