Tabelog Tech Blog

食べログの開発者による技術ブログです

食べログiOSアプリのフルリプレース時の問題の原因と解決案をレガシーソフトウェア改善ガイドで考えてみる

※ 本記事は、過去の事例を元により良い改善案を検討したものになります。現在ではすでに改善されている点なども記載されています。

こんにちは。食べログiOSアプリを担当している saten です。

私は食べログシステム本部 アプリ開発部の基盤チームに所属しています。 基盤チームでは機能開発はあまり行わず、リファクタリングや開発環境(IDEやCI/CDなど)の整備、ライブラリ選定、アーキテクチャ設計など、食べログアプリの下支えをしているチームになります。

今回はTabelog Tech Blogで初の(食べログ系の他のiOSアプリを除く)食べログiOSアプリ本体の話だと思いますので、今も影響を与える2017年にあった食べログiOSアプリでフルリプレース時にあった問題の原因とより良い改善案を

書籍「レガシーソフトウェア改善ガイド」 の 「3.4 決断の時(リファクタか、リライトか)」の章

を元に考えていきたいと思います。

目次

入社した当初(2015年)

入社した当時のフルリプレース前の食べログiOSアプリは以下のような状態でした。

  • 全部Objective-Cで実装
  • ViewControllerが多重の継承関係になっていてわかり辛い状況
  • アーキテクチャもModelがあるぐらいでViewControllerがFatな状態
  • アプリのUIがAPIのIFのEntityを参照
  • 複雑でわかり辛いキャッシュ機構

当時の課題

当時の主な課題としては以下のようなものがありました。

  • 開発速度の向上
    • アプリが複雑化していくとともに、多重の継承関係やFatなViewController、複雑なキャッシュ機構などの悪い設計で、思わぬ不具合などがおこりやすい状況でした。
    • Swiftは既にリリースされているのに、まだObjective-Cで開発している状況だったため、言語的に堅牢な開発がし辛い状態でした
  • 採用の課題
    • 今後、Swiftが主流になることは予測でき、Objective-Cのエンジニアの採用は徐々に難しくなっていくことが予想できました。

2016年、フルリプレースの事業判断

リファクタリング等で徐々に改善するやり方も検討していましたが、開発速度の向上に関しては課題感が強く急務だったため、リスク等も含めて総合的に考えて当時はフルリプレースをする判断となりました。

フルリプレース(2017年)

フルリプレースの際は以下を全て同時に行うことになりました。

  • 同じBundle identifierのアプリで全部作り直す
  • Swiftで全部実装
  • 抽象クラスや抽象メソッド以外は基本的には継承を使用せず、できるだけ別クラスに切り出したりextensionを使用
  • APIも設計し直してレスポンスやペイロードも刷新
  • Viewは全てrefreshメソッドを介してModelの内容表示
  • Clean Architectureを採用(但し、後に紹介する問題があり、ちゃんとClean Architectureになっていなかった) 引用元:The Clean Architecture by Robert C. Martin from The Clean Code Blog, https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

当時の状況

当時の状況は以下のような感じでした。

  • 10ヶ月ぐらいの短期間で本格的に食べログiOSアプリをAPI含め全部作り変えるスケジュールでした
  • 新しい設計に関する有識者があまりいませんでした

良くなったところ

フルリプレースをすることで以下のようなことが改善されました。

  • 抽象クラスや抽象メソッドを除く継承の使用を、基本的には廃止したことで設計がわかりやすくなりました
  • 統一した設計を適用できました
  • Swiftになったことで言語的に堅牢な開発をしやすくなりました

問題が起きたところ

但し、主に下記3つの大きな問題が起きました。

問題1:設計の問題

フルリプレース後の設計には以下のような問題があり、その問題がアプリ全体的に発生しました。それらが原因で、当初の主目的だった開発速度の向上のネックになってしまいました。

Presenterが役割を果たしていない

Presenterはありますが下記の例のようにほぼ実装の無いクラスとなっており、Viewに関するロジックも含めて全てUseCaseに集約してしまったため、Viewに関するロジックが改修し辛くなりました。

