だいたい死んでる

渋谷で働いているWEBプログラマーです。

第1章 アプリケーションアーキテクチャとは1

この記事は「アプリケーションアーキテクチャ設計パターン」を読んだまとめ記事です。 今回は第1章についてまとめます。読書のメモになるためより詳しくは本を読んでください。

www.amazon.co.jp

アーキテクチャとは 

システム開発現場でのアーキテクチャは以下のように多数の意味をもつ。

この本はアプリケーションアーキテクチャを主題に書かれている。 アプリケーションアーキテクチャはアプリケーションアーキテクチャを設計する上で基本的な設計方針であり制約である。

アプリケーションアーキテクチャの目標

2つの目標がある

アプリケーションの構造

規模の大きなシステムを小さな部品に分けて行く。部品は「コンポーネント」と呼ぶ。コンポーネントを適切に分けることで管理しやすくする。分割の粒度とコンポーネント同士の連携をどのようにするかを考える必要がある。

アプリケーションの処理方式

どのように処理を記述するかを考える。

アプリケーションアーキテクチャが必要な理由

アプリケーションの整合性確保

アプリケーションアーキテクチャを適切に設計しないと、全体的な整合性が崩れてしまう事があり、これは結合テストなどの後工程で顕在化する傾向にある。

設計品質の向上

アプリケーションアーキテクチャは設計上の制約であるため十分に検証する必要がある。アプリケーションアーキテクチャの設計が不十分であると各ユースケース担当者が設計する余地が残ってしまう。その結果、検証が不十分なアーキテクチャを採用してしまったり、機能要件に対して不十分もしくは過剰なアーキテクチャになってしまう可能性があります。 適切に設計することにより、良い意味で自由が奪われるため、各ユースケース開発における設計品質を一定に保つことができます。

拡張性・保守性の向上

リリースして終了ではなく投資を回収する必要があり、長期間運用されることを考慮しなければいけない。運用期間の間に機能拡張や仕様変更を行う必要が出てくる。 アプリケーションアーキテクチャが適切に設計されていないと、機能拡張や仕様変更での影響範囲が大きくなってしまい、場合によってはアプリケーションを作り直す必要が出てくるかもしれない。 このような事態を回避するためにはコンポーネントを適切に分割する必要がある。コンポーネント同士はお互いに疎結合にする。

アプリケーションアーキテクチャ設計のポイント

アプリケーションアーキテクチャは非機能要件と密接な関係がある。 非機能要件も充足できるように設計する必要がある。 また、目的が複数ある中で全てを達成しようとするとビジネス的に成功と言えなくなる場合や学習コストが高すぎるとチームメンバーへの負荷が高まる。現実的な妥協点を見つけ出すことも大切。

まとめ

文章の量が増えてきたので、別記事で続きを書いていきます。

SwiftUIでMVVM

この記事は ウィルゲート Advent Calendar 2019 の22日目の記事です。

ConbainとSwiftUIが登場したことで、データバインディングの仕組みを公式がサポートしました。 サンプルとしてMVVMでアプリを作ってみようと思います。

作るアプリ

天気を一覧で見れるアプリを作ってみる。 天気情報取得には以下のAPIを使用しました。

openweathermap.org

ディレクトリ構成について

app
- View
- ViewModel
- Model

上表のように各役割によってディレクトリを分ける。 役割ごとに依存の方向は下図のようにしていきます。

f:id:MikaE:20191216000004p:plain

Viewについて

ユーザーへ機能を提供するために描画を担当します。また、ユーザーからの入力を受け取りViewModelへ渡します。 またViewModelのデータとデータバインディングすることでデータの変更と描画の変更を同期させます。

ViewModelについて

Viewを描画するための状態の保持と、Viewから受け取った入力を適切な形に変換してModelに伝達する役目を持っています。 Viewとの通信はデータバインディングの機構を使って行われます。

Modelについて

アプリケーションのドメインを持つのがModelです。ビジネスロジックを書くところになります。また、データの永続化を行う箇所でもあります。

コードについての説明

Model

APIのレスポンス値からCodableのコードを作成してくれる、quicktypeを使用して自動生成できます。 自動生成したので基本的に何も変えずに使用します。

// MARK: - Weathers
struct Weathers: Codable {
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind
    let clouds: Clouds
    let dt: Int
    let sys: Sys
    let id: Int
    let name: String
    let cod: Int
}

// MARK: - Clouds
struct Clouds: Codable {
    let all: Int
}

// MARK: - Coord
struct Coord: Codable {
    let lon, lat: Double
}

// MARK: - Main
struct Main: Codable {
    let temp: Double
    let pressure, humidity: Int
    let tempMin, tempMax: Double

    enum CodingKeys: String, CodingKey {
        case temp, pressure, humidity
        case tempMin = "temp_min"
        case tempMax = "temp_max"
    }
}

// MARK: - Sys
struct Sys: Codable {
    let type, id: Int
    let message: Double
    let country: String
    let sunrise, sunset: Int
}

// MARK: - Weather
struct Weather: Codable {
    let id: Int
    let main, weatherDescription, icon: String

