SlideShare une entreprise Scribd logo
1  sur  28
Télécharger pour lire hors ligne
既存プロジェクトで使っていたDIを

お引っ越し&DIYすることになった
potatotips	#76	@	オンライン
2021/11/17
Fumiya	Sakai
自己紹介
・Fumiya	Sakai
・Freelance	App	Engineer
アカウント:
・Twitter:	https://twitter.com/fumiyasac

・Facebook:	https://www.facebook.com/fumiya.sakai.37

・Github:	https://github.com/fumiyasac	

・Qiita:	https://qiita.com/fumiyasac@github
発表者:
・Born	on	September	21,	1984
これまでの歩み:
Web	Designer
2008	~	2010
Web	Engineer
2012	~	2016
App	Engineer
2017	~	Now
iOS	/	Android	/	sometimes	Flutter
iOSのUI実装本を執筆しています!
少しの工夫で実現できるTIPS集 ライブラリ表現の活用集
書籍に掲載したサンプルのバージョンアップや続編等に現在着手中です。
過去に技術書典8で電子版だけ頒布した書籍紹介
Vol.1及びVol.2に頒布したものの中で書籍に載せきれなかったものを紹介
第1章:	メディアアプリ型のUI	
第2章:	構造が複雑な写真表示UI
記事一覧を無限スクロールする様な形のアプリ
UIを一覧/詳細表示を簡素化した実装を紹介。
現在はBoothにて販売中です! https://booth.pm/ja/items/1835468
¥1,000	-	
iOSアプリ開発「UI実装であると嬉しいレシピブック	まかない編」
サンプルコード:	https://github.com/fumiyasac/meals_ios_ui_recipe_showcase
第3章:	Combine	+	UICollectionViewCompositionalLayout
タイル状のフォトギャラリーや一覧表示型のア
プリUIでライブラリを活用した実装を紹介。
実務でも利用&考察したもの
特に第1章と第2章の内容に関し
ては、実際に相談されたり、実
装アイデアとして活用する機会
があったものになります。
	全てUIKitを利用
新たに技術書典9で電子版だけ頒布した書籍紹介
表現や動きが特徴的でユーザーにもほんの少し遊び心を与える様なUI実装を紹介
現在はBoothにて販売中です! https://booth.pm/ja/items/2360379
¥1,000	-	
iOSアプリ開発「UI実装であると嬉しいレシピブック	おもしろ編」
サンプルコード:	https://github.com/fumiyasac/meals_2nd_ios_ui_recipe_showcase
実務導入前の検証段階
若干一癖がありそう、ぱっと見
だと実装の方針が立ちにくい感
じに見受けられそうなUI実装や
構造に関して考察しました。
	UIKit	&	SwiftUIを利用
第1章:	面白い表現のフォトギャラリーUI	
第2章:	画面ロック機能を利用したUI
UICollectionViewを活用したユニークなレイア
ウト表現と画面遷移カスタマイズ実装を紹介。
第3章:	SwiftUI	+	OSS	Libraryの活用
SceneDelegateの機能や端末認証を利用した画
面ロック機能を盛り込んだ実装を紹介。
インプレスR&D様より発刊されました✨
UI実装であると嬉しいレシピブックの最新情報
UI実装であると嬉しいレシピブックVol.3として今年10月に商業化しました!
少し複雑で特徴的なUI実装のTIPS集
今後ともUI実装に関する新たな探究や最新のトピック等
にも積極的にキャッチアップしていく所存でおります。
現在は、

・Amazon	Kindleストア

・達人出版会

・紀伊国屋書店

・Apple	Books

・Google	Play

