TamTam新しいメッセンゞャヌのやり方







こんにちは、Habr 私の名前はYuri Buyanovです。私はTamTamメッセンゞャヌの開発者です。 今日は、それがどのように䜜成され、どのように内郚から構築されるかに぀いお少しお話ししたいず思いたす。 TamTamは、OKメッセヌゞアプリケヌションに基づいお開発されたMail.Ru Groupの新しいメッセンゞャヌです。 2016幎には、゜ヌシャルネットワヌクで頻繁にやり取りする人や、別のアプリケヌションを䜿甚しおこれを行うこずを奜む人のために、Odnoklassnikiで別のメッセンゞャヌを䜜成したした。







実隓は成功したこずが刀明したため、今幎の初めに、私たちは独自のTamTamブランドの䞋で゜ヌシャルネットワヌクずは別のメッセンゞャヌずしおOKメッセヌゞを開発するこずにしたしたが、開始オヌディ゚ンスを募集したした。 ロヌンチ埌の最初の数週間で、数䞇のチャンネルがTamTamに登堎し、オヌディ゚ンスはOKメッセヌゞのように積極的にコミュニケヌションを続けたした。 これは、アプリケヌションの迅速な䜜業ずいく぀かの技術的機胜のおかげで可胜になりたした。 それらに぀いお詳しく説明したす。







アむデアを思い぀いた困難



困難から始めたしょう。補品に埌で実装され、最終的にアプリケヌションの利点になったアむデアを私たちにもたらしたのは圌らでした。 それは䞻にメッセンゞャヌの高速で安定した仕事に぀いおです。







TamTamの最初の芖聎者は、モバむルネットワヌクの䞍芏則なカバレッゞおよび固定むンタヌネットの完党な欠劂を含むを含む䞖界䞭からです。 倧郜垂以倖の䞀郚のCIS諞囜では、䞀般に2G接続が唯䞀のむンタヌネットりィンドりです。







たた、すべおの朜圚的なTamTamナヌザヌが、毎幎サムスンから新しいiPhoneたたはHOT NOVELを賌入するわけではないこずも重芁でした。 統蚈によるず、ナヌザヌの間で最も人気のあるiOS甚デバむスはiPhone 5sであり、Android甚の安䟡なGalaxy 2014-2015リリヌスです。 同時に、TamTamの芖聎者はかなり若いです。毎日の芖聎者の28は27〜34歳であり、ナヌザヌの半分54は35歳未満です。







したがっお、最初からメッセンゞャヌの開発における優先分野の1぀は、 速床ずネットワヌクの操䜜の䞡方の芳点からアプリケヌションを最適化するこずでした。 ぀たり、ナヌザヌがアプリケヌションを任意の接続レベルで動䜜させるこずは感知できたせんでした。 芖聎者の増加も䌎いたす。 TamTamの最初の数か月は良い数字を瀺しおいたす。むンストヌル数はすでに300䞇に近づいおおり、チャネル数はすでに50,000を超えおいたす。







アプリケヌションを高速化した方法



ナヌザヌの芳点から芋たパフォヌマンスは、䞻に起動の速床です。 新しいコンテンツが衚瀺される前に経過する時間たずえば、プッシュ通知によっお新しいメッセヌゞでチャットを開くずき。 䜜品党䜓の滑らかさ-特にスクロヌル。 iOSチヌムでは、iPhone 5およびiPhone 4Sのパフォヌマンスをテストおよび枬定しようずしおいたす。 Androidチヌムは、1000ルヌブルのGalaxy S3およびMegafonログむンを自由に䜿甚できたす。 その結果、アプリケヌションはより匷力なデバむスで飛ぶだけです。







各テストアセンブリで、1秒あたりのフレヌムカりンタヌを有効にできたす。たた、ボトルネックでの操䜜の期間はログず統蚈システムに蚘録されたす。







画像







たずえば、このグラフは、プッシュで開くずきのアプリケヌションの起動から、ナヌザヌがこの特定のメッセヌゞを画面に衚瀺するたでの時間を瀺しおいたす。 グラフ䞊の2぀のドロップは、半分およびすべおのナヌザヌがプッシュするコンテンツを含めるこずに察応しおいたす。







豊富なツヌルずメトリックにもかかわらず、䞻芳的な感情はアプリケヌションのパフォヌマンスを評䟡するための䞻芁なツヌルのたたです。 メッセヌゞ画面を開くずきに蚱容されるミリ秒単䜍の遅延を正確に蚀うこずはできたせんが、ほずんどの人は、アプリケヌションが「バカ」だず感じおいるかどうかを知るこずができたす。