    enum CodingKeys: String, CodingKey {
        case id, main
        case weatherDescription = "description"
        case icon
    }
}

// MARK: - Wind
struct Wind: Codable {
    let speed: Double
    let deg: Int
}

ViewModel

データをAPIから取得する処理とModelの型に合わせて変数へ格納する処理を書いていきます。 また、Viewへデータバインドしたいので、PassthroughSubjectとObservableObjectを使用してバインドするための準備もしています。

class WeatherViewModel: Identifiable {
    
    let id = UUID()
    
    let weather: Weather
    
    init(weather: Weather) {
        self.weather = weather
    }
    
    var main: String {
        return self.weather.main
    }
}

class WeathersViewModel: ObservableObject {
    
   let didChange = PassthroughSubject<MemosViewModel,Never>()
    
    init() {
        fetchTopHeadlines()
    }
    
    var weathers = [MemoViewModel]() {
        didSet {
            didChange.send(self)
        }
    }
    
    private func fetchTopHeadlines() {
        let apKey = ""
        let baseURL = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid="
        guard let url = URL(string: baseURL + apKey) else {
            fatalError("URL is not correct!")
        }
        
        ApiCommon().loadTopHeadlines(url: url) { weathers in
            
            if let weathers = weathers {
                self.weathers = weathers.map(MemoViewModel.init)
            }
            
        }
        
    }
}

ViewModelをからデータをバインドするためObservedObjectを使用してオブザーバーを使用できるようにします。 こうすることでデータが変更されると自動的にViewが更新されるようになります。

View

import SwiftUI

struct WeathersView: View {
    @ObservedObject var model = WeathersViewModel()
    
    var body: some View {
        List(model.weathers) { weather in
            Text(weather.main)
        }
    }
}

struct MemoView_Previews: PreviewProvider {
    static var previews: some View {
        MemoView()
    }
}

まとめ

SwiftUIを使うことでこれまでよりも簡単にMVVMの実装をすることが出来ました。 その他のアーキテクチャについても実装をしてみます。

明日はcuresevenさんで、『アドベントカレンダー戦略』です。 お楽しみに!

netdataのメモ

isuconのとき毎回調べるので、netdataのメモを自分用に貼っておきます。

netdataとは

github.com

Netdata is distributed, real-time, performance and health monitoring for systems and applications. It is a highly optimized monitoring agent you install on all your systems and containers.

Netdataはシステムの監視を行うためのアプリケーションです。すべてのシステムのコンテナにインストールすることができます。

Netdata provides unparalleled insights, in real-time, of everything happening on the systems it runs (including web servers, databases, applications), using highly interactive web dashboards. It can run autonomously, without any third party components, or it can be integrated to existing monitoring tool chains (Prometheus, Graphite, OpenTSDB, Kafka, Grafana, etc).

Netdataは、インタラクティブなWebダッシュボードを使用して、実行中のシステムで発生するすべてのリアルタイムで監視することが出来ます。 サードパーティコンポーネントなしで実行され、既存の監視ツール(Prometheus、Graphite、OpenTSDB、Kafka、Grafanaなど)に統合することもできます。

 以下みたいな画面を作れる。 f:id:MikaE:20191217105034p:plain

使い方

ドキュメントを見たほうがいいのでドキュメントを貼ります。

GitHub - netdata/netdata

 導入方法