等で電子版を購入できます!
※	物理本も一部ストアで購
入する事ができます。
今回の発表でお話すること
業務の中でDependency	Injectionをする部分を自作する機会があった
本発表ではUI実装とは少し違ったトピックですが実務の中で活用できたものになります。
1.	DI部分を自前で作る決断と前提となる構成の紹介:
現在のチーム内で色々と検証や議論を重ねた結果自前でこの部分を準備する運びとなった。また、以前に自分でも簡単なサンプ
ルを試したこともあるが、施策が進む中で既存のコードとの上手な共存をしながら進めていく事が求められた。
2.	良いとこどりができるか?のヒントを探る:
現在のチーム内ではアプリエンジニアがiOS/Androidを両方実装する機会もあるので、できれば定番ライブラリや知名度のあるラ
イブラリの利用経験した事がある方であればキャッチアップしやすい形でシンプルにしたいという要望はありそうだった。
3.	実際に運用しているコードから見るポイントや所感など:
自作すると言えどもライブラリの中で利用されている実装方針や考え方には素晴らしいものが沢山あるのは事実なので、既存の
実装方針を崩すことなく進める方針や取り組みの中で思った事をお伝えできればと思います。
(1)	DI部分を自前で作る決断と前提となる構成の紹介
以前に個人的に取り組んだ事例に関する紹介
Property	Wrapperを利用したDependency	Injectionをするアイデアを思いつく
1年前に書いた記事:	https://bit.ly/3nkwW8b
記事の内容を取り入れたサンプル実装:	https://github.com/fumiyasac/VisualEffectTraceExample
外部APIリクエストを利用して表示データ情報を取得する場合
Infra	/	Repository	/	UseCase	/	ViewModelに分離して考えていく
APIRequestManager
▲▲▲▲UseCase
▲▲▲▲ViewModel
▲▲▲▲Repository
ということは、このクラスのインスタンスがないと
左に記載したクラスの処理は利用できない
左に記載したクラスが依存しているクラス
▲▲▲▲ViewController
▲▲▲▲UseCase
▲▲▲▲ViewModel
▲▲▲▲Repository
①	Domain層
②	UseCase層
④	UI層
③	ViewModel層
APIリクエスト&データ取得
ロジックとViewModel仲介
画面取得データの作成
画面表示に関する処理
実際のクラス
各クラスを初期化する際には依存するクラスのインス
タンスを引き渡す形にしなければいけない
補足事項
この処理では各クラスのinitialize
時に依存するクラスのインスタンス
を渡すコンストラクタ・インジェク
ションを想定
この例ではまだ1つのクラスへの依
存しかない形ではあるが、実際は
多くのクラスへ依存する形になる
場合もあります。
Dependency	Injectionを実行する処理の方針
Swift5.1〜利用可能なPropertyWrappersを利用する形で考えてみる
Dependency	Injection	実行側
名前をキーにして呼び出す
名前が一致しないとクラッシュする
container.register(

				RealmAccessManager.shared,

				for:	Dependencies.Name(rawValue:	Dependencies.Name(rawValue:	"RealmAccessProtocol"))

)
let	container	=	Dependencies.Container.default
@Dependencies.Inject(Dependencies.Name(rawValue:	"APIRequestProtocol"))	

				private	var	apiRequestManager:	APIRequestProtocol
@Dependencies.Inject(Dependencies.Name(rawValue:	“RealmAccessProtocol”))

				private	var	realmAccessManager:	RealmAccessProtocol
Dependency	Injection	定義側
container.register(

				APIRequestManager.shared,

				for:	Dependencies.Name(rawValue:	Dependencies.Name(rawValue:	"APIRequestProtocol"))

)
Containerにインスタンスを登録
名前と一緒にContainerへ登録
レイヤー化して責務を分けた部分の実装例
Domain層やUseCase層での実装例(API	Request	with	RxSwiftの場合)
import	RxSwift

//	MARK:	-	Protocol

protocol	ItemUseCase	{

			func	execute(page:	Int)	->	Single<ItemAPIResponse>

}

final	class	RequestItemDataUseCase:	ItemUseCase	{

				//	MARK:	-	Properties

				@Dependencies.Inject(Dependencies.Name(rawValue:	"ItemRepository"))	private	var	itemRepository:	ItemRepository

				//	MARK:	-	EventIntroductionUseCase

				func	execute(page:	Int)	->	Single<ItemAPIResponse>	{

								itemRepository.requestItemDataList(page:	page)

				}

}
コードの抜粋 API経由でItem一覧を取得するUseCase層
Property	Wrapperを利用したインスタンス化
Protocol定義
※	UnitTestなどの際にMock化したものを適用する想定
Single	/	Maybe	/Completableを利用して処理を結合
※	APIリクエスト処理を連携する形にする
参考:	https://qiita.com/monoqlo/items/7bcec98432389b3b8909
実際の開発で適用できるかを吟味していく
MVP(Model-View-Presenter)	+	Layered	Architecture(with	DDD)
今回想定しているApp内部のアーキテクチャ概要	(UIKit	&	RxSwiftを利用する想定)
UI UseCase Domain InfraStructure
View	(ViewController)
Presenter
Contract
View-Model-Presenter

※	ViewObject
プレゼンテーション ビジネスロジック ドメインロジック
DomainModel	(Entity)
Repository
DomainService
Api	/	GraphQL	Client
LocalStore
外部技術
ロジック部分はiOS/Android間で実装や機能設計で比較できる様に設計思想を統一している
※	基本的には疎結合な構造&責務の明確化はしている(UnitTestは導入している)形となっています。
RestfulAPI	/	GraphQL

UserDefault	/	Realm
※	UnitTestはPresenter/UseCase/Damain/InfrastructureはQuick・Nimbleを利用	&	MockはSwiftyMockyでの自動生成の方針です。
実際のプロジェクトでも軽く検証をしてみたその後
この方法とは別の方法を改めて探してみることを決断することにしました
それなりの規模感があるのでここは「心臓部分」。なので流れを止めず短期決着でカタをつけたいと思った。
1.	必要最低限の変更で済むか?という観点:
この方法だと名前をキーにして呼び出す管理方法ではあったので、よくよく考えてみると冗長&変更ファイル数が結構出てしま
う点や既存のUnitTestに沿うかという点では、自分でも検証を進めていく中で懸念を感じた。
2.	メンバーの中で馴染みがある書き方か?という観点:
iOSではSwinject/DIKit,	AndroidではDagger2/DaggerHiltといった定番ライブラリや知名度のあるライブラリの利用経験があり
その書き方や考え方からは少し外れてしまいそうな気がした。
新機能開発や改善対応もあったのでその部分と両立したかった。
自分たちで仕様を把握しておきたい思いもあった。
ライブラリに依存しない形ではあるけれども

