Skip to content

Instantly share code, notes, and snippets.

@nkmrh
Created October 28, 2022 11:01
Show Gist options
  • Save nkmrh/b8167af0c17b37464f053fda2e04695f to your computer and use it in GitHub Desktop.
Save nkmrh/b8167af0c17b37464f053fda2e04695f to your computer and use it in GitHub Desktop.
Japanese translation of NSSpain-X-13

13 - Lessons learnt rewriting SoundCloud in SwiftUI - Matias Villaverde & Rens Breur

https://vimeo.com/751534042

Um, yeah before the talk, I would like to use this time to clarify something because it has been this like rumors or like people talking behind our backs.

ええと、そうですね、話をする前に、この時間を使って、あることを明らかにしたいと思います。 というのも、これまで私たちの背後で というのも、これまで噂や陰口をたたかれたことがあったからです。 っているんです。

like yeah saying kind of toxic things, you know like and like I mean, I understand we come here to Spain like Tapas and so on but I think it still should be like a professional environment. So

毒のあることを言ってるようなものだ。 スペインに来たからにはタパスのようなものを食べたいと思うのはわかりますが のようなものであるべきだと思います。 プロフェッショナルな環境であるべきだと思います。だから

there are some people that have been saying that in the previous talks the During the covid period online we have been attending without wearing pants. That's definitely false. We do wear pants and that's why we're here in person. And yeah with that said and clarify. Let's start with our talk with some. Yeah lessons.

という声もあるようです。 今までの講演では オンラインではノーパンで参加している。 それは間違いなく嘘です。私たちはパンツを履いて そのために私たちはここにいるのです。 そして、ええ、それを言って、明確にする。私たちの話を始めましょう。 トークを始めましょう。ええ、レッスンです。

Thank you. Yeah, so these are some mistakes and lessons while we rewrite the same Cloud you since with UI a bit of background. We are like a 10 years old codebase AKA we have a lot of Legacy code. Most around like 70 contributors. We have more than 10 million daily users a lot of content. You can find everything like for example snake jazz is really lovely everything you can find Santa Clara.

ありがとうございます。 これは間違いや教訓です。 同じクラウドを書き換えている間の教訓です。 UIの背景を少し説明します。私たちは10年前のコードベースです。 年前のコードベース、別名レガシーコードがたくさんあります。 レガシーコードがあります。 70人ほどのコントリビューターがいます。私たちは 毎日1千万人以上のユーザーがいて、多くのコンテンツが コンテンツがある。例えば 例えば、スネークジャズは本当に サンタ・クララを見つけることができます。

Before SwiftUI

Yeah, so before Swift UI what we're using Viper. Everything was UI kit. I will not get into the Inners of Viper, but it was a idea of using clean architecture principles like programming against an interface having different layers unit. Test everything and it came the project up. Sorry. The only difference that we had is we added like an event controller that it was like the single source of Truth for events, like user input The View life cycle, but it was just basically Viper. We came the project less redesigned SoundCloud. Let's make it amazing and pretty again. So it was a good time that we sit in front of the Whiteboard We Touch our faces and we said let's find the best architecture for it.

そう、Swift UIの前に、Viperを使っているんです。すべて はUIキットでした。Viperの内部には触れませんがそれは クリーンなアーキテクチャの原則を使うというアイデアです。 に対してプログラミングを行うという、クリーンなアーキテクチャの原則を に対してプログラミングするような、クリーンなアーキテクチャの原則を使うというものでした。すべてをテストして、それ プロジェクトが立ち上がりました。すみません。ただ 唯一の違いは、イベントコントローラを追加したことです。 このコントローラは、イベントのための真実の単一ソースとなります。 ユーザー入力のような ビューのライフサイクル、でもそれは しかし、それは基本的にViperだけでした 私たちは、このプロジェクトで再設計を行うことはありませんでした。 SoundCloudです。をもう一度素晴らしく、かわいくしよう もう一度 ということで、ホワイトボードの前に座って 私たちはホワイトボードの前に座り 顔を触って、最適なアーキテクチャを見つけよう、と。