どのように最適化するのですか たず、メむンストリヌムから可胜なすべおのものを削陀したすデヌタベヌスの操䜜以䞋で詳しく説明したす、ネットワヌクの操䜜、デヌタのシリアル化ず逆シリアル化、画像の凊理、および怍字に関連する蚈算です。







アプリケヌションを起動するずき、たたはチャット画面を開くずき、バックグラりンドで重い操䜜を実行しおも、目に芋える遅延から私たちを救いたせん。 したがっお、組版などの䞀郚の操䜜は時間内に最適化する必芁がありたすが、他の操䜜はメッセヌゞを受信しお​​すぐに実行し、実行結果をデヌタベヌスにキャッシュするのが最適です。







ボトルネックのあるサヌドパヌティの゜リュヌションずラむブラリを遞択するずき、スピヌドずコンパクトさも考慮に入れようずしたした。 特に、それがMessagePackを遞択した理由でありiOSでは具䜓的に異なる実装のベンチマヌクを䜜成したした、デヌタをオブゞェクトにマッピングするラむブラリをMantleからYYModelに倉曎し、トラフィックを圧瞮するアルゎリズムずしおlz4で停止したした 。







さらに、 スムヌズなむンタヌフェむスを実珟するために、レンダリングを症候的に最適化したす。









すべおのリストには、自動レむアりトのない手動レむアりトがありたす。 自動レむアりトも倧奜きで、コヌドでMasonryを䜿甚した宣蚀型レむアりトを䜿甚しおいたすが、適切な堎合にのみ䜿甚したす。







オフラむンで悪いむンタヌネットで䜜業する



ネットワヌクを䜿甚する堎合、高速でコンパクトなプロトコルずアグレッシブなキャッシュを遞択するこずにより、トラフィックず遅延を最小限に抑えようずしたす。







サヌバヌず通信する方法ずしお、TCP゜ケットずバむナリプロトコルのみを䜿甚したす。 これにより、サヌバヌから曎新をリアルタむムで受信するこずず、より䜿い慣れた「芁求/応答」モヌドで䜜業するこずができたす。







API自䜓、぀たり䜎レベルプロトコルの䞊にある䞀連のコマンドは、将来、別のトランスポヌトの䞊、たずえばWeb゜ケットに実装できたす。 これらすべおにより、アプリケヌションの䞊䜍レベルのロゞックに觊れる必芁はありたせん。







画像







パッケヌゞ自䜓は、サヌビスコヌドコマンドコヌド、プロトコルバヌゞョン、ペむロヌド長を含む固定長ヘッダヌで構成されおいたす。 芁求ぞの応答は異なる順序で送られ、サヌバヌコマンドず混合される可胜性があるため、ヘッダヌに芁求ず応答をリンクできるシヌケンス番号がありたす。







ペむロヌドの圢匏ずしお、メッセヌゞパックを詊すこずにしたした。 回路の難しいタスクを必芁ずせず、非垞にコンパクトで、倚くのプラットフォヌム甚の非垞に気の利いたシリアル化ラむブラリを備えおいたす。 実際、これはJSONの効果的なバむナリアナログです。 トラフィックの消費をさらに削枛するために、lz4アルゎリズムでペむロヌドを圧瞮したす。 たた、その速床ずCPUおよびバッテリヌの軜負荷のために遞択したした。







䞍良ネットワヌクでのアプリケヌションの正垞な動䜜を保蚌する䞻な方法の1぀は、 オフラむンサポヌトを最倧化するこずです。 アプリケヌションは最倧デヌタをキャッシュし、同期に費やす時間ずトラフィックを枛らし、接続が衚瀺されるたでコマンドの送信を遅らせるこずができる必芁がありたす。 さらに、次にアプリケヌションを起動したずきにも接続が返される堎合がありたす。぀たり、送信䞭のすべおの保留䞭のタスクはデヌタベヌスに保存できるはずです。







接続埌、クラむアントは認蚌を行うず同時に、重芁なデヌタ蚭定、連絡先のリスト、最新のメッセヌゞずのチャットを芁求したす。 最埌の曎新のタむムスタンプをサヌバヌの時間枠に保存し、それをリク゚ストに枡し、実際に倉曎されたもののみを取埗したす。 接続が確立されるず、新しいメッセヌゞや連絡先デヌタの倉曎など、リアルタむムの曎新を受信できたす。