できるだけ似た感覚で書ける形を模索することに
(2)	良いとこどりができるか?のヒントを探る
DIに関する解説資料からも理解を深める
自分もこの様なタスクは初めて&影響範囲が全体なので準備を念入りにする
ライブラリを利用した際の知見や他社様の開発事例に触れることでイメージがしやすくなった。
仕組みを改めて復習&参考事例に触れるのも大切:
資料:	https://bit.ly/2YShmHx 資料:	https://bit.ly/3oxNsRT
馴染みのあるライブラリの実装からヒントを得る
iOS/Android両方のライブラリの仕様・実装例・ドキュメントを参考にする
DI部分をライブラリに頼らない決断をしたとはいえ良さそうな部分はできるだけ取り入れたい。
1.	iOSでのDIライブラリ例:
Swinject:

https://github.com/Swinject/Swinject
2.	AndroidでのDIライブラリ例:
Dagger2	&	Dagger	Hilt:

https://developer.android.com/training/dependency-injection/dagger-basics?hl=ja

https://developer.android.com/training/dependency-injection/hilt-android?hl=ja
実務で経験があったのはSwinject・Dagger2、個人的に軽く試してみたのはDITranquillity・Dagger	Hit
DITranquillity:

https://github.com/ivlevAstef/DITranquillity
needle:

https://github.com/uber/needle
なぜ両OSを試してみたか?
自分自身もiOS開発と並行して
Android開発をしていたため。
DIコンテナを自前で作成する上で今回元にした資料
自前でDIコンテナを作成する事例や紹介記事から良さそうに感じたもの
How	to:	create	your	SUPER	simple	dependency	injector	container	in	Swift	(自前でのシンプルなDIコンテナの作成)
https://www.fabrizioduroni.it/2020/04/19/dependecy-injection-swift/
1.	実態は大きなシングルトンの中にインスタンスを格納する仕様:
このプロジェクトで一番大事な部分については、

(1)	コンストラクタインジェクションができること

(2)	Local	/	Remoteで同じProtocolを使う際も管理できること

の2点だったのでこの方針でもひとまず大きな問題はなさそうだった。
2.	依存関係の書き方が意外と直感的で馴染むと感じた:
DIライブラリ「Swinject	/	DITranquillity」にもイメージが似ていたの
で、DIライブラリに触れた経験があれば慣れるのではないかと思えた。
個人的に「良さそう」と思えた部分は下記の2点になります
DIコンテナの元となる部分のコード例
Protocol・実装クラスを1セットで登録し必要があれば名前で分類する形
final	class	DependeciesContainer	{

				//	MARK:	-	DIコンテナ自体はSingletonとして保持する

				static	let	shared	=	DependeciesContainer()

				private	init()	{}

				private	var	dependecies:	[DependencyKey:	Any]	=	[:]

				//	MARK:	-	Function

				func	register<T>(_	type:	T.Type,	impl:	Any,	name:	String?	=	nil)	{

								let	dependencyKey	=	DependencyKey(type:	type,	name:	name)

								dependecies[dependencyKey]	=	impl

				}

				func	resolve<T>(_	type:	T.Type,	name:	String?	=	nil)	->	T	{

								let	dependencyKey	=	DependencyKey(type:	type,	name:	name)

								if	let	dep	=	dependecies[dependencyKey]	as?	T	{

												return	dep

								}	else	{

												let	protocolTypeName	=	NSString(string:	"(type)").components(separatedBy:	".").last!

												fatalError("(protocolTypeName)の依存性を解決できませんでした:(protocolTypeName).")

								}

				}

}
final	class	DependencyKey:	Hashable,	Equatable	{

				//	MARK:	-	Properties

				private	let	type:	Any.Type

				private	let	name:	String?

				//	MARK:	-	Initializer

				init(type:	Any.Type,	name:	String?	=	nil)	{

								self.type	=	type

								self.name	=	name

				}

				//	MARK:	-	Hashable,	Equatable

				func	hash(into	hasher:	inout	Hasher)	{

								hasher.combine(ObjectIdentifier(type))

								hasher.combine(name)

				}

				static	func	==	(lhs:	DependencyKey,	rhs:	DependencyKey)

	->	Bool	{

								return	lhs.type	==	rhs.type	&&	lhs.name	==	rhs.name

				}

}
型と名前で分類
v
追加し忘れがあった場合にはfatalErrorでわかるようにする
//	MEMO:	Infra/Repository/UseCaseについてはDIコンテナに登録する

final	class	DependenciesDefinition	{

				//	MARK:	-	Function

				func	inject()	{

								//	MEMO:	インスタンスを保持するための場所

								let	dependecies	=	DependeciesContainer.shared

								//	※途中省略

								//	MARK:	-	Infra

								dependecies.register(

												MovieQualityLocalStore.self,

												impl:	MovieQualityLocalStoreImpl()

								)
DIコンテナの元となる部分のコード例
各種Layerにおける依存関係の解決を図る部分の書き方はこの様な形
								//	MARK:	-	Repository

								dependecies.register(

												FeaturedMovieRepository.self,

												impl:	FeaturedMovieRepositoryImpl(

																apiClient:	dependecies.resolve(ApiClient.self),

																backgroundScheduler:	dependecies.resolve(ImmediateSchedulerType.self,	name:	background)

												)

								)

								//	MARK:	-	UseCase

								dependecies.register(

												GetMainUseCase.self,

												impl:	GetMainUseCaseImpl(

																mainBannerRepository:	dependecies.resolve(MainBannerRepository.self),

																mainNewsRepository:	dependecies.resolve(MainNewsRepository.self),

																featuredMovieRepository:	dependecies.resolve(FeaturedMovieRepository.self),

																mainMovieRepository:	dependecies.resolve(MainMovieRepository.self)

												)

								)

				}

}
Domain	Logic
LocalDB	/	API
Business	Logic
//	MEMO:	DIコンテナの適用

DependenciesDefinition().inject()
AppDelegate.swiftに記載
(3)	実際に運用しているコードから見るポイントや所感など
DIコンテナの中で実行する処理のコード例(1)
名前と型による管理をすることで適切な処理を選択する事例(1)
処理レイヤーによって利用するスレッドを適切に指定するために第2引数を活用:
let	background	=	"background"
dependecies.register(

				ImmediateSchedulerType.self,

				impl:	MainScheduler.instance

)

dependecies.register(

				ImmediateSchedulerType.self,

				impl:	SerialDispatchQueueScheduler(qos:	.default),

				name:	background

)
CategoryCoursesPresenterImpl(

				getCategoryCoursesUseCase:	dependecies.resolve(GetCategoryCoursesUseCase.self),

				stockCourseUseCase:	dependecies.resolve(StockCourseUseCase.self),

				unstockCourseUseCase:	dependecies.resolve(UnstockCourseUseCase.self),

				mainScheduler:	dependecies.resolve(ImmediateSchedulerType.self)

)
dependecies.register(

				CategoryRepository.self,

				impl:	CategoryRepositoryImpl(

								graphQLClient:	dependecies.resolve(GraphQLClient.self),

								readApiCacheClient:	dependecies.resolve(ReadApiCacheClient.self),

								backgroundScheduler:	dependecies.resolve(ImmediateSchedulerType.self,	name:	background)

				)

)
subscribe(on:	backgroundScheduler)
Repository API	/	GraphQLでの処理なのでサブスレッドで実行
Presenter UIへの取得データ反映処理なのでメインスレッドで実行
observe(on:	mainScheduler)
処理内ではこの様に利用する
サブスレッドで処理をする場合は下記を付与
メインスレッドで処理をする場合は下記を付与
DIコンテナの中で実行する処理のコード例(2)
名前と型による管理をすることで適切な処理を選択する事例(2)
Cacheを利用するか?サーバーとの通信を利用するか適切に指定するために第2引数を活用:
let	local	=	"local"
dependecies.register(

				CourseRepository.self,

				impl:	CourseRepositoryImpl(

								graphQLClient:	dependecies.resolve(GraphQLClient.self),

								readApiCacheClient:	dependecies.resolve(ReadApiCacheClient.self),

								courseMemoryCache:	dependecies.resolve(CourseMemoryCache.self),

								backgroundScheduler:	dependecies.resolve(ImmediateSchedulerType.self,	name:	background)

				)

)
dependecies.register(

				CourseRepository.self,

				impl:	LocalCourseRepositoryImpl(

								readApiCacheClient:	dependecies.resolve(ReadApiCacheClient.self),

								courseMemoryCache:	dependecies.resolve(CourseMemoryCache.self),

								backgroundScheduler:	dependecies.resolve(ImmediateSchedulerType.self,	name:	background)

				),

				name:	local

)
サーバーとの通信
Cacheを利用する
localGetCategoryCoursesUseCase:	

		dependecies.resolve(

				GetCategoryCoursesUseCase.self,	name:	local

		)
getCategoryCoursesUseCase:

		dependecies.resolve(

				GetCategoryCoursesUseCase.self

		)
とあるPresenterでの処理例
①	まずはCacheからのデータを反映する
②	次にサーバーからのデータを反映する
同じ名前のUseCaseでもデータ取得先が違う
Presenter部分はDIコンテナに登録しない
DIコンテナの中で実行する処理のコード例(3)
PresenterとViewController部分に関する処理
ここだけは例外的にFactoryメソッドを作って反映する形を取る:
static	func	createFindPresenter()	->	FindPresenter	{

				return	FindPresenterImpl(

								getFindUseCase:	dependecies.resolve(GetFindUseCase.self),

								localGetFindUseCase:	dependecies.resolve(GetFindUseCase.self,	name:	local),

								stockCourseUseCase:	dependecies.resolve(StockCourseUseCase.self),

								unstockCourseUseCase:	dependecies.resolve(UnstockCourseUseCase.self),

								getCommunityEventUseCase:	dependecies.resolve(GetCommunityEventUseCase.self),

								mainScheduler:	dependecies.resolve(ImmediateSchedulerType.self)

				)

}
private	var	presenter:	FindPresenter!
//	MEMO:	ViewDidLoad内部