Let's use SwiftUI

And it was quite easy actually because what Viper has is that you can replace the implementation of any of the layers and you can reuse the rest of your code. So what that's what we did we replaced the UI view controllers for Swift UI views and this was possible because we follow some of the clean architecture principles. One of it

というのも、Viperが持っているのは、実装を置き換えるだけなので、実はとても簡単だったんです。 は、どのレイヤーでも実装を置き換えることができ どのレイヤーの実装を入れ替えても 残りのコードも再利用できるのです。そこで 私たちが行ったのは、UIビューコントローラーをSwiftの UIビューに置き換えました。 これは、私たちがいくつかのクリーンアーキテクチャの原則に従っているから可能なのです。 そのうちのひとつは

Independent of the Database

is like being Independence of the database like our UI didn't know from where our data is coming from. Instead of having like entities we have something called repositories a repository is like a link at least of different notes it of the node. It will be different store and we will like iterate over that linked list till we find the fresh data. So it will start from like the network layer. We will decode it into an API model using the API note. It was the first node. We will output that API model. We will transform into domain model that domain model is going to be the input of the next node that is going to be mapped to a core data model that core data model is going to be saved into core data. I think we will read from core data. We will output a core data model map it into a domain model that domain model is going to go to the next node, and we will just save it in memory just like To work a bit faster and then we will output the domain model finally to the repository. So yeah, we have this like kind of flow of data coming from right to left or left to right then when you're looking at there was this basically this link at least they have different nodes the network client API and know the ram no the core data node and it starts with an APN model that has the domain model that Maps into the main model and that to a correlated model the domain and there's a lot of mappers, but don't worry. Everything is like generic. So we have a lot of generic mappers.

というのも、Viperが持っているのは、実装を置き換えるだけなので、実はとても簡単だったんです。 は、どのレイヤーでも実装を置き換えることができ どのレイヤーの実装を入れ替えても 残りのコードも再利用できるのです。ですから 私たちが行ったのは、UIビューコントローラーをSwiftの UIビューに置き換えました。 これは、私たちがいくつかのクリーンアーキテクチャの原則に従っているから可能なのです。 そのうちのひとつは その一つは、データベースから独立することで、UIはデータがどこから来るのか分からないようにすることです。 データがどこから来るかわからないようにすることです。 エンティティを持つ代わりに、リポジトリと呼ばれるものがあります。 リポジトリとは 少なくとも異なる ノートのようなものです。それは異なる を保存し そのリンクリストを新しいデータを見つけるまで繰り返すような 新鮮なデータを見つけるまで、そのリンクリストを繰り返します。だから、それは ネットワーク層からスタートします。私たちは を使ってAPIモデルにデコードします。 APIノートです。これは最初のノードです。それを出力します。 APIモデルです。ドメインモデルに変換する そのドメインモデルが次のノードの入力となる。 次のノードにマッピングされます。 コアデータモデルにマッピングされる。 コアデータに保存されます。 コアデータから読み込むことになると思う。 コア・データ・モデルを出力し、それをドメイン・モデルにマップします。 そのドメインモデルは次のノードに移動します。 それをメモリに保存する と同じようにメモリに保存します。 もう少し高速に動作させるため、そして 最終的にドメインモデルをリポジトリに出力します。 そう、このように 右から左へ、あるいは左から右へのデータの流れがあります。 左から左へ、あるいは左から右へ、そして、そこにあるものを見てみると 基本的にこのリンクは少なくとも ネットワーククライアントAPIと ラムはコアデータノードで、APNモデルから始まります。 モデルから始まり、ドメインモデルがメインモデルにマップされ そしてそれは相関モデルへ、ドメインへ、そしてそこには多くのマッパーがあります。 マッパーがたくさんありますが、心配しないでください。すべて汎用的なものです。ですから 汎用的なマッパーがたくさんあります。

Let's ViewModel