チャット履歎はもう少し耇雑です。 すべおのチャットの履歎党䜓を事前にアップロヌドするのは無意味ですが、䞀床埗たのはキャッシュしお、もう聞かないようにするこずです。 チャット履歎のどのセクションがキャッシュされおいるかを芋るず、履歎に「ギャップ」があるこずがわかりたす。 たずえば、ログむン埌にチャットリストを曎新するず、チャットの最埌のメッセヌゞが倉曎されたこずがわかりたした。 同時に、前のセッションでキャッシュされたチャット履歎のセクションたたはいく぀かのセクションがデヌタベヌスにありたす。 さらに、最埌のチャットメッセヌゞず以前にキャッシュされたメッセヌゞの間にサヌバヌ䞊にあるメッセヌゞの数がわからないため、耇雑さが増したす。







したがっお、メッセヌゞ自䜓に加えお、連続した履歎に関するメタデヌタキャッシュしたチャンクを保存したす。 チャットをスクロヌルするずき、この情報を䜿甚したす。デヌタベヌスから次のペヌゞをロヌドするか、サヌバヌにリク゚ストを送信するかを決定するのに圹立ちたす。 たたは倚分䞡方を行いたす。 サヌバヌから履歎の新しいセクションを受信するず、これらのチャンクはサむズを倉曎しお互いにマヌゞしたす受信した履歎のセクションがデヌタベヌスで䜿甚可胜な2぀の異なるチャンクを接続しおいるこずをクラむアントが理解しおいる堎合。







倚くの操䜜をオフラむンで実行できるため、タスクを保存するメカニズムを開発したした。 圌は、タスクを実行する方法、タスクの完了を埅぀方法、デヌタベヌスにステヌタスを保存する方法、たたはアプリケヌションの起動時にロヌドしお実行する方法を知っおいたす。







タスクはデヌタベヌスに保存でき、実行ロゞック党䜓をカプセル化したす。 他のタスクやアプリケヌションの状態ぞの䟝存関係は非垞に耇雑になる可胜性があるため、それらの远跡もタスク自䜓に実装されたす。 たずえば、写真付きのメッセヌゞを送信するタスクは、写真が凊理され、CDNにアップロヌドされおいるこずを確認しこのため、個別のタスクが責任を負いたす、ネットワヌク接続を埅機し必芁な堎合、メッセヌゞのみを盎接送信しようずしたす。







スムヌズなアプリケヌション操䜜のための2぀のトリック



䜿いやすくスムヌズなむンタヌフェむスを䜜成できないシステムの制限を回避するために䜿甚したいく぀かのトリックに぀いお少しお話したす。 iOSアプリケヌションの䟋。







開発の難しさの1぀は、チャット内での無限スクロヌル、぀たり、チャットを䞊にスクロヌルするずきにナヌザヌに衚瀺されないメッセヌゞ履歎をロヌドするこずでした。 99の堎合、ナヌザヌはチャットの最䞋郚に䜍眮しおおり、叀いメッセヌゞを読むためにスクロヌルアップしたいず考えおいたす。 ここで、2぀の問題に盎面しおいたす。







たず、メッセヌゞリストの䞀番䞊に垞にぶ぀かり、数画面ごずにダりンロヌドを埅぀のは面倒です。 この問題を解決するのはそれほど難しくありたせんでした。ナヌザヌが䞀番䞊たでスクロヌルしお「ねじれ」が芋えるたで埅たなかったのですが、スクロヌル䞭であっおも事前にストヌリヌの前のペヌゞをリク゚ストしようずしたしたロヌカルキャッシュずサヌバヌの䞡方から。 キャッシュたたはクむック接続にメッセヌゞがある堎合、ナヌザヌは新しいメッセヌゞパックを衚瀺できるたでに最䞊郚たでスクロヌルする時間がありたせん。







2番目の問題はより深刻であるこずが刀明したした。メッセヌゞリストの先頭にそのようなペヌゞを挿入した埌UITableViewに基づいお䜜成、既にロヌドされたセクションのcontentOffsetがシフトし、スクロヌルが「ゞャンプ」したす。 もちろん、挿入されたペヌゞのサむズを蚈算しおcontentOffsetを元に戻すこずもできたすが、これはスクロヌルアニメヌションの急激な停止に぀ながり、ナヌザヌにずっおtheくお思いがけないものになりたす。 たずえば、KVOを介しおcontentSizeテヌブルを远跡するなど、さたざたな方法でこれを実行しようずしたしたが、垞に倱敗したした。UITableViewは、リストの最䞊郚に項目を远加できないだけです。







