Gofor iOSのGopherフィヌドリンゎたたは効果的なバック゚ンド


玄束どおり、バック゚ンドをGoに移行し、クラむアントのビゞネスロゞックの量を3分の1以䞊削枛する方法に぀いお話したした。


察象者 小芏暡䌁業、囲and、モバむル開発者、およびこのトピックに興味を持っおいる、たたは興味を持っおいるすべおの人。
䜕に぀いお Goぞの移行の理由、遭遇した困難、モバむルアプリケヌションずそのバック゚ンドのアヌキテクチャを改善するための手順ずヒント。
レベル ゞュニアおよびミドル。



長い間、モバむル開発アりト゜ヌシングのチヌムは、独自のバック゚ンド開発者がいるサヌドパヌティのプロゞェクトに取り組み、特定の補品の請負業者ずしお行動したした。 契玄には垞にモバむル開発者ずしお音楜ずAPIが必芁であるず明蚘されおいるずいう事実にもかかわらず、これは必ずしも助けにはなりたせんでした。



必ずしもそうではないので、最近、自分の魂を傷぀けるような状況の小さなコレクションを䜜成したした。それを過去の蚘事の1぀でアップロヌドしたした。


そのため、チヌムにかなり匷力なJavaSpring開発者がいたため、新しい顧客ごずにしっかりず発衚するこずにしたした。 最初、圌らはそのような原則的な䜍眮が私たちを远い払うこずを恐れおいたした、そしお、結局私たちはパンず氎で裞のたたでいるでしょう。 しかし、刀明したように、亀枉の段階で誰かがすでに私たちを気に入っおいお、圌らが私たちず協力したいなら、ほずんどすべおが合意できたす。 クラむアントが既にチヌム内に自分のスタッフを持っおいる堎合でも、最初に䜿甚する予定でした。 次に、マむクロサヌビスなどのスマヌトワヌドず、モバむルアプリケヌション専甚のタスクを実行するビゞネスロゞックを備えた別のサヌバヌを実行できるこずを孊びたした。 このアプロヌチが垞に適切であるずは蚀いたせんが、これに぀いおはこれ以䞊説明したせん。


行く理由


いく぀かの成功したプロゞェクトの埌、Javaは私たちにずっお重すぎたした。 アプリケヌションにずっおすべおを可胜な限り䟿利にするために、倚くの時間がルヌチンに費やされたした。


䞀般にSpringずJavaに぀いお悪いこずを蚀いたくありたせん。それは巚倧な倪いスペむンのガレオン船のような深刻なタスクのための玠晎らしいツヌルです。 そしお、私たちは軜量の海賊クリッパヌのようなものを探しおいたした。


機胜をすばやく実装し、簡単に倉曎し、各状況で最適な゜リュヌションを探すために頭を枩める必芁はありたせんでした。 問題の兞型的な解決策を長時間グヌグルで調べたずきにどのように起こるかを知っおいるので、それが最も適切であり、そのうち10個のうち5個はすでに叀くなっおいたす。 そしお、倉数の名前の遞択に30分かかりたす。


Goにはそのような問題はありたせん。 すべおの蚀葉から。 時々、あなたは完璧な解決策を探しお座っおいたすが、StackOverflowはこれに答えたす。「たあ、はい、forルヌプで、䜕を埅っおいたしたか」


時間が経぀に぀れお、あなたはそれに慣れお、あらゆる皮類のささいなこずを無料でグヌグルで止めたすが、頭をオンにしおコヌドを曞くだけです。


難しさは䜕ですか


そもそも、継承はありたせん。 最初は脳を運んでいたした。 あなたはOOPのあなたの党䜓の考えを砎り、 アヒルタむピングに慣れなければなりたせん。 簡単に蚀えば、アヒルのように芋え、アヒルのように泳ぎ、アヒルのように鳎くなら、これはアヒルかもしれたせん。


実際、むンタヌフェむスの継承のみがありたす。


そしお第二に、重倧な䞍利な点-少数の既補ツヌル、しかし倚くのバグ。 倚くのこずを通垞の方法で行うこずはできたせん。たた、䞀般にクラスずしお䜕かが欠けおいたす。 たずえば、IoC 䟝存関係の逆転 の通垞のフレヌムワヌクはありたせん。 経隓豊かなホリネズミは、Facebookからのlibがあるず蚀うでしょう。 でも、料理の仕方がわからないだけなのかもしれたせんし、それでもその䟿利さは実際には倚くのこずが望たれおいたす。 単玔にSpringず比范するこずはできないため、手で倚くの䜜業を行う必芁がありたす。


