« 2016年2月 | メイン | 2016年4月 »

2016年3月

2016年3月11日 (金)

Mac on Macの環境構築をしてみました。

ご無沙汰しております、おっぴーです。

本日は、VirturalBoxを利用したMac On Macの環境作成方法について書いてみたいと思います。 弊社では大半の開発者はMacBook Proを利用していますので、OS Xの環境がほしい!ということはほとんどありません。

が、ハンズオンの資料を準備するために、「綺麗な状態のOS XにNode.jsの開発環境を作りたい」という要望がでてきたためVirtrualBoxを利用した環境構築をしてみました。 構築に利用した環境は、

  • Virtual Box 5.0.16 r105871
  • OS X El Capitan 10.11.3

です。

ということで、下記では

  • そもそもVitrualBoxでOS Xを起動してライセンス的に問題ないのか
  • VirtualBoxを動かすためのisoファイルの作り方
  • VirtualBoxの設定と起動方法

についてご紹介します。

そもそもVitrualBoxでOS Xを起動してライセンス的に問題ないのか

ソフトウェア開発においては、App Storeからダウンロードしたインストーラーを利用して、Mac上で2つまで環境構築をして良い、となっています。 下記が日本語の引用文です。よかった、よかった。

お客様が所有または管理する各Macコンピュータの仮想オペレーティングシステム環境内で、Appleソフトウェアの最大2つの追加コピーまたはインスタンスをインストールし、使用し、稼働させることができます。 これらは、(a)ソフトウェア開発、(b)ソフトウェア開発中の試験、(c)OS X Serverの使用、または(d)個人的、非営利的使用を目的として行うことができます。

Apple_regal


VirtualBoxを動かすためのisoファイルの作り方

これらの情報はいろいろあるのですが、下記が一番詳しい手順でした。

http://anadoxin.org/blog/creating-a-bootable-el-capitan-iso-image.html

まずは、AppStoreからEl Capitanのインストーラーをダウンロードします。 ダウンロードされたファイルは、/Application の配下に「Install OS X El Capitan.app」という名前で作成されます。 ちなみにファイルの大きさが6Gもあるので、ダウンロードが終わるまで気長に待ちましょう。

Create_iso1


つぎに、isoファイルを作成する作業に入ります。 各コマンドの詳しい内容は上記のURLを見て下さい。ここではざっとコマンドをご紹介します。

## App Storeからダウンロードしたインストーラーをマウント(/Volumes/esdが作成される)
hdiutil attach "/Applications/Install OS X El Capitan.app/Contents/SharedSupport/InstallESD.dmg" -noverify -nobrowse -mountpoint 

## isoファイルにするための仮ファイルを作成してマウント(ElCapitan3.cdr.dmgが作成される)
hdiutil create -o ElCapitan3.cdr -size 7316m -layout SPUD -fs HFS+J
hdiutil attach ElCapitan3.cdr.dmg -noverify -nobrowse -mountpoint /Volumes/iso

## インストーラーの情報をiso用の仮ファイルにリストア
asr restore -source /Volumes/esd/BaseSystem.dmg -target /Volumes/iso -noprompt -noverify -erase

## asrを実行して作成された/Volumes/OS X Base Systemの既存の内容を削除
rm /Volumes/OS\ X\ Base\ System/System/Installation/Packages

## マウントしたインストーラーの内容をasrコマンドで作成したディレクトリにコピー(すると、ElCapitan3.cdr.dmg にコピーされる)
cp -rp /Volumes/esd/Packages /Volumes/OS\ X\ Base\ System/System/Installation
cp -rp /Volumes/esd/BaseSystem.chunklist /Volumes/OS\ X\ Base\ System/
cp -rp /Volumes/esd/BaseSystem.dmg /Volumes/OS\ X\ Base\ System/

## マウントを解除
hdiutil detach /Volumes/esd
hdiutil detach /Volumes/OS\ X\ Base\ System

## 作成したファイルをiso用にUDTOフォーマットに変更(ElCapitan3.iso.cdrが作成される)
hdiutil convert ElCapitan3.cdr.dmg -format UDTO -o ElCapitan3.iso

##  作成したファイルをisoファイルにリネーム
mv ElCapitan3.iso.cdr ElCapitan.iso

以上で、VirtualBoxでインストールに利用するisoファイルの作成は完了です。

VirtualBoxの設定と起動方法

個人的なハマりどころは、VirtualBoxの設定です。

まずは、チップセットの設定を、PIIX3に変更することです。

http://apple.stackexchange.com/questions/198737/install-el-capitan-in-virtual-box-for-testing-purposes