It works. Please. Don't touch it. So, yeah, so every layer it had different models, so we thought it was a good idea to add viewmodels. So we have presenters that you will get the domain models and transform them into view months and bus view models. They will be presented into our swiftui another clean architecture principle that we read in one of these best selling books that models should be immutable because there are thread-safe you don't have different parts of the applications that are mutating your state so we can be a bit more functional right and you sound clever. So that's what we did. And also we added combined we can be now a bit more functional. So instead of having presenters. We had a view model Factory that it will output the publisher of view model. So like a stream of For example, like if you're presenting like a track list or like a playlist We will have an a stream of you track view models.

うまくいくんです。お願い 触らないように そうそう、各レイヤーにはそれぞれ異なるモデルがありましたので ビューモデルを追加するのが良いアイデアだと思いました。そこで プレゼンターを用意しました。 ドメイン・モデルからビュー・モデルに変換し とバスビューモデルに変換します。これらのモデルは、私たちの swiftui に表示されます。 もう一つのクリーンなアーキテクチャの原則は、ベストセラーの本の中で読んだものです。 モデルは不変であるべきだと、このベストセラーの本で読みました。 スレッドセーフであるため、モデルは不変であるべきです。 アプリケーションのさまざまな部分で状態が変化することはありません。 そのため、アプリケーションのさまざまな部分が状態を変化させることがありません。 そうすれば、もう少し機能的になります。 と賢そうに言っています。これが私たちが行ったことです。そしてまた 私たちは結合を加えました これで少しは機能的になります より機能的になりました。つまり、プレゼンターを置く代わりに 私たちは ビューモデルを出力する Factory があります。 ビューモデルのパブリッシャーです。のストリームのようなものですね。 例えば、トラックリストやプレイリストのようなものを提示する場合、我々はストリームを用意します。 プレイリストのようなものです。 のストリームを持つことになります。

Don't use @Environment

Yeah, this is and just a small thing. We didn't want to use environment because it will break it was difficult to find where this dependencies are coming from as well. It can crash at runtime and the compiler cannot tell us like if some of the views doesn't have environment and if you remember someone said in in the meeting like this looks like a Singleton and it It's not use it and we didn't use it

ええ、これは、ほんの小さなことです。 小さなことですが 環境は使いたくなかったんです。 が壊れてしまうからです。 を見つけるのが大変でした。実行時にクラッシュする可能性がありますし、コンパイラが あるビューが環境を持っていない場合、コンパイラはそれを知ることができません。 ある人が言っていたのを覚えていますか? これはシングルトンのように見えますが、実はそうではありません。 これはシングルトンに見えるが、使っていない。

The new and shiny

And with this architecture that uses Swift UI he applies clean architecture principles. Is uses or reduces our old code? It has combined. We wrote all the obligation. You took us some time. I would call it we have time and we release it to the App Store Which one of the first big companies or like companies that has built at scale the deployed an app completely billions with UI. It was quite cool. We managed to ship it.

そして、このアーキテクチャは、Swift UIを採用したこのアーキテクチャは、クリーンアーキテクチャの原則を適用しています。 私たちの古いコードを使うか減らすか? それは結合されています。我々は、すべての義務を書いた。時間がかかりましたね。UIで完全に数十億のアプリを大規模に構築し、デプロイした最初の大企業の一つ、またはそのような企業の一つです。とてもクールでした。なんとか出荷することができました。

And then we got an email from Apple. It's like hey your app is 10 times lower than your competition. full disclosure here like this and as an email with tutorials of how to build a table View there was a highlight of my career. Love it. And yeah. with that said I will leave you with my colleague friends. They're just gonna live demo some of the findings that so let's look at how this architecture. That we put a lot of thought into turnout to be slow and also really hard to work with so for that mati, and I have prepared two versions of the demo application. So the demo app shows one of the playlists on soundclouds it patches it from the API and then it caches it in core data. I don't want to show this project in detail. I don't think it works in a presentation to show a lot of code. I think it also wouldn't work if I give you the code because this architecture is not easy to understand but I would like to highlight some points. First of all, you can see the interactor and the repository you can also see that there's a few model provider. This uses combine to Output a few model. The playlist view then takes a few model from the few model provider. And uses that in the body and any subfields of playlist view such as track view in this case. our initialized with a with a dump few model structure that they get from the playlist View.