presenter	=	PresenterFactory.createFindPresenter()
画面生成時にこのメソッドを適用する
※注意※
let	findViewController	=	UIStoryboard(name:	"Find",	bundle:	nil).instantiateInitialViewController	{	coder	in

				FindViewController(

								coder:	coder,

								presenter:	PresenterFactory.createFindPresneter()

				)

}
※	iOS13からはStoryboardのDependency	Injectionが利用できるのでこれを利用しても良さそうです。
実際にお引っ越し期間はどの様なスケジュールだった?
実は書き換える部分は既存DIコンテナとPresenterの一部だけで済みました
移行作業&切り替え作業方針とfeature開発との歩調を合わせ:
様々なライブラリの実装や参考記事等を比較しながら、ど
の方法が良いかを探りながら実装方針を決める。

また、独立した画面で旧新DIコンテナで動くことを確認。
Start
End
🏃 	DI 🏃 	Feature
1	Sprint
developブランチの変更
Feature開発ブランチがdevelop
にマージされたら取込&変更
基本的に対応中はDIコンテナの
お引っ越し&DIYに専念する
この期間はこまめにMerge&Confiict解消
2	Sprint
比較的軽めで依存関係が複雑ではないものから少しずつ移
行する。また移行作業中は2つのDIを共存させる形。
旧DI 新DI 新DI
移行完了
移行作業中は共存 力仕事にならざるを得なかった
のは反省点でした…😢
DIをお引っ越し&DIYをする際にあると嬉しいこと
上手く移行が完了しても以前と変わらず動作確認ができていないといけない
自分1人では結構不安に最初は感じていた部分はあれども、この様なチームの助けのお陰で完了できたと思います。
1.	現在の画面を書き出した画面遷移図:
チームとしてもアプリの仕様や画面遷移の全体像を把握する用途でデザイナーの方が準備して
頂いていたものがあり、画面や機能毎に適用ないしは移行をする作業時にも画面実装の抜け漏
れを防止するのに役に立ちました。
2.	QAチームによるリグレッションテスト:
UnitTestでの仕様の担保はある程度してはいるものの、開発者だけではテストがしにくい部分
(SandBoxでの課金処理など)の動作検証や、開発者の観点だけでは気がつきにくい部分を洗
い出すことができる事もあったので、本当に実施して頂き本当に感謝しております。
まとめ
車輪の再開発かもしれないが、自前で実装する方針もありかもしれない
1.	新たに取り入れる際も既存開発と並行した引っ越し時でも今のコードへの影響を少なくする工夫:
今回は既存で利用していたものを置き換える形で置き換えていく方針ではあったので、特にプロダクションコードだけではなく
テストコードに対しても最低限の調整だけで置き換える部分に注意をした様に思いました。
2.	各種定番ライブラリでの実装方針により深く触れる良い機会:
iOS/Android共にDI用の有名ライブラリがあり、それぞれ特徴的な部分があるので、平素の開発においては慣習的となっている部
分に改めて深く触れることでその特徴やメリット・デメリットを再認識する良い機会になった様に思いました。
勿論、素晴らしいライブラリが沢山ある領域なので、プロジェクトに合わせた良い選択を心がけたい部分。
3.	ライブラリの良い部分や特徴を取り入れた形を保ちつつも上手な形を見出す難しさ:
既存である程度の規模がある中ではチームの中で「しっくり来る形」を見出す準備の大切さを感じると同時に、自前でこの部分
を実装する際にはチームの状況等を鑑みて良い特徴となり得る部分を積極的に取り入れていくと良さそうに思いました。
Thank	you	for	listening	!

Contenu connexe

Tendances

Tendances (20)

「速」を落とさないコードレビュー
「速」を落とさないコードレビュー「速」を落とさないコードレビュー
「速」を落とさないコードレビュー
 
#MRDevDaysJP HoloLens 2 アプリ開発入門
#MRDevDaysJP HoloLens 2 アプリ開発入門#MRDevDaysJP HoloLens 2 アプリ開発入門
#MRDevDaysJP HoloLens 2 アプリ開発入門
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
 
そうだPostProcess Materialで見た目を変えよう
そうだPostProcess Materialで見た目を変えようそうだPostProcess Materialで見た目を変えよう
そうだPostProcess Materialで見た目を変えよう
 
UniTask入門
UniTask入門UniTask入門
UniTask入門
 
新たなgitのブランチモデル「Git Feature Flow」!Git Flow,Git Hub Flow,Git Lab Flowを超えれるか?
新たなgitのブランチモデル「Git Feature Flow」!Git Flow,Git Hub Flow,Git Lab Flowを超えれるか?新たなgitのブランチモデル「Git Feature Flow」!Git Flow,Git Hub Flow,Git Lab Flowを超えれるか?
新たなgitのブランチモデル「Git Feature Flow」!Git Flow,Git Hub Flow,Git Lab Flowを超えれるか?
 