import RxSwift
import Domain

protocol ReviewListPresenterDelegate: AnyObject {
  func refresh(model: ReviewListViewControllerModel)
}

final class ReviewListPresenter: PresenterProtocol {
  weak var delegate: ReviewListPresenterDelegate?

  let usecase = ReviewListUseCase()
  let disposeBag = DisposeBag()

  init() {
    usecase.variable.asDriver().drive { [weak self] model in
      self?.inform(model: model)
    }.disposed(by: disposeBag)
  }

  func inform(model: ReviewListViewControllerModel) {
    delegate?.refresh(model: model)
  }
}
常に全体再描画、吹き出しや部分的な表示を切り替えるにも全体再描画

当時はまだSwiftUIが世の中に無い状態だったのでUIKitを使用してフルリプレースをしました。その際にModelの内容を全てrefreshメソッドで全体を毎回描画するようになりました。しかし、SwiftUIと異なり当時のUIKit(DiffableDataSourceやCompositionalLayoutもありませんでした)は差分更新する仕組みが無く、イベントのちょっとしたそのままなら簡単な表示変更でも、refreshメソッドを介して全て再描画しなければ表示を変更できない状態になりました。それによって、TableViewのreloadDataなども行われるため、思わぬ再描画による副作用が起きやすくなりました。

結果的にイベントによるちょっとしたViewの表示変更の際も副作用を意識しなければならなくなりました。

問題2:案件開発を一時停止

当初は案件開発を継続しながらフルリプレースを行う方針でしたが、案件開発を追いながらフルリプレースすることは難しく、予定通り進まず、結局途中で案件開発を止めて案件開発のチームの方も入ってフルリプレースをすることになりました。

これについては予定通り進めれなかったのが悪いと思うかもしれませんが、後に紹介する「レガシーソフトウェア改善ガイド」からフルリプレースにおける見積もりの難しさを紹介します。

問題3:Androidの負債

当初はAndroidも含めてフルリプレースする予定でしたが、Androidの方はもっと予定通り進まず、結局Androidの方のフルリプレースは途中で中断することになってしまいました。iOSはフルリプレースでAPIも刷新していたのでAPIが二重管理になる状態が継続して発生する状態ができてしまいました。

これについても後に「レガシーソフトウェア改善ガイド」からリスクの話をします。

問題が起きた原因

  • 多くの改修を短期間に同時に盛り込み過ぎている
  • 規模の大きいプロジェクトのため失敗するリスクがあり、Androidの方は実際に中断している
  • 短期間で進んだため、設計と実装が振り返られるタイミングなく全体に適用されている
  • 有識者があまりおらず適切なレビューができていない

レガシーソフトウェア改善ガイドを元に考えてみる

やっとここで 書籍「レガシーソフトウェア改善ガイド」 の登場ですが、

「3.4 決断の時(リファクタか、リライトか)」の章

から考えてみます。今回の実施したフルリプレースはビッグリライトに当たると思います。

食べログiOSアプリでリライトは適切だったと思われる要素

著者は、基本的にリファクタリングのインクリメンタルな改善を推奨し、ビックリライトを推奨していませんが、リライトのメリットとして、当時の食べログiOSアプリなら下記のようなことが考えられます。

既存の実装に縛られない

(リライトのメリットの引用1)

自由(過去からの解放)
コードをゼロから書けば、元のコードベースから解放され、「触らぬ神に祟りなし」という感じがなくなる。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.129). Kindle 版. 翔泳社; 第1版 (2016/11/10)

(リライトのメリットの引用2)

いざリライトしてみたら、実際の認証の仕様は、ずいぶん単純だということが判明した。既存のコードに大量の複雑さがあったのは、もう必要のない過去の仕様に関係していたのだが、その事実を発見するにはゼロから書き直す必要があった。つまりレガシーコードを相手にしていると、「木を見て森を見ず」にいることがあるのだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.130). Kindle 版. 翔泳社; 第1版 (2016/11/10)

リライトは既存のコードに縛られることなく、実装することができます。なので無駄に複雑になっているものなどがシンプルになるかもしれません。

