Android MVVM 設計 2

Android 担当の k-matsushita です。

前回は MVVM の概念について紹介しました。今回はサンプルアプリを元に MVVM をどうやって実装していくかを紹介します。

nekojarashi.hatenablog.jp

続きを読む

Android MVVM 設計 1

Android 担当の松下です。

Android アプリを作った時に Activity に全て詰め込んでしまった事はありませんか?
実は僕が Android アプリに join した時はそういう設計でした…。(リリースを急いでいたらしいので仕方ないですね 😓)
リリースが完了し少し落ち着いた頃に、大規模なリファクタリングを行うことが決まって、その時に 「MVVM」 にしようという話が出てきました。

そういった経緯で弊社アプリは MVVM の設計になりました。
今回は 「MVVM」 の恩恵を、経験に基づいて書いていこうと思います。

続きを読む

WCF で簡単にプロセス間通信

開発部の y-okubo です。

今回は C# の(正確には .NET Framework)WCF を使ってプロセス間通信を簡単に行ってみようと思います。

WCF の基本的な概念については以下の記事を参照してください。

www.atmarkit.co.jp

今回やりたい事を図にすると以下のような内容になります。

f:id:nekojarashi-Inc:20170814181814p:plain

WCF 関係コード

サービス実装

お行儀良くやるのであれば、インターフェイスの定義と実装は別ファイルにすべきでしょうが、ここはサクッと作ってしまいたいので単一ファイルに両方定義してしまいます。

using System.ServiceModel;

namespace Hoge
{
    [ServiceContract]
    public interface ISearchService
    {
        [OperationContract]
        void Execute();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
    public class SearchService : ISearchService
    {
        public delegate void Searcher();

        public Searcher SercherDelegate;

        public void Execute()
        {
            SercherDelegate();    // 実装はデリゲートします
        }
    }
}

サービス起動(サーバ)

例外処理はかなりアバウトです。

SearchService service = new SearchService();
service.SercherDelegate = hogeForm.SearchRequest;    // デリゲート登録

serviceHost = new ServiceHost(
    service,
    new Uri("net.pipe://localhost/Hoge"));

try
{
    serviceHost.AddServiceEndpoint(
        typeof(ISearchService),
        new NetNamedPipeBinding(),
        "SearchService");
    serviceHost.Open();
}
catch (AddressAlreadyInUseException)
{
    MessageBox.Show("既にサービスは起動しています。");
}
catch (Exception e)
{
    MessageBox.Show(e.ToString());
}

サービス呼び出し(クライアント)

new ChannelFactory<ISearchService>(
    new NetNamedPipeBinding(),
    new EndpointAddress("net.pipe://localhost/Hoge/SearchService")).CreateChannel()
    .Execute();

サービス関連のハマり所

  • NetNamedPipeBinding() の引数はサービス側と呼び出し側で揃えないと例外が発生するので気を付ける。
  • EndpointAddress の指定を間違えないように気を付ける。
    • EndpointAddress は ServiceHost の URI と Endpoint を結合した文字列。
    • サービス側はこれらを別々に指定しているが、呼び出し側は結合した文字列を指定しているので注意。

Windows Forms 関係コード

実際にフォームを呼び出す

サービス起動時に登録したデリゲートメソッドです。

public void SearchRequest()
{
    // ここは必ず別スレッドで呼ばれる
    Invoke((MethodInvoker)delegate ()
    {
        MainForm_ShowSearchForm(this, null);
    });
}

フォーム呼び出し時のハマり所