設定を変えておかないと、VirtualBoxを起動しても、インストールが始まりませんでした。 設定方法は、画像を参考にしてください。

Setvb1


作成したisoファイルを設定した後、起動したらあとは通常のインストール方法と同様です。

Setvb2


ただし、AppleIDの認証がとおることは確認していません。 AppleIDが連携できるかは、適宜、確認してみてください。

また、VirtualBox上のOS Xからインターネットの接続ができない、という事象にも遭遇しました。 原因はしらべていませんが、その際は、システム環境設定→ネットワーク→アシスタント→診断を選択し、ネットワーク診断をすると正常にインターネットに接続できるようになりました。

以上で、VirtualBox上でOS X El Capitanを動作させられます。 需要があるのか謎ですね。

続きを読む "Mac on Macの環境構築をしてみました。" »

2016年3月 4日 (金)

JavaScriptの書き方をいろいろと試してみた

こんにちは、三宅です。
1月からのプロジェクトで開発しているアプリケーションでは、サーバサイドもクライアントサイドもJavaScriptを採用。
その中でソフトウェアアーキテクチャやコーディングスタイルなど、いろいろなことを試してみました。

アプリケーションの特徴

コンテンツ管理がメインユースケースのアプリケーションです。
現時点ではそれほど複雑な構造にはなっていませんが、タグ付けやユーザやロールに応じたアクセス権限を実装することが将来的にあるかもしれない、というようなものです。

開発の方針

開発に際して、以下の方針を立てました。

  • ドメイン層を明確に分離する
    • アプリケーションで扱う概念をモデルとして表現する
    • ドメイン層は特定のフレームワークやインフラに依存しない
  • クラスベースで記述する
    • ドメインモデルをクラスとして宣言的に定義したい
    • ECMAScript2015(ES6)でクラス定義や継承などが直感的に記述できるようになったため
  • サーバサイドとクラインとサイドは同じモデルを利用する
    • バリデーションなどはモデルに持たせ、それらのコードが分散することを防ぐ

また、一般的なことではありますが、できるだけコードの重複を防ぐ、外部の状態に依存するコードを書かない、ということを意識しました。

フレームワークやミドルウェア

MongoDB、Express、AngularJS、Node.jsといういわゆるMEANスタックを採用しました。

ORMとしてMongoose、テンプレートエンジンにはjadeを利用しています。
コードは基本的にES6で記述し、サーバサイドはBabelを用いてファイルごとにES5に変換、クライアントサイドはBrowserifyを利用し、画面ごとにファイルを生成するようにしました。

ビルドタスクやディレクトリ構成などは、Nodeyardをほぼそのまま利用しています。

試したこといろいろ

少しいろいろなレベル感の話が出てきてしまうかもしれませんが、開発の上で試してみて良さそうだったことを書いていきます。

constでの変数宣言

ES6では「let」と「const」という新しい変数宣言の方法が追加されました。参考

letとconstはブロックスコープです。そしてletは再代入が可能、constは再代入が不可能な変数となります。
可能な限りconstを用いることで、意図しない値の再代入を防ぐことができます。
また、varではなくletを用いることで、JavaScript特有のfor文の中などで宣言した変数の意図しない挙動を防ぐことができます。ただ、繰り返し処理は基本的にイテレータを使っているので、そこまでスコープを意識する機会はありませんが。

アローファンクションの利用

アローファンクションという記述で関数を宣言できるようになりました。

const sample = (a) => {
  return a + 1;
};

この記述は単なる「function」のショートハンドではなく、「this」のスコープがレキシカルスコープになるという大きな違いがあります。
JavaScriptのfunction内のthisはダイナミックスコープで、呼び出し元によって参照先が変わるという大きな特徴がありました。
アローファンクションを用いることで、例えばクラス内で定義した関数内のthisは常にクラスインスタンスになるため、挙動を予測しやすいコードになります。

オブジェクトリテラルの拡張

オブジェクトをリテラルで作成する際の構文が拡張されました。参考
その中でも、変数を設定する際のショートハンドを多用しました。

const name = req.body.name;
const password = req.body.password;

const params = { name, password };

上記のparamsは、以下のオブジェクトの宣言と同じです。

const params = {
  name: name, password: password
};

変数名を何回も書く必要がなく、タイポの可能性を低減することができます。

定義したモデルの拡張

モデルをクラスとして定義するのですが、画面表示名の取得メソッドなど、ビジネスロジック以外のメソッドが欲しくなることがあります。

そのようなメソッドはコアとなるクラス定義とは別に行うようにしました。
SwiftのExtensionsのようなイメージです。

