Chatwork Creator's Note

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

ビジネスチャット「Chatwork」のエンジニアとデザイナーのブログです。

読者になる

ドメインモデルの根拠とドメインモデル貧血症の対策について

ChatWork Advent Calendar 2017の10日目の記事です。

こんにちは。かとじゅん([Twitter:@j5ik2o]) です。

何を書こうかと悩んだのですが、社内で意見を聞いたところ、やはりDDD関連がよいとなりました。

この記事も、もう四年前ですっかり古くなりました。最近どういう観点で実践しているかまとめてみます。(DDD初級者という方は、まず上の記事を読むことをお勧めします)

DDDを実践するにあたっての個人的な問題点は2つあります。ひとつは、「いきなりドメインモデルを作ることができない」という問題。もうひとつは、ドメインモデルを作り上げても実装コードに役に立つ振る舞いが思いつかず、いわゆる「ドメインモデル貧血症*1」になりやすいという問題です。このような問題は、僕がコミュニティで関わった多くのエンジニアから耳にします。今日の記事はこの二点について考えてみましょう。相変わらず、長編なので時間があるときにお読みください(笑)

*1:詳しくはこちら参照 → http://bliki-ja.github.io/AnemicDomainModel/

続きを読む

東京オフィス自慢の「椅子」紹介

f:id:cw-hayama:20171208144526j:plain デザイン部のハヤマです。ChatWork Advent Calendar 2017の9日目の記事です。

11月に新しくなった東京オフィスは、「働き方をアップデートできるオフィス」をコンセプトに細部までこだわって作られています。中でも共有スペースに配置しているデザイナーズ家具の椅子は家具屋さん顔負けのラインナップです!

今回は、そんな自慢の「椅子」をご紹介します。

続きを読む

REST APIを実行して学ぶRust

こんにちは。火村です。 ChatWork Advent Calendar 2017の7日目の記事です。

さまざまなプログラミング言語を学ぶと、違う部分や同じ部分が見えてきて、プログラミングの本質が見えてきて楽しいです。 ところで、新しいプログラミング言語に挑戦するときは、皆さんどうしていますか? 定番は「Hello, World」の出力ですが、次のステップは他の言語でやったことあること簡単なことに挑戦してみることが多いのではないでしょうか。

というわけで、Rustを使ってチャットワークAPIを実行してみました。 そこからRustの様々な要素を掴んでもらいたいなというのが今回の内容です。

  • はじめに
  • 解説
  • 補足
    • エラーハンドリング
    • 文字列
    • 非同期リクエスト
  • まとめ
続きを読む

ChatWorkの過去アドベントカレンダーまとめ

こんにちは。10月に入社したあらいです。よろしくお願いします。

この記事はChatWork Advent Calendar 2017の6日目です。

さて、予告なく始まったChatWorkアドベントカレンダー2017ですが、実は2年ぶりのカレンダーです! お楽しみ頂けているでしょうか? この記事では過去のアドベントカレンダーと人気記事を振り返っていきたいと思います。

2013年

adventar.org

記念すべき最初のアドベントカレンダーは2013年でした。 CTO山本による黒い画面不要のサイトジェネレータPhestの紹介や、 当時公開されたばかりのChatWork API の活用記事が話題になりました!

2014年

adventar.org

翌2014年のカレンダーです。 2014年は4月にPHPからScalaへの移行を発表、 また7月にはロゴのリニューアルを行い、 フロント・バックエンドともにプロダクトの改善に向けた努力をする中で得た知見を共有しました。

2015年〜2016年

さて2015年〜2016年ですがカレンダーがありません。 おかしいですね。何かあったんでしょうか(お察し下さい)。 ヒントはこちらの記事の中に隠されています。

creators-note.chatwork.com

2017年

adventar.org

そして今年2017年のカレンダーです。 最近の技術への取り組みのほか、オフィス移転の裏話などを予定しています。 どうぞお楽しみに!

PHPでJSを書く話

ChatWork Advent Calendar 2017の5日目の記事です。

こんにちは。インフラマネジメント部の @cw-ozakii です。

先日のphpcon 2017にてbabel-preset-phpのLTをさせていただきました。

このときはLTの枠内に収めるためにbabel-preset-phpで何ができるのかをデモを中心に進めました。が、LTの内容から落とした技術的な話の中にはbabel-preset-phpをいかに導入するかという知見が詰まっていたので、今回はそのあたりの話をご紹介したいと思います。

babel-preset-phpの使い方

$ npm install --save-dev babel-cli babel-preset-php
$ $(npm bin)/babel source.php -o output.js --presets=php