複雑な設計

(神クラスの問題の引用)

一般に、ゼロから書くことによって既存のコードからの余計な影響を防ぐことができる。既存のコードのパラダイム(理論的枠組)の中でコードを書いていると、その周囲にあるコードの設計と実装から、良くも悪くも制約を受けるのが自然なことだ。
私が昔扱ったレガシーJavaアプリケーションは、なんでもこなせる「神クラス」を酷使していた。そいつは3千行もある化け物で、staticなユーティリティメソッドが、ぎっしり詰め込まれていた。この アプリケーションに新しいコードを追加するときは、そのクラスを使わずに済ますのが、ほとんど不可能だった(参照するたびに涙が出たけれど)。それどころか、何でも「神クラス」に追加してしまえ、と思わせる誘惑もあった。既存の設計では、他の方法でコーディングすることが、ほとんど不可能になっていたのだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.130). Kindle 版. 翔泳社; 第1版 (2016/11/10)

多重の継承関係やFatなViewController、複雑なキャッシュ機構などのある状態だったので、既存の設計から変えるのは大変だったと思います。

食べログiOSアプリでビッグリライトが不適切だったと思われる要素

次に食べログiOSアプリでビッグリライトが不適切だったと思われる要素について考えてみましょう。 主に以下のような要素が考えれます。

  • リスク
    • 見積もりを超過しやすい
    • リグレッションが発生しやすい
    • 長期でコストが二重になりやすい
  • リライトに対するリファクタリングのメリット

リスク

著者はリライトへの反論としてまずは、リスクの大きさについて述べています。

(リライトのリスクの引用1)

リスク
レガシープロジェクトの書き換えは、大規模なソフトウェア開発プロジェクトだ。元のシステムのサイズによって、その完成には何か月も、あるいは何年もかかるかも知れない。このようなスケールの開発プロジェクトは、必ず、かなりのリスクを伴う。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.121). Kindle 版. 翔泳社; 第1版 (2016/11/10)

今回のビッグリライトでも大きなリスクが生じ、実際に問題になりました。

具体的には以下のようなリスクがあります。

見積もりを超過しやすい

著者はリライトにおける見積もりの難しさを以下のように述べています。

(リライトの見積もりの難しさの引用1)

オーバーヘッド
技術者は、ソフトウェアプロジェクトを新規にゼロからセットアップするときのオーバーヘッドを、過少に見積もりやすい。すでに軌道に乗ったプロジェクトで仕事をしているときは、オーバーヘッドの多さを本当に認識することがないからだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.124). Kindle 版. 翔泳社; 第1版 (2016/11/10)

(リライトの見積もりの難しさの引用2)

いつも予想より時間がかかる
前述したオーバーヘッドを念頭に置き、必要な仕事の量を甘く見積もりがちな開発者の傾向を計算に入れても、やはり書き直しは、必ず見積もりを超過する。ソフトウェアプロジェクトのサイズを見積もるのが難しいことは周知の事実であり、プロジェクトが大きければ大きいほど難しくなる。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.126). Kindle 版. 翔泳社; 第1版 (2016/11/10)

(リライトの見積もりの難しさの引用3)

リライトは普通、長期にわたるプロジェクトであり、しかも見積もりを超過しやすいのだから、代替品を開発している間に元のソフトウェアに対して発生する変更に対処できるように計画する必要がある。次に3つの選択肢を示すが、どれも理想的ではない。
•元のソフトウェアの開発を、書き直しの期間は完全に凍結する。
 これではユーザーが不幸になりそうだ。
•開発の継続を許し、絶え間ない仕様の変更に、できるだけ努力して追いつく。
 これは「動く標的」を追いかけるのだから、リライトのプロジェクトが、ひどく遅くなってしまう可能性がある。
•開発の継続を許すが、リライトには、どの変更も実装しないでおく。
 つまりリライトはプロジェクトを始めたときの仕様書(スナップショット)を元に実装するだけにして、追加で実装すべき変更のすべてを、ただ追跡管理しておく。リライトが完成しようとするとき、元のソフトウェアの開発を凍結し、それまでに溜まった変更のバックログを新しいバージョンに移植する。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.127). Kindle 版. 翔泳社; 第1版 (2016/11/10)