Go党䜓のもう1぀の小さな制限は、たずえば、次の圢匏のAPIを䜜成しないこずです。


/cards/:id /cards/something 

既存のhttpルヌタヌの堎合、これらは盞互に排他的な芁求です。 ワむルドカヌド倉数ず䜕かの特定のアドレスの間で混乱したす。 愚かな制限ですが、あなたはそれに耐えなければなりたせん。 誰かが解決策を知っおいれば、私は聞いおうれしいです。


たた、冬眠や倚かれ少なかれ適切な類䌌䜓はありたせん。 はい、倚くのORMがありたすが、それらのすべおは今のずころかなり匱いです。 Goの開発䞭に芋た䞭で最高のものはgormです。 その䞻な利点は、ベヌスから構造ぞの応答の最も䟿利なマッピングです。 疑わしい動䜜のデバッグに長時間を費やしたくない堎合は、ベアSQLでク゚リを蚘述する必芁がありたす。


PS このlibを䜿甚するプロセスで発生した回避策を個別に共有したいず思いたす。 通垞の構造ではなくgormを䜿甚しお倉数に挿入した埌にidを曞き蟌む必芁がある堎合は、次の束葉杖が圹立ちたす。 リク゚ストレベルで、id以倖に戻る結果の名前を倉曎したす。


 ... returning id as value 

倉数ぞの埌続のスキャンで


 ... Row().Scan(&variable) 

事実は、idフィヌルドがオブゞェクトの特定のフィヌルドずしおgormによっお認識されるこずです。 そしお、それを解き攟぀には、リク゚ストレベルで別の名前に倉曎する必芁がありたす。


長所、たたはなぜGoで曞くのか


゚ントリヌのしきい倀から始めたいず思いたす。それは最小限です。 同じ春がどのようなガラガラになったのかを芚えおおくず、Goはそれず比范しお、ゞュニアクラスで教えるこずができるので、ずおも簡単です。


そしお、この単玔さは、蚀語だけでなく、それが持぀環境にもありたす。 gradleずmavenで長いマナを読む必芁はありたせん。すべおが少なくずも1回だけ開始されるように長い蚭定を曞く必芁はありたせん。 ここでは、いく぀かのチヌムがすべおを管理し、䟡倀のあるコレクタヌずプロファむラヌはすでに蚀語の䞀郚であり、開始するために詳现な調査を必芁ずしたせん。
圌らが蚀うように習埗しやすく、習埗しにくい。 これは私が個人的に垞に珟代の技術に欠けおいたものです。人々のために䜜られたものではないようです。


これから開発スピヌドが続きたす。 蚀語は1぀の目的のために䜜られたした



本質的に、それはビゞネスのバック゚ンド蚀語です。 それは高速で、シンプルであり、耇雑な問題を理解可胜な方法で解決するこずができたす。 耇雑なタスクず理解床に関しおは、Goにはgoroutinkiやチャンネルなどのクヌルなものがあるため、これは議論のための別のトピックです。 これは、自分の足で撃぀機䌚が最小限の、最も䟿利なマルチスレッドです。


建築


Web


Webフレヌムワヌクずしお、 Ginを遞択したした。 ただRevelがありたすが、私たちにはあたりにも狭く、そのパラダむムを揺るぎなく口述しおいるように芋えたした。 柔軟性を持たせるために、もう少し自由な手をお勧めしたす。


Ginは、䟿利なAPIず䞍必芁な耇雑さの欠劂に魅了されたした。 圌の入堎閟倀は非垞に䜎いです。 ずおも倚くのこずで、研修生は1日で文字通りそれを理解したした。 単に混乱する堎所はありたせん。 䞀目で必芁なすべおの機胜。


もちろん、圌は問題がないわけではありたせん。 キャッシュなどのいく぀かの決定は、サヌドパヌティによっお行われたす。 たた、githubを介したむンポヌトの䜿甚に慣れおいる堎合、むンポヌトの競合があり、gopkgを介しおむンポヌトを行った堎合、たたはその逆も同様です。 その結果、2぀のプラグむンは単玔に盞互排他的になりたす。
誰かがこの問題の解決策を知っおいるなら、コメントに曞いおください。


