こんにちは。エンジニアの田渕です。 5月も中旬を過ぎたのに、東京はまだなんだか微妙に肌寒い日々。。。毎年こんなもんだったっけ?と思いながら、過ごしています。
さて、すっかり定着してきたユニファのエンジニアブログですが、本日はユニファらしい(?)記事を一つ書いてみようかと思います。
続きを読むこんにちは。エンジニアの田渕です。 5月も中旬を過ぎたのに、東京はまだなんだか微妙に肌寒い日々。。。毎年こんなもんだったっけ?と思いながら、過ごしています。
さて、すっかり定着してきたユニファのエンジニアブログですが、本日はユニファらしい(?)記事を一つ書いてみようかと思います。
続きを読むこんにちは。田中剛です。
今回は先日リリースされたReact VR を Cordovaで スマホアプリ化 する話を書いてみます。
え? ユニファでVR ? (||゚Д゚)
と思った方もいらっしゃるかもしれません。
はい、VRは私の趣味100%で業務には1%も関係ありません。。
が、Cordova や ReactNative などのハイブリッドアプリのフレームワークは何かのプロジェクトで使いたいと密かに思っています。 ( ̄ー ̄)
今回の記事を書くにあたって以下の記事がとても参考になりました。m(__)m qiita.com
では、やり方を順に説明していきます。
cordovaのインストール
$ npm install -g cordova
React VRのインストール
$ npm install -g react-vr-cli
cordovaプロジェクトの作成
$ cordova create path/to/your/dir com.example.hello.reactvr HelloCordovaReactVr
createのパラメータは corodva create ディレクトリ 識別子 アプリ名
です。
識別子でハイフンやアンダースコアを使うとハマるので要注意です。(AppIDとしてiOSではアンダースコア、Androidではハイフンを使えないため)
iOSやAndroidのプラットフォームを追加
$ cordova platform add ios --save
$ cordova platform add android --save
React VRのプロジェクトを作成
corodvaプロジェクトのルートディレクトリでReact VRのプロジェクトを作成します。
$ react-vr init react_vr
initのパラメータは react-vr init アプリ名
です。
React VRアプリのコード(js)の修正
index.vr.js
をエディタで編集します
せっかくなので extract-streetviewというツールを使って弊社オフィス地点のストリートビューのパノラマ画像をダウンロードして使ってみます。
<View>
<Pano source={asset('unifa_office_sv_pano.jpg')}
style={{
transform: [
{rotateY : -90}
] }}
/>
<Text
style={{
backgroundColor: '#77ff79',
fontSize: 0.5,
layoutOrigin: [0.5, 0.5],
paddingLeft: 0.2,
paddingRight: 0.2,
textAlign: 'center',
textAlignVertical: 'center',
transform: [{translate: [0, 0, -3]}],
}}>
Welcome to Unifa
</Text>
</View>
ちなみに extract-streetview は次のような感じで使えます。
$ extract-streetview 35.7004793,139.7768184 -f jpg -q 100 -z 2 -o unifa_office_sv_pano.jpg
React VRアプリをビルド
$ cd react_vr
$ npm run bundle
React VRアプリのコード(html)の修正
vr/index.html
をエディタで編集します
index.htmlにcordova.jsを追加
<body>
.....
<script type="text/javascript" src="cordova.js"></script>
</body>
ビルドした js を使うようにパスを修正
2箇所修正します。.jsをつけないとNGのようです
client.bundle.js
<script src="./build/client.bundle.js?platform=vr"></script>
index.bundle.js
'./build/index.bundle.js?platform=vr&dev=true'
static_assets が index.html があるディレクトリから見えるようにする
ln -s ../static_assets .
assetsRootのパラメータを追加
ReactVR.init(
// When you're ready to deploy your app, update this line to point to
// your compiled index.bundle.js
'./build/index.bundle.js?platform=vr&dev=true',
// Attach it to the body tag
document.body,
{ assetRoot: 'static_assets' } // 追加
);
cordovaのwwwディレクトリがReact VRのコンテンツを参照するようにする
cordovaプロジェクトのルートディレクトリに移動して
$ mv www www.orig
$ ln -s react_vr/vr www
cordovaアプリをビルド
$ cordova build [ios/android]
この状態で $ cordova serve ios
をするとブラウザ上で動作確認できます。
続いてエミュレーターで動作確認します
iOS
$ cordova emulate ios
必要に応じて --target=iPhone-6s
のようにターゲット端末をオプションで指定します。
おお、出ました! ただし、シミュレーターではジャイロが使えないため真下向きのままから動きません… (´Д`。)
Android
Android は 最初にエミュレーターを起動してから コマンドを打ってください
$ cordova emulate android
orz.. AndroidのエミュレーターはWebGLをサポートしてないようです..
手持ちのiPad mini でやってみます。
そのまま、$ cordova run ios
すると
`Code Sign error: No code signing identities found: No valid signing identities (i.e. certificate and private key pair) were found.`
のエラーが出るので Xcodeのプロジェクトを開きます
$ open platforms/ios/HelloCorodvaReactVr.xcodeproj
Fix issueしてXcode上でビルド、実行します。
アプリは起動できたもののテクスチャが表示されません..。(ノ゚ο゚)ノ
iPad miniが古いせいでしょうか…
Androidは手持ちのNexus5がいつの間にやらUSBデバッグ接続できなくなっていて(なぜ…?)実機で確認できませんでした..
iOS、Androidとも最新の実機では動いてくれると信じています。。
iPad mini の OS を10.3 に アップデートしたら見れるようになりました! ヾ(´▽`)ノ
アップデート前は動いてなかったThree.jsのサンプルがOSアップデート後に動くようになったのでそれでWebGL対応を判定できそうです。 https://threejs.org/examples/#webgl_animation_cloth
みなさまこんにちは。ユニファCTOの赤沼です。私がユニファでCTOという役割を担うようになってから一年ちょっと経ちました。私も入社当初はガンガンコードを書いていましたが、最近は基本的には自分ではコードを書かなくなり、他のメンバーからは私が何をやっているのか、どんな役割なのかが見えづらくなって来てしまいました。そこで先日開発部の定例ミーティング時に、私が考えるユニファCTOの役割についてメンバー向けに話させてもらったので、ここでも簡単に紹介させていただこうと思います。
一般的な定義としては、「技術的な視点で経営にコミットする」というのがCTOの役割であり、技術と人の問題に答えを出して実行する人ということになるかと思います。それをユニファの事業内容を踏まえて少し具体化すると、「先端的な技術を保育の現場や家族コミュニケーションに活かす方法を見つけて実行する、また、そういうチームを作る人」ということになると思っています。経営陣の一員としては技術視点での事業企画への提案を求められるわけですが、他の経営陣への技術的な理解を促すことも、前述の役割を果たすためには必要になって来ます。
良くある話として、エンジニアやクリエイターがユーザ視点を忘れてシステムを作ると、実際のユーザにとっては受け入れられないことが多いので、ユニファではサービスの主なユーザである保育士や保護者の視点で考えることを重視しています。保育の現場や家族コミュニケーションそれ自体について深く掘り下げて考えることはとても重要で、開発部メンバーにとっても必要なことです。ですが、ちょっと見方を変えると、それは開発部メンバー以外でもできることではあったりします。逆に、それぞれの専門的な技術領域について深く掘り下げていったり、それを現場にどう活かせるかを考えるのは、開発部メンバーにしかできません。もちろんユーザ視点を忘れて良いということではないですが、それぞれの領域におけるプロフェッショナルとしての技術向上が本来の役割として強く求められます。例えばエンジニアがAIの技術的な流れに乗れていないと、長期的に見たときにビジネス面でも取り残される可能性があるわけです。
ユニファは先日優勝したStartup World Cupをはじめ、色々なピッチコンテスト等で賞をいただいていて、事業モデルとしては高い評価をいただいていますが、会社としては事業モデルも優れているし、技術面でも強みがあるというのが理想なわけです。今後の技術的な方向性として、技術的にも強みなるし、事業面でも優位に立てる技術をいかに選択していくかということになります。
とは言え純粋な技術要素自体を事業的な強みにするのは困難です。なので最初から全く新しい道を探すのではなく、すでにデファクトスタンダートになっている技術や、ある程度環境が整って来ている技術は大いに活用させていただき、高速道路を進んだそのちょっと先のまだ整っていない領域をどう開拓していくかということではないかと思っています。そのためには技術的な視点を高く保つことが大事ですし、技術要素だけでなく、開発プロセスなどに強みを見つけられる可能性もあります。
また、そういった取り組みをしていくためには、会社全体として技術に投資していく文化を作ることが必要になります。ビジネスサイドメンバーからすると結果に直結する部分ではないので理解を得づらいのですが、将来的なことを考えて今技術に投資していくと同時に、現在のシステムが持っている、目に見えない技術的な課題を解消していくことについてリソースを割くことに納得感を持ってもらえるように働きかけていくことが求められると思っています。
CTOとしては誰よりも深く考えて、5年後、10年後を考えたときに今どの技術を選ぶかの技術的な方針を打ち出す言わばトップダウンの視点になるわけですが、一方で各メンバーからも、こういうことができるんじゃないか、というボトムアップの提案が出てくることも重要です。こういったボトムアップの提案がメンバーからどんどん出てくる、ボトムアップ体質を持った、トップダウンとボトムアップの両面から挟み込んでいけるチームを作っていくことが重要だと思っています。技術面でも例えばエンジニアであれば、プログラミングやコンピュータサイエンスなどのベース技術のレベルアップと、先端技術のキャッチアップの両面が求められていきます。メンバーそれぞれがそれぞれの専門領域におけるプロフェッショナルとして、スキルアップへの手を休めず追求していくことに当然のこととして取り組んでいけるチームを作っていきたいと思っています。
こんにちは。スマートフォンエンジニアのまさです。
最近サーバとやりとりをするアプリを作成していますが、APIをなんども叩くアプリでは、
どうしてもローディングが多くなりがちで、ユーザーにストレスを与えてしまいます。
何度も叩く必要のないAPIはレスポンスをRealmに保存しておいて、より快適なアプリを実現したいですね。
今回は、Realmで多対多のモデルを作る方法をご紹介します。
まずは、podでrealmを入れます。
$ pod init $ vi Podfile
pod 'RealmSwift' # 追加
$ pod install
今回は複数の子供が複数のグループに所属しているモデルを作ってみようと思います。 基本的には、多対多は、中間テーブルを用意し、それぞれのテーブルに一対多にすることで実現します。
import RealmSwift class Kid: Object { dynamic var id = 0 dynamic var name = "" var kidGroups = List<KidGroup>() override static func primaryKey() -> String? { return "id" } } class KidGroup: Object { dynamic var group: Group? dynamic var kid: Kid? let ownerKid = LinkingObjects(fromType: Kid.self, property: "kidGroups") let ownerGroup = LinkingObjects(fromType: Group.self, property: "kidGroups") } class Group: Object { dynamic var id = 0 dynamic var name = "" var kidGroups = List<KidGroup>() override static func primaryKey() -> String? { return "id" } }
モデルクラスを用意したら、データを入れてみます。 テストなので、viewDidLoadに入れてログを出して確認しています。
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. // テストのため、毎回realmのDBを消して再度新規生成されるようにしています let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) let path = paths[0] + "/test.realm" let url = URL(fileURLWithPath: path) let fileManager = FileManager.default if fileManager.fileExists(atPath: path) { try! FileManager.default.removeItem(atPath: path) try! FileManager.default.removeItem(atPath: path + ".lock") try! FileManager.default.removeItem(atPath: path + ".management") } let realm = try! Realm(fileURL: url) // たろう君は、たぬき組に、所属、 // じろう君は、たぬき組、きつね組どちらにも所属させてみる let kid = Kid() kid.id = 1 kid.name = "たろう" let kid2 = Kid() kid2.id = 2 kid2.name = "じろう" let group = Group() group.id = 101 group.name = "たぬき組" let group2 = Group() group2.id = 102 group2.name = "きつね組" let kidGroup = KidGroup() kidGroup.group = group kidGroup.kid = kid kid.kidGroups.append(kidGroup) group.kidGroups.append(kidGroup) let kidGroup2 = KidGroup() kidGroup2.group = group2 kidGroup2.kid = kid2 kid2.kidGroups.append(kidGroup2) group2.kidGroups.append(kidGroup2) let kidGroup3 = KidGroup() kidGroup3.group = group kidGroup3.kid = kid2 kid2.kidGroups.append(kidGroup3) group.kidGroups.append(kidGroup3) try! realm.write() { realm.add(kid) realm.add(kid2) } }
それでは、正しく参照できるのか、また中間テーブルが削除されれば きちんと関連がきれるのか、テストしてみようと思います。下記のコードをviewDidLoadの下側に追記してみます。
// クエリ print("Kidのオブジェクトをすべて取得する") let kids = realm.objects(Kid.self) print(kids.count) // => 2 print(kids[0].kidGroups.count) // => 1 print(kids[1].kidGroups.count) // => 2 print("Kidのidが2のオブジェクトを取得する") let kidsId_2 = realm.objects(Kid.self).filter("id = 2") print(kidsId_2[0].kidGroups.count) // => 2 print(kidsId_2[0].kidGroups[0].group?.name ?? "") // => たぬき組 print(kidsId_2[0].kidGroups[1].group?.name ?? "") // => きつね組 print("Groupがきつね組に所属しているkidを取得する") let groupsId_102 = realm.objects(Group.self).filter("id = 102") print(groupsId_102[0].kidGroups.count) // => 1 print(groupsId_102[0].kidGroups[0].kid?.name ?? "") // => じろう print("Kidじろうのgroupきつね組との関連を切ってみる") try! realm.write { realm.delete(groupsId_102[0].kidGroups[0]) } print("きちんと関連が切れているか確認する groupから参照した場合") let updateGroupsId_102 = realm.objects(Group.self).filter("id = 102") print(updateGroupsId_102[0].kidGroups.count) // =>0 print("きちんと関連が切れているか確認する kidから参照した場合") let updateKidsId_2 = realm.objects(Kid.self).filter("id = 2") print(updateKidsId_2[0].kidGroups.count) // => 1 print(updateKidsId_2[0].kidGroups[0].group?.name ?? "") // => たぬき組
正しく参照できているようです。中間テーブルを削除して関連を切れば、kidから参照しても、groupから参照しても正しい結果と
なっているのがわかります。多対多を実現させることができました。
まだまだRealm初心者なので、今後もいろいろと試してみようと思います。
もしここがおかしいとか、こういう書き方もあるよなどありましたら、ご指摘頂けると幸いです。
こんにちは、WEBエンジニアのチョウです。
1つのサービスに新機能がどんどん追加されると、ロジックが複雑になり、開発やメンテナンスは難しくなります。その解決方法はいつくかあると思いますが、1つの方法として、1つのサービスを複数サービスに分割して別々で開発するというやり方があります。複数サービスへの分割には、スケールアウトに優れているなどのメリットがありますが、テストの実施やインフラの準備は以前よりも難しくなります。今回、複数サービスにおけるローカルテストについてすこし共有したいと思います。
普通のローカルテストはアプリケーションを立ち上げて、ブラウザでテストするのです。複数サービスの場合は、必要なサービス一つ一つを起動しないといけないです。そこで、設定の問題だったり、サービスが依頼する環境の問題だったり、一回だけならいいですが、毎回やらないといけないと無駄に時間かかります。もし設定は事前に用意できて、環境はちゃんと管理されているツールがあれば一番いいかなと思う人はきっといますでしょう。
AWSにすでにAMIみたいなサーバーインスタンスのsnapshotを取る仕組みがあります。ローカルの仮想マシンでsnapshotを取ってテストするのも可能ですが、パソコンで同時に起動できる仮想マシンが限られてるようで、AMIのやり方でテストするのは非現実的だと思います。もう1つの方法は、dockerなどのコンテナ技術です。
コンテナ技術というのはcgroupsなどの仕組みを利用して、サーバー一台で複数サーバーのように、1サーバー1アプリケーションを起動します。cgroups自体は「プロセスグループのリソース(CPU、メモリ、ディスクI/Oなど)の利用を制限・隔離するLinuxカーネルの機能」です。コンテナ技術の中で一番有名なのはdockerです。
つまり、dockerを利用すれば、一台サーバー(dockerの仮想マシン)で複数サービスを起動することが可能になります。もっと正確にいえば、dockerで各サービスのimageを作って、docker-composeを使って複数サービスを起動してテストすることができます。
最近こちらが携わったプロジェクトを紹介します。サービスの構成
nginx ----> Service A ----> Database A
|
--> Service B ----> Database B
元々これらのサービスを起動するには
dockerを使う場合
docker-compose up -d
で一気に起動できる。
もちろん、設定ファイルが必要です。docker-compose.ymlでこんな設定があります。
version: '2'
services:
haproxy:
image: 'nginx'
ports:
- '8081:8081'
depends_on:
- service-a
- service-b
service-a:
image: 'service-a'
command: rails s -p 3000
volumes:
- /path/to/service/a:/usr/src/app
depends_on:
- service-db
environment:
RAILS_ENV: development
service-b:
image: 'serivce-b'
command: rails s -p 3001
volumes:
- /path/to/service/b:/usr/src/app
depends_on:
- service-db
environment:
RAILS_ENV: development
service-db:
image: 'postgres:9.4'
volumes:
- data-service-db:/var/lib/postgresql/data
volumes:
data-service-db:
docker-compose.yml自体は複数のdocker containerを組み合わせる設定ファイルで、パラメータ名は基本dockerがcontainer作る時のパラメータと同じです。docker containerというのは、docker imageのインスタンスです。docker imageはアプリケーションの稼働環境と理解してもいいです。docker imageを作るには、Dockfileを利用し、アプリケーションが依頼してるソフトウェアのインストールしたり、アプリケーションのファイルをコピーしたりして、アプリケーションバイナリのように1つコマンドで起動できるリソースグループを作ります。
Railsアプリケーションにとっては、ローカルで開発する場合が多いですので、Gemfile/Gemfile.lockだけでdocker imageを作って、docker-compose.ymlの中でソースコードをマッピングするほうがおすすめします。
例えば、こんなDockerfile
FROM ruby:2
RUN echo 'deb http://http.debian.net/debian jessie main' >> /etc/apt/sources.list && apt-get update && apt-get install -y nodejs && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN echo "Asia/Tokyo" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
COPY Gemfile /usr/src/app/Gemfile
COPY Gemfile.lock /usr/src/app/Gemfile.lock
RUN bundle install
ちなみに、複数サービスではなくても、application + databaseみたいなパターンも使えます。そして、多数なサービスを起動するのもしんどいかもしれません。一部のサービスだけ変更したり、影響されるサービスが少なかったりする時、Dockerでテストするのは楽になると思います。サービスの数が多くなれば、リモートでサーバーの立ち上げて、リモートのサーバーでテストするほうがいいかもしれません。
いかがでしょうか。複数サービスがかかわるプロジェクトでDockerを使ってみませんか。
こんにちは、サーバーサイドエンジニアの本間です。
以前弊社のしだより、デジタル連絡帳アプリ るくみーnote のクライアントサイド開発の一部 をご紹介させていただきました。 今回は、このプロダクトのサーバーサイド開発で工夫した点をご紹介したいと思います。
この開発におけるサーバーサイドエンジニアの主なタスクは、デジタル連絡帳のデータを保管するためのAPIサーバーの構築です。 今回、アプリとサーバーは完全分業で並列に開発を進めることから アプリケーション開発者にいかに早くAPIの仕様や動作を理解してもらえるか が開発を円滑に進める上での鍵になりそうだなと考えていました。
この問題に対応するため、以下の2つの対策を可能な限り工数をかけずに実施したいと思い、調査しました。
インフラエンジニアのすずきです。2回目!
先日弊社社長がシリコンバレーにいき”Startup World Cup 2017”に参加し戦ってまいりました。 そして見事優勝することができました。 応援してくださった皆様ありがとうございました!!
その様子を記事にて
新たな投資を受けたことで、さらなる事業拡大を図っていきたいところです。
その流れでと言うか、事業拡大というか新しいサービスを作る際に、 AWSを利用されてる方はサービスごとにアカウントを分けたりされるのではないかな?と思います。 でもアカウント発行ってなかなか面倒で、
手間がかかりますよね、完璧に覚えてる情報でもないですし…
そんななか2017年2月27日AWS Organizations が一般公開されました これで一括請求アカウントから、子アカウントを作成することができるようになるようです。
そしてちょうど良いタイミングで、新規アカウント発行する需要があったので、新規アカウント作成のついでにAWS Organizationsも設定してみました。 設定じゃなくてアカウント作るところだけ見たい方は、先頭を少し読んでから最後の方に飛んでもらったら良いかなと思います。
続きを読む