実際に今回も、プロジェクトは予定通り進まず、当初は案件の開発を継続しながらやる予定でしたが、案件開発の方を止める方針で途中に変更になってしまっています。

大きなプロジェクトを見積もる難しさについて、「レガシーソフトウェア改善ガイド」では以下のように述べています。

(リライトの見積もりの難しさの引用4)

もし私が標準的なA5サイズのノートパッドをあなたに見せて、この画面はiPhoneよりどのくらい大きいですかと訊いたら、たぶんあなたは憶測でも、かなり確信を持って答えることができるだろう(私なら、A5のノートパッドはiPhoneの3倍か4倍だと言うだろう)。では次に、同じ実験を、こんどはノートパッドの代わりに映画館のスクリーンを使って繰り返そう。映画館のスクリーンは、iPhoneの何倍だろうか。千倍か。1万倍か。私には見当も付かない!

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.126). Kindle 版. 翔泳社; 第1版 (2016/11/10)

リグレッションが発生しやすい

別のリスクとして以下のようにリグレッションの発生しやすさがあります。

(リライトのリグレッションの引用1)

既存のシステムの書き換えには、独自のリスクがある。それはリグレッションのリスクだ。既存のソフトウェアには、そのシステムのすべての仕様が(ビジネスのルール全部を含めて)プログラムのソースコードにエンコードされている。これらのビジネスルールをひとつ残らず見つけて、それらを忠実に新しいシステムに移植できると保証できなければ、そのシステムの振る舞いは、書き換えの結果として変わってしまうだろう。このような振る舞いの変更が、エンドユーザーにさえ明らかになったら、対処が必要なリグレッションが生じている。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.122). Kindle 版. 翔泳社; 第1版 (2016/11/10)

リライトのメリットとして既存の実装に縛られることがないことを記載しましたが、逆にリライトは常にリグレッションが発生するリスクが付き纏います。

また、挙動としてのリグレッションをなんとかできたとしても、下記のように新しく考えた設計が必ずしも問題が無いとは限らないのです。

(リライトで新しく考えた設計が問題が無いとは限らない引用1)

プロジェクトの途中で、そのアーキテクチャが基本的に運用不可能であることが判明し、それまでに書いたコードすべてを捨てなければならなくなるかも知れない。
もっと悪いことに、そのようなアーキテクチャの弱点を、ソフトウェアをユーザーにリリースするまで見つけることができず、負荷をかけてようやく、まったく不安定だとわかるかも知れない。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.121). Kindle 版. 翔泳社; 第1版 (2016/11/10)

(リライトで新しく考えた設計が問題が無いとは限らない引用2)

いくつか機能を実装してみたら、あなたのモデルが、案外使えないことに気がついた。あまりにも抽象的であり、大量のボイラープレートを必要とするのだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.129). Kindle 版. 翔泳社; 第1版 (2016/11/10)

今回は、設計面に問題がありましたが、設計を振りかえるタイミングが無かったため、そのまま全体に問題のある設計が適用されてしまいました。

長期でコストが二重になりやすい

また、ビッグリライトをすると長期で二重にコストが掛かるリスクがあります。

(リライトの二重コストの引用)

新しいサービスの運用コストは、プロジェクトの始動時に1回だけ支払うのではなく、ずっと継続することも忘れてはいけない。長い間(少なくとも古いシステムを完全に停止するまで)保守し、監視し、順調に実行させなければならないシステムが、1つ増えてしまうのだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.125). Kindle 版. 翔泳社; 第1版 (2016/11/10)

リライトは二重のコストを発生させますが、ビッグリライトとなると古いシステムを完全停止するまで二重のコストが掛かり続けます。

しかも、今回はiOSのフルリプレースでAPIを一気に刷新しましたが、Androidの方のプロジェクトは中断したことで、APIを継続して二重で管理するというコストが発生してしまいました。