䟝存関係マネヌゞャヌ


長い間曞きたせんが、これは間違いなくグラむドだずすぐに蚀いたす。 gradleたたはmavenを䜿甚したこずがある堎合は、特定のファむル内の䟝存関係宣蚀のパラダむムに粟通しおいるので、必芁に応じおそれらを埌で䜿甚できたす。 したがっお、GlideはハムスタヌGradleであり、玛争解決やその他の利点がありたす。


ちなみに、テスト䞭に問題が発生した堎合、各フォルダヌをテストしおベンダヌフォルダヌにテストクロヌルするず、問題は簡単に解決されたす。


 go test $(glide novendor) 

このオプションは、ベンダヌフォルダヌをテストから陀倖したす。 glide.yamlおよびglide.lockファむルをリポゞトリ自䜓に入れるだけで十分です。


これはモバむル開発には䞀切圹立ちたせんが、知っおいるだけです


ORMずレルム


これは、バック゚ンドからクラむアントぞのデヌタの転送ず保存に関する膚倧なセクションになりたす。 Goから始めお、モバむルプラットフォヌムにシヌムレスに移行したす。


そしお、Realmずは䜕ですか、なぜCoreData / Arrays / SQLiteよりも優れおいるのですか

Realmに遭遇したこずがなく、それが䜕であるかを理解しおいない堎合、スポむラヌを正しく開きたした。


レルムは、アプリケヌション党䜓でのデヌタ同期の䜜業を容易にするモバむルデヌタベヌスです。 オブゞェクトがただどこにも保存されおいない堎合でも、垞にコンテキストで䜜業する必芁があるCoreDataのような問題はありたせん。 䞀貫性を維持する方が簡単です。
゚ンティティを䜜成し、通垞のオブゞェクトずしお操䜜し、フロヌ間で転送し、奜きなようにゞャグリングするだけで十分です。


圌女はあなたのために倚くの操䜜を行いたすが、もちろん、いく぀かの間違いもありたす。䞀般的に、倧文字ず小文字を区別しない怜玢はありたせん。など。


これらの問題に耐える䟡倀があり、䟡倀があるず考えたした。


自分自身を繰り返さないために、 Gormをormずしお䜿甚し、いく぀かの掚奚事項を瀺したす。



おそらく、これはすべおの技術に圓おはたりたす。ここでは、私は少しスカニタニルですが、それでもです。 繰り返したすが、リコヌルは傷぀きたせんが、重芁です。


次に、モバむルアプリケヌションに぀いお説明したす。 䞻なタスクは、ク゚リで返されるフィヌルドがクラむアント䞊の察応するフィヌルドず同じ名前になるようにするこずです。 これは、いわゆるタグを䜿甚しお簡単に実珟できたす。




jsonタグの名前が正しいこずを確認しおください。 そしお、䟋のように、圌は陀倖フラグを蚭定しおおくこずが望たしいです。 これにより、空のフィヌルドで応答が乱雑になるのを防ぎたす。


なぜ行くの

正しい質問をするこずができたす。同じ名前を任意の蚀語で䜜成できる堎合、Goはそれず䜕をする必芁がありたすか そしお、あなたは正しいでしょうが、Goの利点の1぀は、リフレクションず構造を䜿甚した最も簡単な曞匏蚭定です。 倚くの蚀語にはリフレクションがありたすが、Goを䜿甚するのが最も簡単な方法です。


ずころで、答えから空の構造を非衚瀺にする必芁がある堎合、最良の方法は、構造のMarshalJSONメ゜ッドをオヌバヌロヌドするこずです。


 // ,     Pharmacy   Object func (r Object) MarshalJSON() ([]byte, error) { type Alias Object var pharmacy *Pharmacy = nil //  id != 0,   .   -  nil if r.Pharmacy.ID != 0 { pharmacy = &r.Pharmacy } return json.Marshal(&struct { Pharmacy *Pharmacy `json:"pharmacy,omitempty"` Alias }{ Pharmacy: pharmacy, Alias: (Alias)(r), }) } 

倚くは気にせず、倀の代わりに構造䜓にポむンタヌをすぐに曞き蟌みたすが、これはGoの方法ではありたせん。 Goは䞀般に、必芁のないポむンタヌを奜たない。 これにより、コヌドを最適化し、その可胜性を最倧限に掻甚するこずができなくなりたす。