Email from Apple

You are 10 times slower than the competition

そして、アップルからメールが届きました。 ヘイ あなたのアプリはあなたの競争相手より10倍低いというようなものです 完全な開示 ここではこのように、テーブルビューを構築する方法のチュートリアルを含むメールとして そこに私のキャリアのハイライトがありました。大好きです。というわけで、私の同僚の友人と一緒に、この場を離れることにします。彼らは、このアーキテクチャがどのようなものであるかを見てみましょう。そのために、matiと私は2つのバージョンのデモアプリケーションを用意しました。デモ・アプリケーションは、soundclouds上のプレイリストをAPIからパッチして、コア・データにキャッシュしています。このプロジェクトを詳しく紹介するつもりはありません。たくさんのコードを見せるのは、プレゼンではうまくいかないと思うからです。また、このアーキテクチャは簡単には理解できないので、コードを渡してもうまくいかないと思いますが、いくつかの点を強調したいと思います。まず、インタラクターとリポジトリが見えますが、いくつかのモデルプロバイダーがあることもわかります。これはコンバインを使って、いくつかのモデルを出力します。そして、プレイリストビューは少数のモデルを少数のモデルプロバイダから取得します。そして、それをプレイリストビューのボディとサブフィールド(この場合はトラックビューなど)で使用します。 プレイリストビューから取得した数モデルの構造をダンプして初期化します。

So note some things here. First of all track view is not really a function of state. It takes one representation of the few and turned it into a swiftui specific one. also You can notice that the scrolling isn't isn't very smooth. And the reason is that every change has to go through playlist view through this few model. Before it can get to the other fuse. So then we made version 2 and we thought okay how it's somebody write this application. That doesn't know anything about good good texture like somebody who works at Apple and provides the tutorials and sample code.

そこで、いくつかの点に注意してください。まず第一に、トラックビューは実際にはステートの関数ではありません。また、スクロールがあまりスムーズでないことにお気づきでしょう。その理由は、すべての変更がこの少数のモデルを経由してプレイリストビューを通過しなければならないからです。他のヒューズに到達する前に。そこで、私たちはバージョン2を作り、誰かがこのアプリケーションを書くのはどうだろうと考えました。それは、Appleで働いていて、チュートリアルやサンプルコードを提供してくれるような、良いテクスチャーのことを何も知らない人たちです。

So we thought they might come up with something like this. This is the same view but there's no interact. There's no few model providers. It uses. Apple's property wrappers fetch Observed object and you can see that the fuse are a function of state now. There's no parallel hierarchies of views and view models. So we don't see it. We don't want to say that everybody should start developing apps like this, but there are ways in which version two is better than what we came up with. And rewriting SoundCloud in swiftUI with this architecture. You read some learnings.

そこで、このようなものが出てくるのではないかと考えました。これは同じ表示ですが、対話がありません。モデルプロバイダーもほとんどありません。使っています。AppleのプロパティラッパーはObservedオブジェクトを取得し、ヒューズが状態の関数であることがわかります。ビューとビューモデルの並列階層はありません。 だから、見えないのです。誰もがこのようなアプリを開発し始めるべきだとは言いませんが、私たちが考え出したものよりもバージョン2が優れている点はあります。そして、このアーキテクチャでSoundCloudをswiftUIで書き直しました。いくつかの学びを読みましたね。

Use local data

Keep data close to the view that displays it, as this prevents unnecessary view updates

For example use local data. So in our architecture every change has to go through one observed object and then it had to go through the view and it has a compared a view models. So if UI is able to compare child views and see if it needs to evaluate their body, but we still had to create those views and view models before they could be compared.