リライトに対するリファクタリングのメリット

著者はリライトに対してリファクタリングのメリットについて以下のように述べています。

(リライトに対するリファクタリングのメリットの引用1)

既存のコードベースに変更を加えるのなら、ずっとリスクが小さい。既存のシステムは、たぶん製品として何年も稼働しているだろうから、かなり信頼できる基礎であることが自明であり、それを改良することになるからだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.122). Kindle 版. 翔泳社; 第1版 (2016/11/10)

(リライトに対するリファクタリングのメリットの引用2)

たとえリファクタリングが見積もりを超過して、途中で開発を止めると判断しても、おそらくコードベースには何らかの有益な改善が行われているだろう。完全な書き直しは、完了するまで何の価値もないのだから、いったん始めたら、たとえ予定を超過しても最後まで苦労を続けなければいけない。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.128). Kindle 版. 翔泳社; 第1版 (2016/11/10)

事業を上手く進めるためにも、ビッグリライトは大きなリスクとなります。既存のコードベースに変更を加え、インクリメンタルに進めた方が事業を進める上でもメリットがあるケースが多いです。

上記のリライトの条件としては下記のようなことも記載されています。

(リライトの条件の引用)

リファクタリングを試みたが失敗した
リライトを試みる前に、必ず第1の選択肢としてリファクタリングを試みよう。ある種のレガシーコードベースは、他のものよりリファクタしやすいが、どれほどの成功をリファクタリングが収めるかを、あらかじめ知ることは困難である。最良の方法は、コードに飛び込んで、やってみることだ。いったんリファクタリングに、ある程度の時間と労力を注ぎ込んでみたけれど、品質に顕著な改善が得られないというときに限り、完全なリライトを考慮し始めるべきである。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.132). Kindle 版. 翔泳社; 第1版 (2016/11/10)

当時は本格的な目にみえるリファクタリングを試みていなかったと思います。リファクタリングを試みてからリライトを検討しても良かったと思います。

(まずリファクタリングすることのメリットの引用)

たとえ最終的にリライトを選ぶとしても、やはり最初にリファクタリングを試みる価値がある。それはコードベースを学習する素晴らしい方法であり、代替システムを、どのように設計し実装するのが最良かについて、貴重な洞察が得られるだろう。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.132). Kindle 版. 翔泳社; 第1版 (2016/11/10)

また、最終的にリライトを選ぶとしても、無駄になる訳ではなく、コードベースを学習する貴重な機会になることも記載されています。コードベースを理解することで、リライトすることになっても役に立ちます。

ミニリライトについて

著者はリファクタリングが難しく、リライトせざるを得ない場合、ビッグリライトの代わりにミニリライトという手段も提案しています。

(ミニリライトに関する引用1)

アプリケーションの少なくとも一部は本当に書き直したいけれど、完全なリライトではリスクが大きすぎるし、それではプロジェクトの最後にビッグバンが来るまでビジネスにメリットを提供できないから、思い切って踏み切れないという場合がある。そんなときは、リライトをインクリメンタルに実行できないか、検討してみる価値がある。 その基本的なアイデアは、リライトを数多くの小さな段階に分割することだが、次の2つに重点を置くことが大切だ。
・それぞれの段階で、ビジネスの価値を提供すること。
・どの段階の後でもプロジェクトを停止することが可能であり、その場合でも何らかのメリットが得られること。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.133). Kindle 版. 翔泳社; 第1版 (2016/11/10)

(ミニリライトに関する引用2)

「1か月で終わるミニリライト」になれば、リスクが低く、管理も容易である。それぞれの段階が終了したら、リリースを行って、組織に価値を提供できる。それに開発者も、新しいコードが素早くできて嬉しいのだ。

引用元:クリス・バーチャル. レガシーソフトウェア改善ガイド (Japanese Edition) (p.134). Kindle 版. 翔泳社; 第1版 (2016/11/10)

ミニリライトで進めれば途中で設計ミスにも気づけたかもしれませんし、大きなリスクを取って全体の更新を短期間で進める必要もなかったかもしれません。