フィヌルド名に加えお、そのタむプにも泚意しおください。 数字は数字でなければならず、行は行thanks、capでなければなりたせん。 日付に関しおは、RFC3339を䜿甚するのが最も䟿利です。 サヌバヌでは、オヌバヌロヌドを介しお日付をフォヌマットするこずもできたす。


 func (c *Comment) MarshalJSON() ([]byte, error) { type Alias Comment return json.Marshal(&struct { CreatedAt string `json:"createdAt"` *Alias }{ CreatedAt: c.CreatedAt.Format(time.RFC3339), Alias: (*Alias)(c), }) } 

クラむアントでは、これは次のパタヌンを䜿甚しお日付をフォヌマットするこずにより行われたす。


 "yyyy-MM-dd'T'HH:mm:ssZ" 

RFC3339のもう1぀の利点は、Swaggerのデフォルトの日付圢匏ずしお機胜するこずです。 たた、この方法でフォヌマットされた日付自䜓は、特にPOSIX時間ず比范した堎合、人間にずっお非垞に読みやすいものです。


䞀方、クラむアントではiOSの䟋ですが、Androidでも同様です、すべおのフィヌルドずクラスの関係の名前が完党に䞀臎するため、1぀の汎甚メ゜ッドを䜿甚しお保存を実行できたす。


 func save(dictionary: [String : AnyObject]) -> Promise<Void>{ return Promise {fulfill, reject in let realm = Realm.instance //       ,       . //          . try! realm.write { realm.create(T.self, value: dictionary, update: true) } fulfill() } } 

配列の堎合も状況は䌌おいたすが、保存は既にルヌプ内で実行される必芁がありたす。 倚くの堎合、経隓のない開発者は間違いを犯し、曞き蟌みブロック党䜓をルヌプでラップしたす。


 array.forEach { object in try! realm.write { realm.create(T.self, value: object, update: true) } } 

これは、すべおを䞀括しお保存するのではなく、各オブゞェクトの新しいトランザクションを開く方法であるため、根本的に間違っおいたす。 たた、曎新の通知を接続しおいる堎合、すべおがさらに楜しくなりたす。 トランザクションを次のレベルに匕き䞊げお、次のようにする方がより正確です。


 try! realm.write { array.forEach { object in realm.create(T.self, value: object, update: true) } } 

ご芧のずおり、マッピングを担圓する䞭間局は完党に萜ちおいたす。 デヌタが十分に準備できたら、远加の凊理を行わずにすぐにデヌタベヌスに取り蟌むこずができたす。 たた、バック゚ンドが優れおいればいるほど、この䜙分な凊理は少なくなりたす。 理想的には、日付をオブゞェクトに倉換するだけです。 それ以倖はすべお事前に行う必芁がありたす。


ちなみに、トピックから少し離れおいたす。 クラむアントに氞続的なデヌタベヌスを甚意する必芁がない堎合、これはレルムを攟棄する理由にはなりたせん。 RAM内で厳密に䜜業を行うこずができ、コンテンツをオンデマンドでリセットできたす。


→ iOSおよびAndroidのリンク。


このアプロヌチにより、䞊蚘のリアクティブデヌタベヌスずマッピングのすべおの利点を掻甚できたす。


たた、詳现に特に泚意を払っおいる人のために付け加えたいず思いたす。ここでは、Goが唯䞀の正しい゜リュヌションであり、モバむル開発の䞇胜薬であるずいう声明はありたせん。 誰もが独自の方法でこの問題を解決できたす。 このパスを遞択したした。


Project Goの構造


これで、Go開発者向けのコヌドが倚くなりたす。 あなたがモバむル開発者であれば、次のセクションに自由にスクロヌルできたす。


あなたが囲developer開発者である堎合、今私たちは最も興味深いこずになりたす。 兞型的なアプリケヌションのバック゚ンドを䜜成しおいるず仮定したす。RESTAPI、いく぀かのビゞネスロゞック、モデル、デヌタベヌスロゞック、ナヌティリティ、移行スクリプト、リ゜ヌスの蚭定を含むレむダヌがありたす。 どういうわけか、クラスずパパのためにプロゞェクトでこれらすべおを調敎し、 SOLIDの原則を守り、できればそれに倢䞭にならないようにする必芁がありたす。


これたでのずころ、私たちはそれを抜象的に投げおおり、深く朜り蟌むのではなく、党䜓的な構造が理解されるようにしおいたす。 興味深い堎合は、これを本栌的な別の資料に充おたす。 それでも、Goず連携したモバむルアプリケヌションに぀いお話しおいるずころです。


私の声明で独断的であるふりをしないようにすぐに予玄しおください。誰もが自分のプロゞェクトに合うように自由に仕事をするこずができたす。


構造のスクリヌンショットから始めたしょう。



Intellij Ideaのハムスタヌはどれくらいかわいいでしょう觊るたびに


非展開ディレクトリには、Goファむルたたはリ゜ヌスファむルが䞀床に含たれたす。 簡単に蚀えば、すべおが開かれお最倧限の没入感が埗られたす。


この蚘事では、API、サヌビス、デヌタベヌスの操䜜、およびそれらが盞互にどのように䟝存しおいるかに぀いお、ビゞネスロゞックの責任に぀いおのみ説明したす。 芪愛なる皆さんがこのトピックに興味を瀺したら、1぀の蚘事には情報が倚すぎるので、残りを曞きたす。


だから、順番に


Web


リク゚ストの凊理を担圓するものはすべお、Webに保存されたすバむンダヌ、フィルタヌ、コントロヌラヌ-すべおのはんだ付けはapi.goで行われたす。 そのような結合の䟋


 regions := r.Group("/regions") regions.GET("/list", Cache.Gin, rc.List) regions.GET("/list/active", Cache.Gin, regionController.ListActive) regions.GET("", binders.Coordinates, regionController.RegionByCoord) 

コントロヌラヌの初期化ず䟝存関係の泚入がそこで行われたす。 実際、 api.goファむル党䜓は、ルヌタヌが圢成および開始されるRunメ゜ッドず、すべおの䟝存関係ずそのグルヌプを持぀コントロヌラヌを䜜成するための補助メ゜ッドのヒヌプで構成されおいたす。


Web。バむンダヌ


バむンダはバむンダフォルダにあり、ク゚リからパラメヌタを解析し、䟿利な圢匏に倉換し、さらに䜜業するためにコンテキストにドロップしたす。


このパッケヌゞのメ゜ッドの䟋。 ク゚リからパラメヌタヌを受け取り、boolに倉換しおコンテキストに入れたす。


 func OpenNow(c *gin.Context) { openNow, _ := strconv.ParseBool(c.Query(BindingOpenNow)) c.Set(BindingOpenNow, openNow) } 

゚ラヌ凊理のない最も簡単なオプション。 わかりやすくするために。


Web.Controllers


通垞、コントロヌラヌのレベルでは、ほずんどの間違いを犯したす。䜙分なロゞックをプッシュし、むンタヌフェむスず分離を忘れおから、䞀般に関数型プログラミングにスラむドしたす。 䞀般的に、Goでは、コントロヌラヌはiOSず同じ病気に苊しんでいたす。コントロヌラヌは垞に過負荷になっおいたす。 したがっお、実行するタスクをすぐに決定したす。



兞型的なコントロヌラヌの䟋を芋おみたしょう。


むンポヌトを省略した堎合、クラスはコントロヌラヌむンタヌフェむスで始たりたす。 はい、はい、垞に1぀の実装しかない堎合でも、SOLIDずいう単語の文字「D」を確認したす。 これにより、テストが非垞に簡単になり、コントロヌラヌ自䜓をモックに眮き換えるこずができたす。


 type Order interface { PlaceOrder(c *gin.Context) AroundWithPrices(c *gin.Context) } 

次に、コントロヌラヌ構造自䜓ずそのコンストラクタヌがありたす。これは、 api.goでコントロヌラヌを䜜成するずきに呌び出す䟝存関係を考慮したす。


 //   ,      type order struct { service services.Order } func NewOrder(service services.Order) Order { return &order { service: service, } } 

そしお最埌に、リク゚ストを凊理するメ゜ッド。 レむダヌをバむンダヌで正垞に枡したので、すべおのパラメヌタヌがあるこずが保蚌され、パニック攻撃を恐れるこずなくMustGetを䜿甚しおパラメヌタヌを取埗できたす。


 func (o order)PlaceOrder(c *gin.Context) { m := c.MustGet(BindingOrder).(*model.Order) o.service.PlaceOrder(m) c.IndentedJSON(http.StatusCreated, gin.H { "identifier": m.ID, }) } 

オプションのパラメヌタヌを䜿甚した同じストヌリヌですが、バむンダヌレベルでのみ、れロ倀を蚭定する䟡倀がありたす。コントロヌラヌでチェックむンし、デフォルト倀を眮き換えるか、単に無芖したす。


サヌビス


サヌビスの状況はほずんど同じです。たた、サヌビスはむンタヌフェヌス、構造、コンストラクタヌで始たり、その埌に䞀連のメ゜ッドが続きたす。 1぀の詳现に焊点を圓おたいず思いたす-これがデヌタベヌスを操䜜する原則です。


サヌビスのコンストラクタは、それが動䜜する䞀連のリポゞトリずトランザクションファクトリを考慮する必芁がありたす。


 func NewOrder(repo repositories.Order, txFactory TransactionFactory) Order { return &order { repo: repo, txFactory: txFactory } } 

トランザクションファクトリはトランザクションを生成する単なるクラスであり、耇雑なものはありたせん。


 type TransactionFactory interface { BeginNewTransaction() Transaction } 

gormの完党な工堎コヌド
 type TransactionFactory interface { BeginNewTransaction() Transaction } type transactionFactory struct { db *gorm.DB } func NewTransactionFactory(db *gorm.DB) TransactionFactory { return &transactionFactory{db: db} } func (t transactionFactory)BeginNewTransaction() Transaction { tx := new(transaction) tx.db = t.db tx.Begin() return tx } 

しかし、トランザクション自䜓で停止する䟡倀がありたす。 そもそも、それは䜕に぀いおですか。 トランザクションは実装ず同じむンタヌフェヌスであり、トランザクションの開始、完了、ロヌルバック、および以䞋の゚ンゞンレベルの実装ぞのアクセスのためのメ゜ッドが含たれおいたす。


 type Transaction interface { Begin() Commit() Rollback() DataSource() interface{} } 

gormの完党なトランザクションコヌド
 type Transaction interface { Begin() Commit() Rollback() DataSource() interface{} } type transaction struct { Transaction db *gorm.DB tx *gorm.DB } func (t *transaction)Begin() { t.tx = t.db.Begin() } func (t *transaction)Commit() { t.tx.Commit() } func (t *transaction)Rollback() { t.tx.Rollback() } func (t *transaction)DataSource() interface{} { return t.tx } 

begin 、 commit 、 rollbackですべおをクリアする必芁がある堎合、Datasourceは䜎レベルの実装にアクセスするための単なる束葉杖です。Goのデヌタベヌスでの䜜業は、トランザクションが倉曎された蚭定を持぀デヌタベヌスぞのアクセサヌの単なるコピヌになるように蚭蚈されおいるためです 埌でリポゞトリで䜜業するずきに必芁になりたす。


実際、これはサヌビスメ゜ッドでトランザクションを操䜜する䟋です。


 func (o order)PlaceOrder(m *model.Order) { tx := o.txFactory.BeginNewTransaction() defer tx.Commit() o.repo.Insert(tx, m) } 

トランザクションを開始し、デヌタベヌスにアクセスし、必芁に応じおコミットたたはロヌルバックしたした。


もちろん、トランザクションの利点はいく぀かの操䜜で特に明らかになりたすが、䟋のように1぀しかなくおも、これはそれほど悪くはなりたせん。


専門家に

分離レベルを制埡できないこずを知っおいたす。
ただ浅瀬を芋぀けたら-コメントに曞いおください。


埌茩ぞの远加のアドバむスずしお、できるだけ早く取匕を開始すべきだず蚀いたいです。 すべおのデヌタを準備しお、開始ずコミットの間に最小限のロゞックず蚈算ができるようにしたす。


トランザクションが開かれ、人々が喫煙しお、たずえばGoogleにリク゚ストを送信するこずが起こりたす。 そしお、圌らはなぜそれがすべおデッドロックで起こったのだろうず思いたす。


興味深い事実
珟代の倚くのデヌタベヌスでは、 デッドロックはできるだけ単玔に、タむムアりトによっお定矩されおいたす。 負荷が倧きい堎合、ブロックのためのリ゜ヌスのスキャンは高䟡です。 したがっお、代わりに通垞のタむムアりトがよく䜿甚されたす。 たずえば、 mysqlで 。 この機胜がわからない堎合は、最も玠晎らしい時間の楜しいデバッグを自分で行うこずができたす。

リポゞトリ


同じこずむンタヌフェヌス、構造、コンストラクタヌは、原則ずしお既にパラメヌタヌなしです。
サヌビスコヌドで呌び出した挿入操䜜の䟋を瀺したす。


 func (order)Insert(tx Transaction, m *model.Order) { db := tx.DataSource().(*gorm.DB) query := "insert into orders (shop_id) values (?) returning id" db.Raw(query, m.Shop.ID).Scan(m) } 

トランザクションから䜎レベルのアクセス修食子を受け取り、リク゚ストをコンパむルしお完了したした。 できた


これはすべお、アヌキテクチャを台無しにしないために十分なはずです。 少なくずも速すぎる。 ご質問や異議がある堎合は、コメントを曞いおください、私は議論しお喜んでいるでしょう。


アプリ


さお、ゎヌファヌはいいですが、今どのようにクラむアントず仕事をしおいたすか


Goの堎合ず同様に、スタックから始めたしょう。 䞀般的に、私たちはほがすべおの堎所で詊薬を積極的に䜿甚しおいたすが、ここでは、すぐに誰かの粟神を傷぀けないように、より穏やかなバヌゞョンのアヌキテクチャに぀いお説明したす。


スタック


ネットワヌク局 


SwiftプロゞェクトのAlamofireおよびObjective-CのAFNetworking 。


ずころで、AlamofireがAFNetworkingであるこずを知っおいたしたか AFNetworkingラむセンスを芋ればわかるように、 AFプレフィックスはAlamofireを意味したす。


短絡 


callback- / . , . , .


. iOS: PromiseKit . — , , , success/failure , always, , / . , .


, — . flow , . , , , :


 func details(id: Int) -> Promise<Void> { return getDetails(id) .then(execute: parse) .then(execute: save) } 

getDetails, :


 func getDetails(id: Int) -> Promise<DataResponse<Any>> { return Promise { fulfill, reject in Alamofire.request(NetworkRouter.drugDetails(id: id)).responseJSON { fulfill($0) } } } 

, . , . , . , .


 func parseAsDictionary(response: DataResponse<Any>) -> Promise<[String:AnyObject]> { return Promise {fulfill, reject in switch response.result { case .success(let value): let json = value as! [String : AnyObject] guard response.response!.statusCode < 400 else { let error = Error(dictionary: json) reject(error) return } fulfill(json) break case .failure(let nserror): let error = Error(error: nserror as NSError) reject(error) break } } } //     ,   func save(items: [[String : AnyObject]]) -> Promise<Int> { return Promise {fulfill, reject in let realm = Realm.instance try! realm.write { items.forEach { item in //       generic realm.create(Item.self, value: item, update: true) } } fulfill(items.count) } } 

, MVC, :


 _ = service.details().then {[weak self] array -> Void in // Success. Do w/e you like. } 

デヌタベヌス


, ORM Go-side, , . - , . , datasource . , .


fine-grained notifications , .


extra-
 class ViewController: UITableViewController { var notificationToken: NotificationToken? = nil override func viewDidLoad() { super.viewDidLoad() let realm = try! Realm() let results = realm.objects(Person.self).filter("age > 5") // Observe Results Notifications notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in guard let tableView = self?.tableView else { return } switch changes { case .initial: // Results are now populated and can be accessed without blocking the UI tableView.reloadData() break case .update(_, let deletions, let insertions, let modifications): // Query results have changed, so apply them to the UITableView tableView.beginUpdates() tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }), with: .automatic) tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}), with: .automatic) tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }), with: .automatic) tableView.endUpdates() break case .error(let error): // An error occurred while opening the Realm file on the background worker thread fatalError("\(error)") break } } } deinit { notificationToken?.stop() } } 


, ApiManager.swift . , , — extension ApiManager, .
singleton, . , , .


SOA (service oriented architecture). Rambler , , , .


. — . , . , viewDidLoad. , , . , , , , , .


:



, . , 200-300 . , , .


, : , . , .


おわりに


たずめるず。 Realm- mobile-side , . , -, . , iOS Android, — !


, . , , - .


. .


, . , , , , , , ? MVP MVVM , .


, , : “, ?” : “, .”
.


, , . , , .


PS . ? , , . , , , , .



Source: https://habr.com/ru/post/J331456/


All Articles