TalkroomのiOS高速開発を支える開発規約
こんにちは!piconの唯一のエンジニアの渋谷です!
piconでは、現在エンジニア一人の体制で開発を行っています。
事業拡大にむけて開発クオリティ・スピードともに全く足りていないので、 エンジニア(特にiOS, Android)の方を強く募集 してます!
ただそんな体制の中でも、僕が その他の業務で忙殺されていない限り 以下のような比較的ハイペースで開発が実現出来ています。
Talkroom の初期バージョンは約1週間
大型アップデートも1〜2週間程度
今回は、そんなpiconのiOS開発を支える開発規約について紹介したいと思います!
規約をきっちり決めている
前提としてpiconのiOS開発では、規約が比較的きっちり決まっています。
一人でもあえてがっちり決めてます。
規約が決まっていると、「どこにどんな風に書くか」など不要なところで思考をする必要がなくなるので、UIとかであればほぼ無心で開発できるようになりました。
読みやすさもグンと上がるのでとても気に入っています。(3ヶ月後の自分は他人であるのはなんども痛感しました...
ここでいう規約は、改行や記法の規約にとどまらず、レイヤーの分け方、ファイル内での関数の置き方、変数の定義の仕方など、比較的広い意味での規約です。
今回は、汎用性の高そうなUI周りの規約について紹介したいと思います。
※ PCでご覧になることをおすすめします...
UI周りの規約
picon ではストーリーボードを利用していません。ここは賛否両論あると思うので一旦触れずにおきます、、、w
UIViewControllerのクラスには、Viewの見た目とレイアウトに関することを記述します。
Viewだけにとどまらない処理については、ViewModelで処理するようにしています。
UIViewのサブクラスは以下の基準のいずれかを満たす場合にのみにしてます。
処理もしくは構成が複雑である
共通化できるものである
汎用性が高いものである
可読性を損ねるので、自作のUIViewサブクラスが自作のUIViewサブクラスを持たないようにしています。
UIViewControllerクラスのテンプレートは以下です。
import UIKit import RxSwift final class SampleViewController: UIViewController { // MARK: - Views - // 説明メモ:viewはlazyで定義して、プロパティの初期設定はここで行う // 各Viewのプロパティがかたまりとしてひと目で確認できるのが便利 private lazy var sampleView: UIView = { let view = UIView() view.backgroundColor = UIColor.black view.clipsToBounds = true view.layer.cornerRadius = 10 return view }() // MARK: - Properties - private let viewModel: SampleViewModelType private let disposeBag = DisposeBag() // MARK: - Initializer - // 説明メモ:viewModelは外部から注入する init(viewModel: SampleViewModelType) { super.init(nibName: nil, bundle: nil) self.viewModel = viewModel } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK - Life Cycle Events - override func viewDidLoad() { super.viewDidLoad() configure() setViews() setConstraints() } // MARK: - Setup - // 説明メモ:UIViewControllerに関する設定など private func configure() { view.backgroundColor = UIColor.white } // 説明メモ:viewへのaddはこちらで private func setViews() { view.addSubview(sampleView) } // 説明メモ:viewのレイアウトの制約はこちらで private func setConstraints() { sampleView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true } // 説明メモ:viewのイベント処理はこちらで(piconではRxSwiftを利用してます) private func subscribeViews() { let tapGesture = UITapGestureRecognizer() view.addGestureRecognizer(tapGesture) tapGesture.rx.event .subscribe(onNext: { [weak self] () in // 説明メモ: 簡単な処理ではない限り、関数に切り出す self?.createUser() }) .disposed(by: disposeBag) } // 説明メモ: viewModelのイベントはここでsubscribeする private func subscribeViewModel() { } // MARK: - Other - private func createUser() { // Do something. } } // 説明メモ:Protocolに準拠させる場合はextensionを利用して分離させます extension SampleViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // ... } }
ここまで決まっているとどこに何を書くのか迷いなく書けるようになります。
新たな技術を触る時に、ボイラープレート + コード規約が公開されてると便利だなって思ってます。
ぜひ参考にしてみてください!
おまけ
おまけにViewModelのテンプレートも掲載しておきます。こちらはオープンソース化されているkick starterのコードを参考にしています。
参考記事:
Kickstarter-iOSのViewModelの作り方がウマかった
inputとoutputを明示的にわかりやすくなるのでとても気に入ってます。
import RxSwift protocol SampleViewModelInputs { let submitName: PublishSubject<String> { get } } protocol SampleViewModelOutputs { let submitedName: PublishSubject<Void> { get } } protocol SampleViewModelType { var inputs: SampleViewModelInputs { get } var outputs: SampleViewModelOutputs { get } } final class SampleViewModel: SampleViewModelType, SampleViewModelInputs, SampleViewModelOutputs { // MARK: - Properties var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } private let disposeBag = DisposeBag() // MARK: Inputs let submitName = PublishSubject<String>() // MARK: Outputs let submitedName = PublishSubject<Void>() // MARK: - Initializers init() { setBindings() } // MARK: - Binds - private func setBindings() { submitName .subscribe(onNext: { [weak self] (name) in guard let me = self else { return } self?.updateName(name: name) .subscribe(onNext: { [weak self] _ in // 説明メモ:処理 submitedName.on(.next(())) }) .disposed(by: me.disposeBag) }) .disposed(by: disposeBag) } // MARK: - Other - private func updateName(name: String) -> Observable<Void> { // ... } }
---
piconでは、一緒にプロダクトを作っていく エンジニア(特にiOS, Android)を 全力で募集しています。
少しでも興味ある方は、ぜひ気軽にDMください!
まずは週末コミットやハッカソンのみの参加でも歓迎です。
↓ 連絡はこちら