その結果、䞀連の詊行の埌、䞀皮の「ハック」を適甚するこずでこの問題を解決するこずができたした。.transformを䜿甚しおリストを䞊䞋逆にし、各セルを反察方向に回転したす。 ナヌザヌは䜕も気づきたせんが、contentOffsetは䞋からカりントされるようになり、叀いメッセヌゞを読み蟌んでも䜕の圱響もありたせん。







この゜リュヌションにはいく぀かの萜ずし穎がありたすが、それらを回避するこずもできたした。 たず、逆セルむンデックスをデヌタモデルのむンデックスに倉換する必芁がありたす。逆も同様です。 セクションが耇数ある堎合、蚈算は非垞に耇雑になるため、1぀に制限するこずをお勧めしたす。 もちろん、これによりフロヌティングセクションヘッダヌを䜿甚するこずはできたせん。これは、チャット画面で、たずえば履歎の日付ごずに区切り文字を衚瀺するのに圹立ちたす。 しかし、最終的にフロヌティングセパレヌタヌを手動で行うのはそれほど難しくないこずが刀明したした。







第二に、たれに、ゞェスチャを操䜜するずきなど、セル内の座暙を蚈算するのが難しい堎合がありたすが、すべおを解決するこずもできたす。 第䞉に、デヌタをロヌドするずきに問題が戻りたすが、スクロヌルダりンするずきにロヌドするこずは非垞にたれであるため、私たちにずっおそれほど倧きな問題ではありたせん。 この堎合、スクロヌル䞭にプリロヌドは行いたせんが、ナヌザヌがテヌブルの䞀番䞋たでスクロヌルしおからロヌドむンゞケヌタヌを衚瀺し、テヌブルを曎新しおcontentOffsetを倉曎するのを埅ちたす。







2぀目の問題は、アニメヌション化された非同期のリスト曎新です。 耇数の独立した曎新がほが同時に発生する堎合たずえば、履歎ペヌゞがチャットの䞊郚にロヌドされ、新しいメッセヌゞが䞋郚に到着する堎合、tableViewデリゲヌトによっお䜿甚されるデヌタは、前の曎新のアニメヌションが終了しおいなくおも倉曎できたす。







これにより、UITableViewが間違ったセルをレンダリングしたり、完党にクラッシュしたりする可胜性がありたす。これは、以前のハックを䜿甚した堎合に発生する可胜性がさらに高くなりたす。 もちろん、UITableViewで同期するreloadDataメ゜ッドを参照するこずもできたすが、これは点滅、スクロヌルの停止、その他のナヌザヌの迷惑に぀ながりたす。







特にそのような堎合には、そのような曎新の順次凊理のために別のキュヌを䜜成したした。 すべおのモデル倉曎ずUIでのマッピングは、キュヌに入れられたブロック内で行われたす。 この堎合、ブロックはアニメヌションたたはその他の非同期操䜜の開始時にキュヌをロックし、終了時にロックを解陀できたす。 したがっお、テヌブルに察するすべおの䜜業は順番に行われ、デヌタは前のアニメヌションが完了するたで倉曎されたせん。







持続性



iOSクラむアントでデヌタをキャッシュするには、YapDatabaseラむブラリを䜿甚したす 。







YapDatabaseは、非垞に倚くの機胜セットを備えたSQLite䞊のKey-Valueリポゞトリです。 このラむブラリは、CoreDataよりもはるかにシンプルで柔軟性がありたす。 ここでは、デヌタベヌス内のオブゞェクトをシリアル化するメカニズムを遞択できたす。デフォルトではNSCodingであり、同じMessagePackを䜿甚したす。







YapDatabaseは、基本クラスからのオブゞェクトの継承やプロトコルの実装を必芁ずせず、オブゞェクトをコンテキストにバむンドしたせん。 読み取りおよび曞き蟌みは、同期トランザクションたたは非同期トランザクションを䜿甚しお実行されたす。







たた、拡匵システムの助けを借りお、「実際の」デヌタベヌスず同じすべおの機胜を䜿甚できたす。任意のSQLク゚リずいく぀かのフィヌルドのむンデックス䜜成、フルテキスト怜玢、倉曎ぞのサブスクリプションNSFetchedResultsControllerなど、プラグむン暗号化、CloudKitでの䜜業などHello-worldここでデヌタベヌスを操䜜する䟋は瀺したせん。それらはgithubのwikiにありたす 。







私の奜みでは、YapDatabaseはコヌドの生産性ずわかりやすさを向䞊させたすが、私の同僚の䜕人かはそれをあたり奜きではありたせん。 そしお、それらを理解するこずができたす。CoreDataを長時間䜿甚した埌、YapDatabaseに切り替えるには、脳を少し回転させる必芁がありたす。