bash <(curl -Ss https://my-netdata.io/kickstart.sh)
systemctl status netdata.service

1999ポートを開ける http://Host:1999で見ることができる

止める

systemctl stop netdata.service

動かす

systemctl start netdata.service

SwiftUIについて調べたこと

この記事は ウィルゲート Advent Calendar 2019 の17日目の記事です。

最近業務でSwiftを触ることがなくなり少しさみしいのでSwiftUIについて調べたことをまとめていきます。

SwiftUIの登場まで

iOS SDKの登場以降、iOSアプリのViewを開発する場合はAppleが提供しているUIフレームワークのUIKitを使用してきました。このフレームワークを使用することで、簡単にViewを組み立てることができました。 ただUIKitで作られたアプリはViewControllerに処理が集まっていることが多く、FatViewController になることが多くありました。

問題を解消するため、開発者はMVVM,Viper,クリーンアーキテクチャなどの設計を取り入れてアプリを開発してきました。 2019年WWDCで宣言的にViewを組み立てる仕組みとしてのSwiftUIが発表されました。 SwiftUIの登場によりアプリ開発がどう変わるかをまとめていきます。

SwiftUIとUIkitの違い

UIKit SwiftUI
アーキテクチャ イベント駆動 状態駆動
イベント処理 コールバック,デリゲート クロージャーコールバック

SwiftUIとUIKitの大きな違いは、構文が変わったこと以外に、Viewに状態をもたせることができるようになったことです。 アプリ開発では複雑な状態を扱う事が多く、状態どこで管理しどう扱うかに頭を悩ませることが多くありました。 状態を管理する方法として、AppleはCombineをSwiftUIと同時に発表しました。 CombineはViewへ状態をバインドするための仕組みを提供しています。またViewの中で状態を管理することができるようになりました。 SwiftUIとCombineを使用することで状態の管理が簡単になると思います。

WWDCのセッションではユーザーのアクションをViewへ伝えていくためにどうするか説明がされています。 興味がある人は見てみるといいと思います。 f:id:MikaE:20191212123119p:plain

アーキテクチャについて

SwiftUIとCombineを使用することにより画面の状態をViewに持たせることが出来ます。またデータバインドの仕組みを標準でサポートしているため、MVVMアーキテクチャを使用して作成することが簡単になりました。@Publishedや@Stateような属性や@ObservableObjectを使用しViewModelを作ることが出来ます。

まとめ

SwiftUIはまだまだ登場したばかりで資料がすくないため導入は難しいかもしれません。今後も動向を追っていきたいと思います。

明日はokashoiさんで、『PHP + Swoole で論理回路シミュレータを作ってみた(仮)』です。 お楽しみに!

参考資料

developer.apple.com

developer.apple.com

developer.apple.com

developer.apple.com

若手エンジニアで振り返り会をやった

若手エンジニアが集まって振り返り会を行いました。

今後どういったキャリアを描きたいのかやどういった成長をしてきたかをまとめることを目的に行いました。

やったこと

  • 2時間くらい個人でモクモク振り返り

  • 2時間くらいで振り返ったことを共有

雑に発表した人まとめ

覚えてることを雑多に書きます

アッキー (@akki_megane) | Twitter

  • ISUCON優勝

02 (@cocoeyes02) | Twitter

  • 推進力が足らないので自信を持って推進する

しょーぞー (@shozo_ms) | Twitter

  • アウトプット少ないのでアウトプットする

ぴんくもひかん (@pinkumohikan) | Twitter

  • Railsでサービス作ってみる

おかしょい@アーキテクト 兼 技術広報 (@okashoi) | Twitter

  • プライベートが充実

広高@エンジニア兼プレゼン講師 (@yutanpo_it) | Twitter

  • 深く学びたいことを探したい

キュアセブン (@cureseven) | Twitter

  • 強くなりたい

for_3 | ZOE (@for__3) | Twitter

  • 身近な人を救うようなアウトプットをするためにどうするかを考える
  • ISUCON予選突破できなかったらユニセフ

ShuzoN@webエンジニアとヘッドホン (@ShuzoN__) | Twitter

  • 本をめっちゃ読んだ

振り返って

  • 個人的にはインプットを多くできていたと感じている
  • アウトプットが少なかったので今後は少しでも増やしていきたい

iOSで該当のViewControllerが生成されているかを確認する関数を作る

最近暖かくなったり寒くなったりするので体調を崩し気味ですがなんとか気合で乗り越えています。 業務はいい感じなのでいい感じです。

最近iOSを書いていてバックグラウンドで描画している画面を検索したいことがありなんとか実装したのでメモとして残します。

import Foundation
import UIKit

extension UIViewController {
    /**
     * ViewControllerが子や孫に存在する場合はそのViewControllerを返す
     */
    func findChildren<T:UIViewController>(kind:T.Type?) -> T? {
        if let viewControler = self as? T {
            return viewControler
        }
        if let viewControler = self.presentedViewController as? T {
            return viewControler
        }
        if let viewControlers = self.presentedViewController?.children {
            return viewControlers.compactMap{$0.findChildren(kind: kind)}.first
        }
        return nil
    }
}

いい感じにかけた気がするのですが、急いで書いたので抜けてる部分とかありそう。 ご利用は計画的に。

Codableで使える構造体をJsonから自動生成してくれる便利拡張

最近業務でSwiftを書くことが多くなり(ここ6ヶ月はほぼSwift)わからないことだらけで右往左往しています。

業務ではAPIとのやり取りを行うことが多くSwift4から追加されたCodableを使用してJsonの整形を行っています。Codableを利用するときはAPIのレスポンスに合った構造体の定義する必要があり、APIごとに定義していくことが面倒になっていました。

 

そんなときXcodeの便利そうな拡張を見つけました。

github.com

この拡張を使うと、Jsonの構造からCodableで使える構造体を自動的に生成してくれます。

 

f:id:MikaE:20181014175659g:plain

便利そう

導入(メモ)

  1. Alcatrazで入れられそうと思った
  2. f:id:MikaE:20181014182613p:plain
    アーカイブされてた・・・
    読み取ることはできるけどこれって入れていいの?

  3. speakerdeck.coし

    少し調べてみたら良さそうな資料が出てきた。この資料を見たところ一旦.appを生成すれば導入できるよって書いてありました。なのでソースコードを落としてきてArchiveする。
  4. Archiveした結果を「アプリケーション」ディレクトリに入れる。
  5. システム環境設定から拡張機能を開き有効化することで使用できます。

    f:id:MikaE:20181016125830p:plain

  6. 有効化後xcodeを再起動することで機能をしようるることができました。

まとめ

いろいろ調べて便利な拡張機能を使っていきたい。