例えば、ローカルデータを使用します。私たちのアーキテクチャでは、すべての変更は1つの観測されたオブジェクトを通過しなければならず、その後、ビューを通過して、ビューモデルを比較しなければなりません。そのため、UIが子ビューを比較し、そのボディを評価する必要があるかどうかを確認することができますが、それでも比較する前にそれらのビューとビューモデルを作成する必要がありました。

Use all property wrappers

Different properties wrappers are optimized for their use

Also use all the property wrappers that are available from swiftUI. We only use the observed objects because it allowed us to make a few Observer class. And that was what we wanted for our architecture but there are many different property wrappers and they're optimized for a specific use sometimes more than you expect.

また、swiftUIから利用可能なすべてのプロパティラッパーを使用します。私たちが観測されたオブジェクトを使用するのは、Observerクラスをいくつか作ることができたからです。しかし、プロパティラッパーには様々なものがあり、特定の用途に最適化されていることもあるので、予想以上に便利です。

EXAMPLE State and Binding

For example State and binding are optimized in a particular way. Let's say we want to add some functionality to our playlist app. To select a trick we could do that by editing a state variable to playlist view that contains the idea of the selected track and then the track view could have a binding to the same variable. You might think that if the selected track is changed that will cause the retrigger of the playlist views body because that's the view that contains the state but Swift UI is smart enough to know that this state variable is not used directly in the playlist views body, but only through bindings. So only the track views are updated.

例えばStateとbindingは特定の方法で最適化されています。例えば、プレイリストアプリに何らかの機能を追加したいとします。トリックを選択するには、選択されたトラックのアイデアを含むプレイリストビューのステート変数を編集し、トラックビューに同じ変数へのバインディングを持たせることができます。選択されたトラックが変更された場合、それは状態を含むビューであるため、プレイリストビュー本体の再トリガーを引き起こすと思うかもしれませんが、この状態変数はプレイリストビュー本体で直接使用されていないことを知っているSwift UIは十分にスマートです、唯一のバインディングを介して、その。そのため、トラックビューのみが更新されます。

EXAMPLE Environment

Another example is the environment so you probably know about this optimization. But let's say that we want to add the option to change the cell size and increase the artwork using a cell size property that we set in a root view of our application and we want to read in the artwork View. If you use environment for that and set it in the root View and read it in the artwork for you. And we change the cell size only the artworks will be retriggered.

別の例は、環境なので、おそらくこの最適化について知っていると思います。しかし、アプリケーションのルートビューに設定したセルサイズプロパティを使用して、セルサイズを変更してアートワークを増やすオプションを追加し、アートワークビューで読みたいとします。そのために環境を使用し、ルートビューに設定し、あなたのためのアートワークでそれを読み取る場合。そして、セルサイズを変更すると、アートワークだけが再トリガーされます。

EXAMPLE FetchRequest and ObservedObject

And the last one is particularly important for our example if we use fetch requests and observed objects and one of the tracks changes. First of all, it's going to trigger The observed object in track View. And it will also trigger the fetch request and playlist View. But the playlist views body contains now a list of tracks that only contain a reference to the track type. So they're really easy to create and also much cheaper to compare.

そして最後の1つは、フェッチリクエストと観測オブジェクトを使用して、トラックの1つが変更された場合、この例では特に重要です。まず、トラックビューの観測されたオブジェクトがトリガーされます。そして、フェッチリクエストとプレイリストビューもトリガーされます。しかし、プレイリストビューのボディには、トラックタイプへの参照だけを含むトラックのリストが含まれるようになりました。そのため、作成が非常に簡単で、比較も非常に安くなっています。

Don't force the use of Combine

SwiftUI is not reactive, and the data flow in both frameworks is reversed