当時の問題に対する解決案

難しい問題なので答えは簡単ではないでしょうが、下記のような解決案が考えられます。

解決案1:先行してSwiftを全体的に適用する

悪い設計をリファクタリングやリライトで撲滅するのと比べるとObjective-CをSwift化する方が難度は低いです。 Swiftの恩恵を早く受けたければ、設計をそのままに全体をSwift化してからリファクタリングやリライトを試みていっても良いと思います。

そうすれば、大きなリスクを負うことなく、課題の1つである採用の面の解消やSwiftの堅牢な実装もしやすくなる状態を、早くリリースもできるため、安定して事業としてもプラスになります。

解決案2:リファクタリングやミニリライトを検討する

上記でも記載したように、本格的にまずはリファクタリングをやってみることを進めても良かったと思います。 多重の継承関係や本格的なAPIのリファクタリング、複雑なキャッシュ機構でやはりリライトが必要だった場合でも、ミニリライトを検討しても良かったと思います。

リファクタリングやミニリライトする際は、ビッグリライトするよりも長期で時間が掛かる可能性はあったり、どこからリファクタリングやミニリライトをどのくらいするなどの検討事項は多くなりますが、一気に大きなリスクを負ったりせず、途中でやり方を見直したり、途中まででも成果を反映してくことができます。案件開発が止まる可能性も減らせて、インクリメンタルに改善できるため、確実に事業としてもプラスになりやすかったと思います。

解決案3:ビッグリライトをするにも設計の振り返りのタイミングを設ける

上記が無理でビッグリライトになった場合は、有識者がいれば設計をレビューしてもらったり、有識者がいなかったとしても、設計を部分的に適用して検証やフィードバックをもらうなど設計を振り返るタイミングを設けていれば、設計ミスを全体に適用することを防げた可能性があると思います。

そうすれば、時間が掛かっても適切な設計が反映され生じる負債は減って、結果として事業にはプラスになった可能性があります。

まとめ

開発速度の向上を急速に求められたとしても、まずはインクリメンタルに変更していくことができないかをしっかり検討した方が良いと思います。そうしないとかえって事業に悪影響を与える可能性があり、開発速度を速くするためなのにかえって負債を抱えることになる可能性があります。

ビッグリライトをしないためには、日頃からインクリメンタルな改善をしていくことが大事です。インクリメンタルな改善ができなければ、結局最終的により大きな負債となって返ってくる可能性があるためです。

今後について

今後は、以下のようなインクリメンタルな改善を行っていく予定です。

フルリプレース時に生じた設計の問題のリファクタリング

フルリプレース時に生じた設計の問題について、既にある程度それぞれ以下のように直していますが今後も修正していく予定です。

Presenterが役割を果たしていない

UseCaseにはビジネスロジックを、PresenterにはView関するロジックを置くように分け、UseCaseのModelでなくPresenterにちゃんとViewのためのViewModelを設けるように修正

常に全体再描画、吹き出しや部分的な表示を切り替えるにも全体再描画

全てrefreshメソッド1つでViewを更新するのではなく、イベント毎にPresenterからViewにコールバックを呼んで部分的に描画を変更するように修正

テスタブルな環境を整える

インクリメンタルに改善していく上で、品質を安定してリファクタリングなどの改善ができるように自動テストの環境を整えることが重要です。

今まで、ユニットテストはほぼ実装されていませんでしたが、今後はテスタブルな設計・環境に改善し、ユニットテストも追加していく予定です。

フローの整理や自動化、環境の改善

インクリメンタルに改善していく上で、スマホアプリの設計だけでなく、素早くリリースして世の中のフィードバックを受けるサイクルを速くすることも重要です。

そのためにも、フローの整理や自動化など、定常的な作業を簡略化したりなどの、より働きやすく環境を改善しフィードバックサイクルを速くすることもとても重要です。

終わりに

一緒に食べログスマホアプリをインクリメンタルに改善したいという方はぜひ気軽にお声がけください! カジュアル面談も大歓迎ですので、ご希望の方はフリーテキストに、「カジュアル面談希望」と記載ください。