/core/entities/a.js

class A {}

/extensions/entities/a.js

import A from '../core/entities/a.js';

A.prototype.getDisplayName = () => {
  return `A: ${this.name}`;
};

やっていることは、従来のJavaScriptでもあったプロトタイプ拡張です。
上記のように整理することで、コアのコードに特定の環境のみでしか利用しないメソッドを含めないようにすることができると考えています。

サーバサイドとクライアントサイドでのオブジェクトの共有

共有するモデルに対してシリアライザとデシリアライザを追加し、サーバでのレンダリング時に設定した初期値をブラウザの上で復元できるようにしました。

テンプレートをレンダリングする際に、以下のように初期値を渡すようにしました。

const initial = { user: user.seriallize() };
res.render('template', { initial });

script.
  window.__INITIAL__ = JSON.parse(unescape("!{escape(JSON.stringify(initial))}"));

window.INITIAL に初期値を代入する際に、XSSを防ぐためにエスケープしてレンダリングするようにしています。
今回はAngularJSを利用しましたが、Reactのサーバサイドレンダリングでも同様に初期値を渡すことができると思います。
渡された初期値をでシリアライズして利用します。

const user = User.deserialize(window.__INITIAL__.user);

今回はモデルごとに定義しましたが、シリアライザは少し工夫すれば汎用的な関数を作れそうな気がします。

MongooseのModelの継承

Mongooseには、discriminatorというModelの継承を行うための機能があります。
The model.discriminator() function
この機能を用いて、Userというモデルに対してManagementUser、SubscriptionUserのようなユーザの種類に応じたサブタイプを定義しました。
実際に保存されるデータにはサブタイプを識別するための項目が追加されるだけなのですが、サブタイプを宣言的に定義することができること、サブタイプを指定したクエリを実行できる点で採用しました。

インスタンスが特定のクラスのオブジェクトであるかの判定

あるクラスのオブジェクトをインスタンスを返却するメソッドがあり、そのインスタンスがどのサブクラスのオブジェクトであるかによって、処理を分けたいというような場面。
ES6のクラス定義は実際には継承とプロトタイプチェーンのシンタックスシュガーであるため、instanceofが使えます。
プロジェクトでは、インスタンスを判定するための関数を定義して利用しました。

const instanceOf = function(instance, ComparisonClass) {
  if (!(instance instanceof ComparisonClass)) {
    return false;
  } else {
    return true;
}

}

Errorクラスの継承

例えばApplicationErrorのような独自のエラーを定義して、そのエラーの時だけ処理を変えたい、というような場面。
クラス継承ができるのなら…と以下のように書いていたのですが、instanceofでErrorのインスタンスとしか判断することができませんでした。

class ApplicationError extends Error {
  constructor(message = 'ApplicationError', params = {}) {
    super(message);

    Object.keys(params).forEach((key) => {
      this[key] = params[key];
    });
  }
}

正確には、nodeコマンドで直接実行した場合はinstanceofでApplicationErrorと判定できるのですが、Babelで変換されたコードでは「error instanceof ApplicationError」でfalseが返されました。
暫定処理として、typeプロパティを生やしてそれで判断するようにしましたが、この部分は少し調べて見る予定です。


ざっと試してみたことを書きましたが、やはりJavaScriptではイミュータブルで型に基づくプログラミングには限界がある…という印象です。
継承によるサブクラスの利用はある程度使えるのですが、多重継承ができないこと、インタフェースの定義ができないことが、大きな足かせになります。
そのようなプログラミングスタイルを取るのであれば、TypeScriptを採用した方がいいということを実感しました。

また、クライアントサイドとサーバサイドでのオブジェクトの共有で、シリアライズする際にコンストラクタなどの情報を持っていないと、デシリアライズする際にサブクラスまで復元できないという問題もありました。今回はその部分は妥協して、基底クラスのオブジェクトとして復元して利用するような形をとりました。

サーバサイドだけであれば、TypeScriptで型に基づくたプログラミングができるのですが、クライアントサイドでもコードを共有するようなパターンだと、パラメータのみのインタフェースを定義し、それに準拠したオブジェクトを処理する関数を用意する、という方式の方が楽かもしれません。今後もそのあたりはいろいろと試してみたいと考えています。

採用情報

株式会社フレクトでは、事業拡大のため、
Salesforce/Force.comのアプリケーション
開発
HerokuやAWSなどのクラウドプラッ
トフォーム上でのWebアプリケーション開発

エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみた
い方、是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、
セールスフォースパートナーです。
heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。
Powered by Six Apart