基本的には上記のようにNodeプロジェクトでbabel-cliとbabel-preset-phpをインストールし、babelを実行するだけでPHPのコードをNodeのコードに変換することができます。もし、複数のファイルを変換する場合は

$ $(npm bin)/babel src --out-dir dist --presets=php

というようにすれば複数のファイルをNodeのコードに変換をすることはできます。しかし、ここでrequireの問題が出てきます。

requireの問題

LTでも少し話しましたがbabel-preset-phpはPSR-4のautoloaderに対応していません。そこで別のファイルを読み出すにはPHPのrequireやincludeを使う必要が出てきます。

Foo.php

<?
class Foo {
}

index.php

<?
require(__DIR__ . '/Foo.php');

$foo = new Foo();

autoloaderに対応する前の懐かしいPHPの書き方ですね。しかし、このコードをNodeに変換しようとするといくつか注意点が出てきます。

1. PHPのrequire ≠ Nodeのrequire

一つ目はPHPのrequireとNodeのrequireで微妙に挙動が違うということです。

相対パスを書いたときPHPのrequireはPHPのマニュアルにある通りカレントディレクトリからの相対パスになります。しかし、Nodeのrequireはそのファイルからの相対パスとなり、基準となるところが違うためPHPとNodeで両方に対応した相対パスを書くことはできません。 そのため、もしrequireでパスを指定する場合はDIRを使って絶対パスになるように指定する必要があります。

余談ですが、

<?
require(dirname(__FILE__)  . '/Foo.php');

のようにdirname(FILE)の場合はdirnameがbabel-preset-phpが対応していないためエラーになります。

2. クラス定義の読み込み

二つ目はクラス定義の読み込みの仕方がPHPとNodeで違うということです。

PHPの場合はクラスを定義した.phpファイルをrequireすれば、そのクラスを利用できるようになります。 対してNodeはというと

foo.js

class Foo {
}

module.exports = Foo;

上記のようにクラスをexportして

index.js

var Foo = require(__dirname + '/foo');

のようにexportされたクラスを受け取る必要があります。

これを解決するためにはPHPかNodeのどちらかに寄せる必要があります。

PHPに寄せる場合は

Foo.php

<?
class Foo {
}

if (global) { // on Node
    global.Foo = Foo;
}

というようにNodeのグローバル空間にクラス定義を書き込むことで、requireするだけでクラスを利用できるようになります。

逆にNodeに寄せる場合は

Foo.php

<?
class Foo {
}

return Foo;

index.php

<?
$Foo = require(__DIR__ . '/Foo.php');

$foo = new $Foo();

というようにrequireの結果を受け取り、それをクラスとして利用します。

これはどちらが良い、悪いということはありません。PHPのように書きたければ一つ目の方法を、Nodeのように書きたければ二つ目の方法をということで導入するプロジェクトのスタイルに合わせて決定すれば良いかなと思います。

3. requireの拡張子が.phpのままになる

三つ目はbabelで変換したファイルは.jsに書き換えられるのですが、requireで指定したファイル名は.phpのままになってしまうということです。

index.js

<?
require(__dirname . '/Foo.php');

var foo = new Foo();

ここでgruntやgulpなどのタスクランナーを用いて、ビルドフローで文字列置換を行うのも一つの手ではあります。が、それはあまりイケてる手法ではないので、ここはWebpackを利用して依存を解決し一つのファイルにまとめてしまおうと思います。

$ npm install --save-dev webpack babel-loader

webpack.config.js

module.exports = {
  context: __dirname + '/src',
  entry: __dirname + '/src/index.php',
  output: {
    path: __dirname + '/public',
    filename: 'index.js'
  },
  module: {
    loaders: [
      {
        test: /\.php$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['php']
          }
        }
      }
    ]
  }
};

ここまで準備ができたら、あとはWebpackを実行すると複数のPHPファイルを一まとめのJSにまとめることができます。

$ $(npm bin)/webpack

余談ですが、同様のことをできるツールとしてBrowserifyではエラーになってしまいまとめることはできませんでした。 特に深くは追っていないのでもしかしたらBrowserifyでも可能かもしれませんので、どなたか自信がある方はチャレンジしてみてください。

まとめ

いかがでしたでしょうか。このrequireの問題さえ解決してしまえば、あとは既存のNodeの開発フローに乗せて、ElectronでもReact Nativeでも好きなように開発を進め始めることはできるのかなと思います。おそらくその過程でまだ見ぬ地雷を踏みぬくことができるので、そのときはぜひともどんなものを踏み抜いたのかお教えください。

自分はもう十分踏み抜いたと満足したのであとは任せます。

ChatWork Advent Calendar 2017、明日は @cw-arai です。