UE4で学ぶ水中表現(UE4 Environment Art Dive)
UE4で学ぶ水中表現(UE4 Environment Art Dive)UE4で学ぶ水中表現(UE4 Environment Art Dive)
UE4で学ぶ水中表現(UE4 Environment Art Dive)
 
Di入門
Di入門Di入門
Di入門
 
PHP実践 ~外部APIを使って情報を取得する~
PHP実践 ~外部APIを使って情報を取得する~PHP実践 ~外部APIを使って情報を取得する~
PHP実践 ~外部APIを使って情報を取得する~
 
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
【Unite 2018 Tokyo】Unityにおける疎結合設計 ~UIへの適用事例から学ぶ、テクニックとメリット~
 
ワタシハ Azure Functions チョットデキル
ワタシハ Azure Functions チョットデキルワタシハ Azure Functions チョットデキル
ワタシハ Azure Functions チョットデキル
 
UE4を使った映像制作 (UE4 Character Art Dive Online)
UE4を使った映像制作 (UE4 Character Art Dive Online)UE4を使った映像制作 (UE4 Character Art Dive Online)
UE4を使った映像制作 (UE4 Character Art Dive Online)
 
【16-E-4】残業ゼロで開発スピードが10倍に!もう元の開発体制には戻れないデンソー流のアジャイル開発
【16-E-4】残業ゼロで開発スピードが10倍に!もう元の開発体制には戻れないデンソー流のアジャイル開発【16-E-4】残業ゼロで開発スピードが10倍に!もう元の開発体制には戻れないデンソー流のアジャイル開発
【16-E-4】残業ゼロで開発スピードが10倍に!もう元の開発体制には戻れないデンソー流のアジャイル開発
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
PHPの戻り値型宣言でselfを使ってみよう
PHPの戻り値型宣言でselfを使ってみようPHPの戻り値型宣言でselfを使ってみよう
PHPの戻り値型宣言でselfを使ってみよう
 
C#メタプログラミング概略 in 2021
C#メタプログラミング概略 in 2021C#メタプログラミング概略 in 2021
C#メタプログラミング概略 in 2021
 
Confluenceショートカットキー表 v1
Confluenceショートカットキー表 v1Confluenceショートカットキー表 v1
Confluenceショートカットキー表 v1
 
ASP. NET Core 汎用ホスト概要
ASP. NET Core 汎用ホスト概要ASP. NET Core 汎用ホスト概要
ASP. NET Core 汎用ホスト概要
 
AI動向 6月8日改訂.pdf
AI動向 6月8日改訂.pdfAI動向 6月8日改訂.pdf
AI動向 6月8日改訂.pdf
 
AWS CDKに魅入られた PHPer がオススメする
AWS CDKに魅入られた PHPer がオススメするAWS CDKに魅入られた PHPer がオススメする
AWS CDKに魅入られた PHPer がオススメする
 

Similaire à 既存プロジェクトで使っていたDIをお引っ越し&DIYすることになった

A2 Media Evaluation Question 2
A2 Media Evaluation Question 2A2 Media Evaluation Question 2
A2 Media Evaluation Question 2
Ashleat153
 
A2 Media Evaluation
A2 Media Evaluation A2 Media Evaluation
A2 Media Evaluation
Ashleat153
 
A2 Media Evaluation Q.2
A2 Media Evaluation Q.2A2 Media Evaluation Q.2
A2 Media Evaluation Q.2
Ashleat153
 

Similaire à 既存プロジェクトで使っていたDIをお引っ越し&DIYすることになった (20)

UIKitやSwiftUIで表現や動きが特徴的なUI実装事例を考察する
UIKitやSwiftUIで表現や動きが特徴的なUI実装事例を考察するUIKitやSwiftUIで表現や動きが特徴的なUI実装事例を考察する
UIKitやSwiftUIで表現や動きが特徴的なUI実装事例を考察する
 
UI実装に関するセッションを 簡単ながら振り返ってみる(仮)
UI実装に関するセッションを 簡単ながら振り返ってみる(仮)UI実装に関するセッションを 簡単ながら振り返ってみる(仮)
UI実装に関するセッションを 簡単ながら振り返ってみる(仮)
 
書籍執筆からの今後に向けてのロードマップ
書籍執筆からの今後に向けてのロードマップ書籍執筆からの今後に向けてのロードマップ
書籍執筆からの今後に向けてのロードマップ
 
How I become Go GDE
How I become Go GDEHow I become Go GDE
How I become Go GDE
 
Hint of a little ingenuity about UI.
Hint of a little ingenuity about UI.Hint of a little ingenuity about UI.
Hint of a little ingenuity about UI.
 
A Brief Introduction to Design Hacking + Generative Design
A Brief Introduction to Design Hacking + Generative DesignA Brief Introduction to Design Hacking + Generative Design
A Brief Introduction to Design Hacking + Generative Design
 
Hashicorp Tools For The Windows Ecosystem
Hashicorp Tools For The Windows EcosystemHashicorp Tools For The Windows Ecosystem
Hashicorp Tools For The Windows Ecosystem
 