Another thing we learned was Don't Force the use of combine because in our experience they don't work. Well together that well. Reactive programming and declarative UI programming don't have anything in common. So reactive programming works with streams of immutable values and it sounds super useful for UI programming. If you could model user inputs using a stream of immutable input events, you could maybe transform that into a stream of user and stream a view models which is useful, but that's not how SwiftUI allows you to get events or set views. So in our example, the scrolling was slow because when an artwork came into view when it was appearing we were loading the image from from our API in combine. So we're going to get a publisher of the event that a track is that an artwork is appearing on screen. But we can immediately get a publisher out of that. If you want to pipe this into combine, we need to create a subject and then in the on appear modifier from Swift UI which takes a closer where we can call something we can call sand on this subject and then we can use it in combine. And in the end we have a publisher a few models, which is useful, but in order to use it, we need to create an ad published variable and then assign our publisher to this variable and it's not so much boilerplate code because it's not that much. But it really it's really tempting to make this the kind of reactive program from combine with a more imperative style programming in SwiftUI, and you might set a variable inside of a map and that causes the data flow to be really complicated.

もうひとつ学んだことは、「コンバインを無理に使うな」ということです。うまくまとまるということは リアクティブ・プログラミングと宣言型UIプログラミングには共通点がない。リアクティブ・プログラミングは、イミュータブルな値のストリームを扱うので、UIプログラミングには超便利そうです。もし、不変の入力イベントのストリームを使ってユーザーの入力をモデル化できれば、それをユーザーのストリームとビューモデルのストリームに変換することができ、それは便利ですが、SwiftUIでイベントを取得したりビューを設定する方法はそうではありません。この例では、アートワークが表示されたときに、combineのAPIから画像をロードしていたので、スクロールが遅かったのです。そこで、アートワークが画面に表示されるトラックというイベントのパブリッシャーを取得することにしました。しかし、そこからすぐにパブリッシャーを取得することができます。これをcombineにパイプしたい場合は、subjectを作って、Swift UIのon appear modifierで、このsubjectにsandを呼び出すことができるクローザーを持っていって、combineでそれを使うことができます。最終的にはパブリッシャーといくつかのモデルがあって、これは便利なのですが、これを使うには、広告掲載用の変数を作って、パブリッシャーをこの変数に代入する必要があります。しかし、SwiftUIでより命令的なスタイルのプログラミングと組み合わせて、この種のリアクティブなプログラムを作るのは本当に魅力的で、マップの中に変数を設定することもあり、データフローが本当に複雑になってしまいます。

Be careful with closures

SwiftUI does not like them

Another thing we learned was be careful with closures because in our experience They weren't indication. Sometimes they really did something wrong. So this isn't actually an example of the SoundCloud source code. We added lazy view lazy views really smart. So it reaps a few and it stores And disclosures only called in the body. That means it's only called when lazy view appears. So this is because we have a background in uikit programming where we want to prevent view from being created. But LazyView stores the closure to content view that stores the reference to all the various books that are used inside and also it stores a reference to do to the logic that creates the view like to the body. Sober Harvey saving anything here.

もうひとつ学んだことは、クロージャーには注意が必要だということです。時には本当に間違ったことをすることもあります。これはSoundCloudのソースコードの例ではありません。私たちは怠惰なビューを追加しました。このビューは、ボディーの中でしか呼び出されないので、いくつかの情報を取得し、それを保存します。つまり、遅延ビューが表示されたときだけ呼び出されるのです。これは、uikitのプログラミングで、viewが作られないようにしたいという背景があるからです。しかし、LazyViewはコンテンツビューへのクロージャを保存し、内部で使用される様々なブックへの参照を保存し、さらにボディにあるようなビューを作成するロジックへの参照を保存しています。地味にHarveyはここで何かを保存しています。

What is the best architecture?

Yeah, the learnings would just then the best architecture if you want to rewrite. Your app in Swift UI we don't know. Definitely don't know but we have some learnings like as a kind of takeout of this talk. The first one is like have just one single source of Truth for state. If you remember it in the previous slides

ええ、学習はちょうどあなたが書き直したい場合は、最適なアーキテクチャになります。Swift UIでのあなたのアプリは、私たちにはわかりません。確かにわからないけど、この講演の収穫として、いくつかの学びがあります。まず1つ目は、状態の真偽を判断するソースを1つだけ持つということです。前のスライドにあったように