  • メインスレッドで実行せねばならないので気を付ける。
    • 上記のメソッドはサービスのスレッド(バックグラウンド)から呼び出されることが分かっているので、InvokeRequired でのチェックを省略しています。

まとめ

WCF を使う方法について簡単に紹介いたしました。

プロセス間通信となるとかなり面倒なイメージがありますが、WCF を使えばサーバ・クライアント通信の様に行うことができます。

最近のアプリは役割毎に小さな粒度でプロセスを分けて緩やかに連携する、いわゆるマイクロサービス的な構成の物が増えているようですので、C# のみでアプリを構成するのであれば WCF は有力な選択肢になるかと思います。

WCF を使う上でこの記事がお役に立てば幸いです。

ねこじゃらしについて

ねこじゃらしでは C# に限らず Ruby (Ruby on Rails) や JavaScript での開発経験がある Web エンジニア、UI/UX デザイナを募集しております。

ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。

www.nekojarashi.com

シンプルなUIを作る

簡単なUIを作るために

開発部のiOS担当の林田です。 見た目上のUIがシンプルであっても条件が多い設計は実装に時間がかかり、文字や画像の多さ大きさなどでレイアウトが大きく変わってしまいます。 今回はスマホのUI設計をするときにシンプルで条件の少ないレイアウトを作っていきます。

このようなデザインがあったとします。

f:id:nekojarashi-Inc:20160825191953p:plain

これを要素ごと色分けをします。
ここでは各要素のマージンは8px(dx)として考えます

f:id:nekojarashi-Inc:20160825192220p:plain

要素としては

  • アイコン(黄色)
  • タイトル(緑)
  • テキスト(水色)

に分かれます。

iOSであればUIView、AndroidではViewと呼ばれる単位として分けます。 表示されるディスプレイの固定であれば問題ありませんが、スマホは端末によってサイズが異なります。

横幅の長い端末で表示するとこうなります。

f:id:nekojarashi-Inc:20160825192451p:plain

これはアイコンとタイトルの横幅が固定(Fix)になっており、背景とテキストの横幅が可変(Flexible)になっているためです。

f:id:nekojarashi-Inc:20160825192559p:plain

スマホのみならずブラウザでもよく見られるデザインで、固定値と可変値をもたせ、様々なサイズのディスプレイに対応します。

実はこのデザインには問題あります、タイトルが固定値となっているため、長いタイトルが入ると入りきれなくなります。
試しにタイトルをJectorからThe long title applicationに変更してみます。

f:id:nekojarashi-Inc:20160826154840p:plain

タイトルがテキストに被っているので、いくつか対応するレイアウトにしてみます。

  • タイトルの横幅がテキストの横幅より優先して表示される

f:id:nekojarashi-Inc:20160826155048p:plain

この場合条件は

  • タイトルの横は可変、縦は固定
  • テキストの横は可変、縦は可変
  • タイトルはテキストより先に横幅が決まる

ということになります。 非常に見難いレイアウトなっていますね。

  • タイトルは一定のサイズ以上になると後が省略される

f:id:nekojarashi-Inc:20160826155219p:plain

レイアウトは変わりませんが、もしタイトルがここでしか表示されないのであれば、ユーザーはすべてのタイトルは見えないことになります。

  • タイトルは、テキストの下に表示される

f:id:nekojarashi-Inc:20160826155330p:plain

この場合条件は

  • タイトルはテキストの下に表示される
  • タイトルの横は可変、縦は固定
  • テキストの横と縦は可変

とりあえずこれにしましょう。

ですがまだ問題があります。
先ほどタイトルはテキストの下に表示されるという条件を追加しましたが、テキストが少ない時にこうなります。

f:id:nekojarashi-Inc:20160826155452p:plain

条件を付け加えます

  • タイトルはテキストとアイコンのどちらか、縦幅の大きいほうの下に表示される
  • タイトルの横は可変、縦は固定
  • テキストの横と縦は可変

f:id:nekojarashi-Inc:20160826160023p:plain

これで正常に表示されました

ここまで変更するとタイトル上にあったほうが良いと思います

f:id:nekojarashi-Inc:20160826155917p:plain

  • タイトルの横は可変、縦は固定
  • テキストの横と縦は可変
  • アイコンの横と縦は固定

結構シンプルな条件になりました。

まとめ

  1. 要素ごと分ける
  2. 固定値と可変値を割り振る
  3. 最小値と最大値を決める
  4. 条件を付け過ぎると矛盾がおきたり、想定してなかったレイアウトになってり、実装に時間がかかったりする

お知らせ

ねこじゃらしではUI/UX デザイナを募集しております。

ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。

www.nekojarashi.com

Swift で MessagePack-RPC

ねこじゃらしの y-okubo と申します。

今回は、Swift で MessagePack-RPC を実現するライブラリの使い方を紹介します。

MessagePack-RPC については、こちらをご覧ください。

www.slideshare.net

ひとことで言えば、MessagePack (JSON) を使った RPC です。

各言語にライブラリが用意されており、異なる言語で作ったアプリ間でプロセス間通信をするのに便利です。

github.com

なぜか公式にはリストアップされていないのですが、Objective-C 版もあります(CocoaPods 対応がありがたい)。

github.com

今回は、コレを Swift から使ってみることにしました。

プロジェクトの作成

まず、Xcode で適当なプロジェクトを作成します。 今回は OS X - Application - Command Line Tool のプロジェクトを作成します。

f:id:nekojarashi-Inc:20160810182458p:plain

ターミナルでそのディレクトリまで移動して、以下のコマンドで CocoaPods をインストールします。

pod init

この後は、作成された Podfile に使用するライブラリを追加していきます。 Podfile を編集して、以下の内容を追加します。

pod 'MPMessagePack'

以下のコマンドを実行してライブラリをインストールします。

pod install

CocoaPods のライブラリを Xcode で使うには、先のコマンドで生成された .xcworkspace ファイルを開きます。

サンプルコード

簡単なコードを書いて動作確認をしてみます。

まずはサーバのリクエストハンドラを追加します。

RPC が呼び出されると必ずこのコードが実行されます。

メソッド名で分岐することで RPC 呼出しに対応したコードを記述できます。

今回は実験的なコードなので、そのような分岐はせず同じような戻り値を返しています。

func serverRequestHandler(messageId: NSNumber?, method: String?, params: [AnyObject]?, completion: (MPRequestCompletion)?) {
    if let method = method, let params = params {
        print("(Server) method:", method)
        print("(Server) params:", params)
    }
    
    completion!(nil, "Return from server(\(method))")
}

サーバを起動するコードを追加します。

リクエストハンドラを設定して、ポート 5001 番でサーバを起動してみます。

// Server

var server: MPMessagePackServer = MPMessagePackServer()

server.requestHandler = serverRequestHandler

do {
    try server.openWithPort(5001)
}
catch let error as NSError {
    print(error)
}

クライアントのコードを追加します。

こちらは非同期実行のコードになります。

var client: MPMessagePackClient = MPMessagePackClient()

client.openWithHost("127.0.0.1", port: 5001, completion: {error in
    client.sendRequestWithMethod("method_hoge", params: ["hoge", "42"], messageId: 1, completion: {error, result in
        if let error = error {
            print("Error:", error)
        }
    })
})

同期実行のコードは以下になります。 こちらは Exception を throw するので do ~ try ~ catch で例外ハンドリングをする必要があります。

client.openWithHost("127.0.0.1", port: 5001, completion: {error in
    do {
        try print(client.sendRequestWithMethod("method_fuga", params: [], messageId: 1, timeout: 2.0))
    } catch let error as NSError {
        print("Error:", error)
    }
})

注意点として、Command Line Tool でプロジェクトを作成している場合は、以下のコードも追加してください(このコードを追加しないと動きません)。

このコードで無限ループを回してクライアントからのリクエストを待ちます。

NSRunLoop.currentRunLoop().run()

では、コードを実行してみます。

2016-08-12 15:35:40.222 MsgpackRpcSwiftExample[11273:1429215] -[MPMessagePackServer connectionWithInputStream:outputStream:]:38: [Server] Client connected
(Server) method: method_fuga
(Server) params: []
(Server) method: method_hoge
(Server) params: [hoge, 42]

クライアントからの RPC 呼出しに対してサーバが値を受け取っているのがおわかりいただけるかと思います。

まとめ

MessagePack-RPC を Swift から使う方法について簡単に紹介いたしました。

他の言語についてもライブラリが存在するので、異なる言語間でプロセス間通信を行うような処理が必要になったとき、気軽に使えて便利です。

最近はマイクロサービス化によりコンポーネント疎結合化が加速しており、設計の都合やチームのスキルセットによって言語を使い分けるシーンも増えているのではないでしょうか。

そのようなときに、それらコンポーネントを繋ぐ方法として MessagePack-RPC は有力な選択肢になり得ると思います。

MessagePack-RPC を使う上でこの記事がお役に立てば幸いです。

お知らせ

ねこじゃらしでは Swift に限らず RubyJavaScriptプログラマ、UI/UX デザイナを募集しております。

ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。

www.nekojarashi.com

Go の パッケージ管理ツールは glide がイイ感じ

ねこじゃらしの y-okubo と申します。

今回は、仕事で Go を書いたときに使ったパッケージ管理ツール glide について簡単にですが、紹介させていただきます。

そもそも Go にはパッケージ管理を行うための仕組みがありません。
パッケージ管理をし易くするための仕組みが、現行の 1.6 で導入された Vendoring です。

Vendoring の詳しい説明はググっていただくとして、実際にはパッケージ管理を行うためのツールが必要になります。

この手のいわゆるパッケージ管理ツールは gbgom が有名のようですが、今回は試してみて便利だった glide を採用することにしました。

glide 使い方

glide コマンド自体をインストールします。

$ go get github.com/Masterminds/glide
$ go install github.com/Masterminds/glide

glide コマンドで依存パッケージをインストールします。

$ glide create
$ glide install

これで、対象ディレクトリに glide.yaml と glide.lock ができます。
また、vendor ディレクトリも作成され、その中に依存するパッケージが格納されます。
glide.yaml と glide.lock だけをリポジトリに格納して、vendor ディレクトリは Git で Ignore 指定してください。

このリポジトリを初めて使う方は、glide コマンド自体をインストールした後に glide install をすれば、vendor ディレクトリに依存パッケージがインストールされます。

まとめ

私は普段 Ruby で開発をしていて Bundler を使っているのですが、 コマンド体系や構成ファイルがそれと似ており、違和感なく使うことができました。

もう一つの候補であった gom と比べると、コマンド体系や YAML 書式がスッキリしているのもイイ感じで、ドキュメントがよく整備されているのもあって、glide を正式導入することにしました。

逆に言えば、gom は Bundler によく似たコマンド体系や YAML 書式を持っているので、かなり複雑な設定もできそうです(Go 標準のツールがシンプルで強力なので複雑な設定自体が不要な気もしますが)。

glide や gom 以外のパッケージ管理を選択されるのも良いかと思いますが、現時点では glide が個人的に最もオススメできるパッケージ管理ツールです。

glide で快適な Go 開発を!

お知らせ

ねこじゃらしでは Go に限らず RubyJavaScriptプログラマ、UI/UX デザイナを募集しております。

ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。

www.nekojarashi.com

開発部LTを開催しました! (テーマ Rack について)

バックアップ開発部の r-fujiwara です。 ねこじゃらし開発部では、二週間に一度、メンバーの最近の興味を持っていることや、業務で行っていることなどを持ち回りで LT を行っています。

今回

今回は記事を書いている r-fujiwara の番でした。 主に Rack(Application / Server) の話をさせて頂きました。

分かったつもりになるかもしれないRack

speakerdeck.com

この発表をしようと考えた動機

  • (冒頭にもありますが、)教えている後輩に「Rack って何ですか?」と聞かれて答えに窮してしまったので、この機会にちょっと触れてみたかったから。

  • RailsDevelopment で開発していると、やはり「WEBrickって何よ?」「Puma って何よ?」って所に関して、多分自分自身もあまり自信を持って答えられ無さそうだったので、この機会で整理したかったから。

  • しかしながら、Rack のことをあまりにも普通に話しすぎてしまっても、それはそれで何かしらのドキュメントを読めばいい話であると考え、今回は「車で例える」というアプローチを取り、より噛み砕いた説明が出来ないか、と考えて今回の Rack の発表といたしました。

こういった背景があります。

個人的感想

  • 自分としては rack は非常に面白い仕組みであり、Rack Server や Rack Application のソースを読むだけでもかなり力になる、と考えております。

  • アプリケーションを作るだけでなく、その中身がどう動いているのか?とちゃんと理解して然るべき技術選定出来るエンジニアになっていきたいと私は考えておりますし、またそういった人材をねこじゃらしで育てていければ、と考えております。