さらに、耇数の接続を介しおデヌタベヌスを非同期で操䜜する堎合、デヌタベヌスが1぀たたは異なる接続を介しお䞊列読み取りおよび曞き蟌み芁求を凊理する方法を理解する必芁がありたす。 たた、オブゞェクトはデヌタベヌス党䜓で曎新されるこずも忘れないでください。 少し前に読んで倉曎したむンスタンスを保存するこずはできたせん。 デヌタベヌスからオブゞェクトを読み取り、必芁に応じお倉曎し、単䞀のトランザクションで曞き戻す必芁がありたす。 そうしないず、誀っお叀いデヌタをデヌタベヌスに曞き蟌む可胜性がありたす。







䞀般に、デヌタベヌスの操䜜は、コヌドを蚘述するリアクティブスタむルに非垞に䟿利に統合されおいたす。 非同期トランザクションテンプレヌト個々のオブゞェクトの読み取り/曞き蟌み/倉曎は、たずえばReactiveCocoaシグナルでラップするのが非垞に簡単で、ネットワヌク芁求を送信および凊理する1぀のチェヌンでデヌタベヌスず䜜業を統合したす。







アプリケヌションアヌキテクチャ



アヌキテクチャに぀いおはあたり觊れたせんが、そのゞャンルの法則に぀いおは觊れたせん。 MVVMに関する倚くのレポヌトず蚘事が既にありたすたずえば、Objective-C b RACのバヌゞョンの叀兞的なチュヌトリアル パヌト1 、 パヌト2 、たたはSwiftのこのパタヌンの実装に関する蚘事 。







ViewModelsレむダヌの䞋には、ビゞネスロゞック、プロトコルロゞック、およびキャッシングを実装するおよび可胜であればカプセル化するサヌビスのセットがありたす。 アプリケヌション内のナビゲヌションは、いわゆるルヌタヌ、぀たり画面を開くために必芁なコヌドをカプセル化するオブゞェクトを䜿甚しお実行されたす。 実際、ルヌタヌは非垞に倪ったゎッドオブゞェクトになる傟向があるため、プロセスには耇数のルヌタヌがありたした。 したがっお、可胜な限り、それを分解しようずしたす。 たずえば、個別のルヌタヌがナヌザヌ登録/認蚌プロセス党䜓を担圓したす。







以前のプロゞェクトの経隓から、䟝存性泚入はアプリケヌションの構造を倧幅に簡玠化し、アヌキテクチャの倉曎を倧幅に促進するこずがわかっおいたす。 最初はDIにTyphoonフレヌムワヌクを䜿甚したしたが、アプリケヌションの起動時間の最適化䞭に、䟝存関係の解決にはアプリケヌションの起動に蚱容できないほど長い時間がかかるこずがわかりたした匱いデバむスでは数秒単䜍。 したがっお、プロパティベヌスの泚入を介しお手動DIに切り替えたした。 これ以䞊のコヌドがあるずは蚀いたせん。アプリケヌションのサヌビスのレベルは通垞1぀のクラスで構成され、サヌビスの構成党䜓が読みやすいです。 もちろん、共有拡匵機胜ずimessage拡匵機胜の堎合、サヌビスは個別に蚭定されたす。この堎合、必芁なサヌビスははるかに少ないためです。







したがっお、コヌドの䞀貫性は圓初それほど倧きくなく、開発の開始からかなり長い時間が経過した埌でも、メッセンゞャヌの内郚ロゞックのほずんどを実装する別のラむブラリより正確には、ラむブラリのセットに䞀郚のサヌビスずサヌビスコヌドを簡単に転送できたした。プロトコルの凊理ずキャッシュを含み、他のアプリケヌションに組み蟌むこずができたす。







おわりに



アプリケヌションのパフォヌマンスたたはオフラむンでの䜜業-私たちにずっお、これはトレンドになりたいずいう願望ではなく、特定のナヌザヌにコミュニケヌションをずるための䟿利な機䌚を提䟛する実際の方法です。 高䟡なモバむルトラフィックたたは単に悪いむンタヌネットを持っおいる人。 そしお、これはうたくいくためのかなり深刻な動機です。 結果ずしお、評䟡するのはナヌザヌ次第です。メッセンゞャヌをむンストヌルし、コメントでフィヌドバックを共有するこずをお勧めしたす。 私は質問に答えおうれしいです。








All Articles