The webs and it's future.
The webs and it's future.The webs and it's future.
The webs and it's future.
 
Improving developer collaboration with CodeSandbox
Improving developer collaboration with CodeSandboxImproving developer collaboration with CodeSandbox
Improving developer collaboration with CodeSandbox
 
An intro to Eleventy
An intro to EleventyAn intro to Eleventy
An intro to Eleventy
 
DroidKaigi 2018報告会(公式アプリへのコントリビュート)
DroidKaigi 2018報告会(公式アプリへのコントリビュート)DroidKaigi 2018報告会(公式アプリへのコントリビュート)
DroidKaigi 2018報告会(公式アプリへのコントリビュート)
 
Hacking Saturday 2018-05 - flutter
Hacking Saturday 2018-05 - flutterHacking Saturday 2018-05 - flutter
Hacking Saturday 2018-05 - flutter
 
Introducing Ubuntu SDK
Introducing Ubuntu SDKIntroducing Ubuntu SDK
Introducing Ubuntu SDK
 
iOS design: a case study
iOS design: a case studyiOS design: a case study
iOS design: a case study
 
DevOps + MongoDB Serverless = 
DevOps + MongoDB Serverless = DevOps + MongoDB Serverless = 
DevOps + MongoDB Serverless = 
 
A2 Media Evaluation Question 2
A2 Media Evaluation Question 2A2 Media Evaluation Question 2
A2 Media Evaluation Question 2
 
A2 Media Evaluation
A2 Media Evaluation A2 Media Evaluation
A2 Media Evaluation
 
A2 Media Evaluation Q.2
A2 Media Evaluation Q.2A2 Media Evaluation Q.2
A2 Media Evaluation Q.2
 
UI Framework Prototyping with Playgrounds for iOS Apps
UI Framework Prototyping with Playgrounds for iOS AppsUI Framework Prototyping with Playgrounds for iOS Apps
UI Framework Prototyping with Playgrounds for iOS Apps
 
Build your first Monster APP
Build your first Monster APPBuild your first Monster APP
Build your first Monster APP
 

Plus de Fumiya Sakai

Plus de Fumiya Sakai (20)

RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
 
Measures for Growth with Firebase Remote Config & Unit Testing Using RxSwift
Measures for Growth with Firebase Remote Config & Unit Testing Using RxSwiftMeasures for Growth with Firebase Remote Config & Unit Testing Using RxSwift
Measures for Growth with Firebase Remote Config & Unit Testing Using RxSwift
 
2022年の抱負とここ数年続けてきたインプット
2022年の抱負とここ数年続けてきたインプット2022年の抱負とここ数年続けてきたインプット
2022年の抱負とここ数年続けてきたインプット
 
最近の業務やAndroid関連のインプットと振り返り
最近の業務やAndroid関連のインプットと振り返り最近の業務やAndroid関連のインプットと振り返り
最近の業務やAndroid関連のインプットと振り返り
 
少しずつキャッチアップしていくAndroidアプリ開発の補足と振り返り
少しずつキャッチアップしていくAndroidアプリ開発の補足と振り返り少しずつキャッチアップしていくAndroidアプリ開発の補足と振り返り
少しずつキャッチアップしていくAndroidアプリ開発の補足と振り返り
 
少しずつキャッチアップしていくAndroidアプリ開発
少しずつキャッチアップしていくAndroidアプリ開発少しずつキャッチアップしていくAndroidアプリ開発
少しずつキャッチアップしていくAndroidアプリ開発
 
レイヤー分けをしたアーキテクチャで作るiOSアプリ&バックエンドのサンプル実装をのぞく
レイヤー分けをしたアーキテクチャで作るiOSアプリ&バックエンドのサンプル実装をのぞくレイヤー分けをしたアーキテクチャで作るiOSアプリ&バックエンドのサンプル実装をのぞく
レイヤー分けをしたアーキテクチャで作るiOSアプリ&バックエンドのサンプル実装をのぞく
 
iOSアプリ開発で意識すると役立ちそうな「つなぎ目」の部分について
iOSアプリ開発で意識すると役立ちそうな「つなぎ目」の部分についてiOSアプリ開発で意識すると役立ちそうな「つなぎ目」の部分について
iOSアプリ開発で意識すると役立ちそうな「つなぎ目」の部分について
 
試して感覚を掴んでみるUICollectionViewCompositionalLayout & Combine
試して感覚を掴んでみるUICollectionViewCompositionalLayout & Combine試して感覚を掴んでみるUICollectionViewCompositionalLayout & Combine
試して感覚を掴んでみるUICollectionViewCompositionalLayout & Combine
 
デザイナー→Webエンジニア→iOSエンジニアと渡り歩いた僕なりのSwiftとの向き合い方と生かす戦略
デザイナー→Webエンジニア→iOSエンジニアと渡り歩いた僕なりのSwiftとの向き合い方と生かす戦略デザイナー→Webエンジニア→iOSエンジニアと渡り歩いた僕なりのSwiftとの向き合い方と生かす戦略
デザイナー→Webエンジニア→iOSエンジニアと渡り歩いた僕なりのSwiftとの向き合い方と生かす戦略
 
何故に私達(特に私)はアプリのアニメーションや UI表現に魅了されるのか? そして共存と向き合いを考える
何故に私達(特に私)はアプリのアニメーションや UI表現に魅了されるのか? そして共存と向き合いを考える何故に私達(特に私)はアプリのアニメーションや UI表現に魅了されるのか? そして共存と向き合いを考える
何故に私達(特に私)はアプリのアニメーションや UI表現に魅了されるのか? そして共存と向き合いを考える
 
アプリ開発におけるテキスト装飾のアイデア集
アプリ開発におけるテキスト装飾のアイデア集アプリ開発におけるテキスト装飾のアイデア集
アプリ開発におけるテキスト装飾のアイデア集
 
ライブラリやView構造を有効活用して iOSアプリのUIをオシャレにするワザ紹介
ライブラリやView構造を有効活用して iOSアプリのUIをオシャレにするワザ紹介ライブラリやView構造を有効活用して iOSアプリのUIをオシャレにするワザ紹介
ライブラリやView構造を有効活用して iOSアプリのUIをオシャレにするワザ紹介
 
部品に切り分けて考えるView構造とライブラリを上手に活用したUI実装
部品に切り分けて考えるView構造とライブラリを上手に活用したUI実装部品に切り分けて考えるView構造とライブラリを上手に活用したUI実装
部品に切り分けて考えるView構造とライブラリを上手に活用したUI実装
 
UI表現ライブラリを有効活用して iOSアプリのUIをオシャレにするワザ紹介
UI表現ライブラリを有効活用して iOSアプリのUIをオシャレにするワザ紹介UI表現ライブラリを有効活用して iOSアプリのUIをオシャレにするワザ紹介
UI表現ライブラリを有効活用して iOSアプリのUIをオシャレにするワザ紹介
 
iOSアプリで気になった動きや表現を上手にアレンジして活用してみる
iOSアプリで気になった動きや表現を上手にアレンジして活用してみるiOSアプリで気になった動きや表現を上手にアレンジして活用してみる
iOSアプリで気になった動きや表現を上手にアレンジして活用してみる
 
iOSアプリUIとの触れ合いと歩む僕なりのSwiftの楽しみ方
iOSアプリUIとの触れ合いと歩む僕なりのSwiftの楽しみ方iOSアプリUIとの触れ合いと歩む僕なりのSwiftの楽しみ方
iOSアプリUIとの触れ合いと歩む僕なりのSwiftの楽しみ方
 
Approach of Prototyping for making Application User Interface about iOS
Approach of Prototyping for making Application User Interface about iOSApproach of Prototyping for making Application User Interface about iOS
Approach of Prototyping for making Application User Interface about iOS
 
Hint of“Passcode Lock”Screen and Logic (with LocalAuthentication).
Hint of“Passcode Lock”Screen and Logic (with LocalAuthentication).Hint of“Passcode Lock”Screen and Logic (with LocalAuthentication).
Hint of“Passcode Lock”Screen and Logic (with LocalAuthentication).
 
メディアアプリでよく見る無限スクロールするタブの動きへの考察
メディアアプリでよく見る無限スクロールするタブの動きへの考察メディアアプリでよく見る無限スクロールするタブの動きへの考察
メディアアプリでよく見る無限スクロールするタブの動きへの考察
 

Dernier

Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
FIDO Alliance
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
FIDO Alliance
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
FIDO Alliance
 

Dernier (20)

Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptx
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
 
How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdf
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
Oauth 2.0 Introduction and Flows with MuleSoft
Oauth 2.0 Introduction and Flows with MuleSoftOauth 2.0 Introduction and Flows with MuleSoft
Oauth 2.0 Introduction and Flows with MuleSoft
 
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch Tuesday
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджера
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
 
Long journey of Ruby Standard library at RubyKaigi 2024
Long journey of Ruby Standard library at RubyKaigi 2024Long journey of Ruby Standard library at RubyKaigi 2024
Long journey of Ruby Standard library at RubyKaigi 2024
 
Using IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & IrelandUsing IESVE for Room Loads Analysis - UK & Ireland
Using IESVE for Room Loads Analysis - UK & Ireland
 
Choosing the Right FDO Deployment Model for Your Application _ Geoffrey at In...
Choosing the Right FDO Deployment Model for Your Application _ Geoffrey at In...Choosing the Right FDO Deployment Model for Your Application _ Geoffrey at In...
Choosing the Right FDO Deployment Model for Your Application _ Geoffrey at In...
 
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdfIntroduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
 
FDO for Camera, Sensor and Networking Device – Commercial Solutions from VinC...
FDO for Camera, Sensor and Networking Device – Commercial Solutions from VinC...FDO for Camera, Sensor and Networking Device – Commercial Solutions from VinC...
FDO for Camera, Sensor and Networking Device – Commercial Solutions from VinC...
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 

既存プロジェクトで使っていたDIをお引っ越し&DIYすることになった