Source of truth

Have one clear single source of truth for state

we had these huge Viper and repositories where like Data, it will be like a stream of data. No, it will start from the network. note that it will transform it into the domain model the domain model in core data model sometimes and and it will like output at the end this like publisher of So at any time each of the nodes they had different state. So core data had a different state maybe than the in-memory layer or the memory layer will have different state as the view. It was extremely complicated to find and SwiftUI really. Well when you have one single source of resource state, they're like just function of your model and actually works really well evaluating if they need to redraw or not in case your models changes. The second one I think is like

巨大なViperやリポジトリがあって、そこではデータのストリームみたいなものが流れています。コア・データ・モデルのドメイン・モデルに変換して、最後にパブリッシャーのようなものを出力します。コアデータはインメモリレイヤーやメモリレイヤーと異なる状態を持っていて、ビューも異なる状態を持っている可能性があります。これはSwiftUIを見つけるのに非常に複雑でした。リソースの状態の単一のソースがあれば、それらはモデルの単なる機能のようなもので、モデルが変更された場合に再描画する必要があるかどうかを評価するのにとてもよく機能します。2つ目は、次のようなものだと思います。

Do not be too academical

Follow the documentation

try not to be to academical like follow the documentation instead some of these like principles they sound really good, but it's not building rocket science, which is like a table View. will keep it simple, you know like If I can go to the past and talk to myself, I will definitely say Yeah by definitely say Yeah by I read the documentation like we we try to learn all the way and was with not the best idea and then

それは、ドキュメントに従うような学問的なものにならないようにする代わりに、これらの原則のようなもののいくつかは、彼らは本当に良いように聞こえるが、それはロケット科学を構築していない、テーブルビューのようなものである。 もし私が過去に行き、自分自身に語りかけることができたなら、間違いなく「そうだ」と言うでしょう。

Watch out with wrapping Core Data

Core Data is optimized to work well with the UI

watch out with wrapping core data like it sounds great. The database is detail Implementation but actually core data is quite good and most of the problems they come from not knowing how to use core data and it works really well with the UI. It's like a rent mentioned like using fetch request or yeah creating your own property wrappers. It's optimized to work really well with SwiftUI.

コアデータのラッピングに気をつけましょう。データベースはディテールまで実装されていますが、実はコアデータは非常に優れていて、問題のほとんどはコアデータの使い方を知らないことから生じていますし、UIとの相性も抜群です。フェッチ・リクエストを使ったり、独自のプロパティ・ラッパーを作ったりと、家賃のようなものです。SwiftUIでとてもうまく動作するように最適化されています。

Do not use the latest tech

Apple new and shiny... AKA not production ready

And then be careful using the latest tech because these things that there are new and shiny like we started like more than two years ago. It's actually not production ready. And especially when you relapse at scale like a lot of things they were complicated. We need to stop supporting a lot of iOS version just because it was not working.

そして、最新の技術を使うことには注意が必要です。これらの技術は、私たちが2年以上前に始めたように、新しく、ピカピカしています。実は、まだ製品化には至っていないのです。特に、規模が大きくなると、多くのことが複雑になってしまいます。動作しないからといって、iOSの多くのバージョンをサポートするのはやめなければなりません。

Deliver FAST!

15 * 32 = ??

And also, yeah the liver fast like when stakeholders and managers they come and you say we need these tomorrow like to sing on these like 15 times 32 is 143. Yeah, it's wrong. But at least we deliver it fast.

また、ステークホルダーやマネージャーが来て、明日からこれが必要だと言うと、15回歌って143回になるような、肝っ玉の太い話もあります。ええ、間違ってますね。でも、少なくとも納期は早いんです。

Don't design only around testing

Keep only complex logic outside the view for unit testing

Right, but then if we don't have a lot of layers, how do we test? So first we proposed we'll just test it in production users will file bug reports and we'll fix it. But our management didn't like it. So we came up with something else. If you have really complicated logic confused, you can extract that out for example, really complicated logic confused, you can extract that out for example, logic at the sides, which icons to display on a track View. and for the remaining part of testing a few we came up with our testing library to test with UI view that I would like to give a short demo of So this is our track view. I will open the body. It's simple right now just contains an image of the of the artwork and a track title. There's not a lot of logic in there, but it will be useful if you could show the track description, so I'm gonna add a state variable to show the description. And then if scrolling works. I will add a button to show and hide the description. And the description itself now I only need to put this in the feedback. Okay, so it works and I'm a programmer. I think this UI is fine. now for testing I imported our testing Library Axt. And I will add some test identifiers for example for the track title. I will also add an ID to the to the and the track description And I've also add one for the entire trick. So Now, let me go to the tests. So I've already imported the testing library and I've started the test is displaying a preview trick. So the first thing we can do is we can call watch hierarchy. and you can see the track view in a simulator and you can also see that printed the hierarchy of all the fuse that I gave a test ID to now if a click show more you can see it's displaying the track and it's also updating the hierarchy here with the label. Okay, so let's write a test about this so. What I can do is I can get the button out of the And then I can assert that we can find a description. Okay, one last thing. I'm not happy with right now. If it's showing a description the button still says show more should say show less. So let me add an assertion for that. Right, that's not the case right now. Let's go back here and fix it.

でも、レイヤー数が少なければ、どうやってテストすればいいのでしょう?そこで私たちはまず、本番環境でテストし、ユーザーがバグレポートを提出すれば、私たちがそれを修正することを提案しました。しかし、経営陣はそれを好みません。そこで、別の方法を思いつきました。例えば、本当に複雑なロジックで混乱している場合、それを抽出することができます。例えば、トラックビューにどのアイコンを表示するかといったサイドのロジックを抽出することができます。ボディを開いてみます。今は、アートワークの画像とトラックのタイトルを含むだけで、シンプルなものになっています。ロジックはそれほど多くありませんが、トラックの説明を表示できると便利なので、説明を表示するためのステート変数を追加してみます。そして、スクロールがうまくいったら 説明文を表示・非表示にするボタンを追加します。そして、説明文そのものは、あとはこれをフィードバックに入れるだけです。さて、これでうまくいったわけですが、私はプログラマーです。さて、テスト用にテスト用ライブラリAxtをインポートした。そして、例えば曲名にテスト用の識別子を追加します。また、曲名や曲の説明にもIDを追加し、さらにトリック全体にもIDを追加しました。では、テストに移りましょう。テスト用ライブラリはすでにインポート済みで、プレビュー・トリックを表示するテストを開始しました。シミュレータでトラックビューを見ると、テストIDをつけたヒューズの階層がプリントされているのがわかります。では、このテストについて書いてみましょう。 そして、説明を見つけることができることを保証します。 さて、最後にもうひとつ。今のままでは不満です。説明文が表示されているのに、ボタンがshow moreと表示されているのはshow lessと表示すべきです。そこで、そのためのアサーションを追加してみます。 そうですね、今はそうなっていませんね。ここに戻って修正しましょう。

One last word

Make it simple

Um, yeah in so take out one last word make it simple and overcomplicate things. And yeah credits to a lot of the iOS Engineers that they work on rebuilding Swift UI has SoundCloud in SwiftUI. It was this was a really interesting project. And as you might hear like SoundCloud layoffs 20% in the US and the UK, so in case you want to hire a soundclouder, this is the link. Thank you very much. https://linkd.in/er9Zi2qn

そうですね、最後の一言を削除して、シンプルにして、物事を複雑にしすぎました。そして、Swift UIの再構築に取り組んでいるiOSエンジニアの多くに、SwiftUIにSoundCloudを搭載したことを認めています。これは本当に面白いプロジェクトでした。SoundCloudが米国と英国で20%のレイオフをしたことをご存知かもしれませんが、SoundClouderを雇いたい場合は、このリンク先をご覧ください。ありがとうございました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment