Skip to content

nikolajevs86/article-golang-di

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ΠœΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ DI ΠΈ ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π° прилоТСния Π² GO

Π•ΡΡ‚ΡŒ нСсколько Π²Π΅Ρ‰Π΅ΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π½ΠΈΠΌΠ°Ρ‚ΡŒΡΡ Π²Π΅Ρ‡Π½ΠΎ: ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° огонь, Ρ„ΠΈΠΊΡΠΈΡ‚ΡŒ Π±Π°Π³ΠΈ Π² лСгаси-ΠΊΠΎΠ΄Π΅ ΠΈ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒ ΠΎ DI - ΠΈ всё Ρ€Π°Π²Π½ΠΎ Π½Π΅Ρ‚-Π½Π΅Ρ‚, Π΄Π° ΠΈ Π±ΡƒΠ΄Π΅ΡˆΡŒ ΡΡ‚Π°Π»ΠΊΠΈΠ²Π°Ρ‚ΡŒΡΡ со странными зависимостями Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ. Π’ контСкстС языка GO, Π²ΠΏΡ€ΠΎΡ‡Π΅ΠΌ, ситуация Ρ‡ΡƒΡ‚ΡŒ слоТнСС, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ явно Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ ΠΈ всСми ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΠΎΠ³ΠΎ стандарта Ρ€Π°Π±ΠΎΡ‚Ρ‹ с зависимостями Π½Π΅Ρ‚ ΠΈ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΡ€ΡƒΡ‚ΠΈΡ‚ ΠΏΠ΅Π΄Π°Π»ΠΈ своСго собствСнного малСнького самоката - Π°, Π·Π½Π°Ρ‡ΠΈΡ‚, Π΅ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ ΠΎΠ±ΡΡƒΠ΄ΠΈΡ‚ΡŒ ΠΈ ΡΡ€Π°Π²Π½ΠΈΡ‚ΡŒ.

Π’ Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅ я Ρ€Π°ΡΡΠΌΠΎΡ‚Ρ€ΡŽ самыС популярныС инструмСнты ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹ для ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠΈ зависимостСй Π² go, с ΠΈΡ… прСимущСствами ΠΈ нСдостатками. Π’ случаС, Ссли Π²Ρ‹ Π·Π½Π°Π΅Ρ‚Π΅ Ρ‚Π΅ΠΎΡ€ΠΈΡŽ ΠΈ Π°Π±Π±Ρ€Π΅Π²ΠΈΠ°Ρ‚ΡƒΡ€Π° DI Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ Ρƒ вас вопросов (Π² Ρ‚ΠΎΠΌ числС ΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ примСнСния этого ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°), Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΡΡ‚Π°Ρ‚ΡŒΡŽ с сСрСдины, Π² ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π΅ я объясню, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ DI, Π·Π°Ρ‡Π΅ΠΌ это Π½ΡƒΠΆΠ½ΠΎ Π²ΠΎΠΎΠ±Ρ‰Π΅ ΠΈ Π² частности Π² Π³ΠΎ.

Π—Π°Ρ‡Π΅ΠΌ Π½Π°ΠΌ всё это Π½ΡƒΠΆΠ½ΠΎ

Π‘Ρ‚ΠΎΠΈΡ‚ Π½Π°Ρ‡Π°Ρ‚ΡŒ с Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π³Π»Π°Π²Π½Ρ‹ΠΉ Π²Ρ€Π°Π³ всСх программистов ΠΈ главная ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π° появлСния практичСски всСх инструмСнтов проСктирования - это ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ. Π’Ρ€ΠΈΠ²ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ случай всСгда понятСн, Π»Π΅Π³ΠΊΠΎ лоТится Π² Π³ΠΎΠ»ΠΎΠ²Ρƒ, ΠΎΡ‡Π΅Π²ΠΈΠ΄Π½ΠΎ ΠΈ изящно Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ ΠΎΠ΄Π½ΠΎΠΉ строчкой ΠΊΠΎΠ΄Π° ΠΈ с Π½ΠΈΠΌ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π±Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ. ИноС Π΄Π΅Π»ΠΎ, ΠΊΠΎΠ³Π΄Π° Π² систСмС дСсятки ΠΈ сотни тысяч (Π° ΠΈΠ½ΠΎΠ³Π΄Π° ΠΈ большС) строк ΠΊΠΎΠ΄Π°, ΠΈ Π²Π΅Π»ΠΈΠΊΠΎΠ΅ мноТСство β€œΠ΄Π²ΠΈΠΆΡƒΡ‰ΠΈΡ…ΡΡβ€ частСй, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΏΠ»Π΅Ρ‚Π°ΡŽΡ‚ΡΡ, Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΡƒΡŽΡ‚, Π΄Π° ΠΈ просто ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ Π² ΠΎΠ΄Π½ΠΎΠΌ тСсном ΠΌΠΈΡ€ΠΊΠ΅, Π³Π΄Π΅ каТСтся Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΌ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ, Π½Π΅ Π·Π°Π΄Π΅Π² ΠΊΠΎΠ³ΠΎ-Ρ‚ΠΎ локтями. Для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ слоТности чСловСчСство ΠΏΠΎΠΊΠ° Π½Π΅ нашло ΠΏΡƒΡ‚ΠΈ Π»ΡƒΡ‡ΡˆΠ΅, Ρ‡Π΅ΠΌ Ρ€Π°Π·Π±ΠΈΠ²Π°Ρ‚ΡŒ слоТныС Π²Π΅Ρ‰ΠΈ Π½Π° простыС, изолируя ΠΈΡ… ΠΈ рассматривая ΠΏΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ. ΠšΠ»ΡŽΡ‡Π΅Π²Π°Ρ Π²Π΅Ρ‰ΡŒ здСсь - это изоляция, ΠΏΠΎΠΊΠ° ΠΎΠ΄ΠΈΠ½ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π½Π΅ влияСт Π½Π° сосСдниС, ΠΌΠΎΠΆΠ½ΠΎ Π½Π΅ ΠΎΠΏΠ°ΡΠ°Ρ‚ΡŒΡΡ Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹Ρ… эффСктов ΠΈ нСявного воздСйствия ΠΎΠ΄Π½ΠΈΠΌ Π½Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ. Для обСспСчСния Ρ‚Π°ΠΊΠΎΠΉ изоляции ΠΌΡ‹ Ρ€Π΅ΡˆΠ°Π΅ΠΌ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ связи ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°, явно описав, ΠΎΡ‚ Ρ‡Π΅Π³ΠΎ ΠΈ ΠΊΠ°ΠΊ ΠΎΠ½ зависит. На этом ΠΌΠΎΠΌΠ΅Π½Ρ‚Π΅ ΠΌΡ‹ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΠΌ ΠΊ ΠΈΠ½ΡŠΠ΅ΠΊΡ†ΠΈΠΈ (ΠΈΠ»ΠΈ Π²Π½Π΅Π΄Ρ€Π΅Π½ΠΈΡŽ) зависимостСй, которая Π½Π° самом Π΄Π΅Π»Π΅ являСтся просто способом ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ (класс, структура, ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, etc.) Π±Ρ‹Π»ΠΈ доступны Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Π΅ΠΌΡƒ части прилоТСния, скрывая ΠΎΡ‚ Π½Π΅Π³ΠΎ всё излишнСС для Π΅Π³ΠΎ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈΠ»ΠΈ, цитируя википСдию: β€œDI - это процСсс прСдоставлСния внСшнСй зависимости ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠΌΡƒ компонСнту”.

Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ сразу нСсколько Π·Π°Π΄Π°Ρ‡:

  • Π‘ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ излишнСС, ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Ρ ΠΊΠΎΠ³Π½ΠΈΡ‚ΠΈΠ²Π½ΡƒΡŽ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ Π½Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°;
  • Π˜ΡΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹Π΅ ΠΏΠΎΠ±ΠΎΡ‡Π½Ρ‹Π΅ эффСкты (Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ, нСявноС влияниС ΠΎΠ΄Π½ΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π½Π° Ρ€Π°Π±ΠΎΡ‚Ρƒ Π΄Ρ€ΡƒΠ³ΠΈΡ…);
  • АбстрагируСт ΠΎΠ΄Π½ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈΡ…, позволяя Π»Π΅Π³ΠΊΠΎ ΠΈΡ… Π·Π°ΠΌΠ΅Π½ΡΡ‚ΡŒ, Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ;

ΠŸΡ€ΠΎ ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» ΠΈΠ»ΠΈ ΠΏΡ€ΠΈ Ρ‡Ρ‘ΠΌ Ρ‚ΡƒΡ‚ DI

КаТдоС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ Π΅Π³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ для осущСствлСния своСй ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… инфраструктурных Π·Π°Π΄Π°Ρ‡. Π­Ρ‚ΠΈ дСйствия ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ Π² нСсколько Ρ„Π°Π·:

  • Запуск - ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π΄ΠΎΠ»ΠΆΠ½ΠΎ запустится ΠΈ провСсти приготовлСния ΠΊ Ρ€Π°Π±ΠΎΡ‚Π΅: ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ доступ Π΄ΠΎ Π²Π½Π΅ΡˆΠ½ΠΈΡ… систСм, ΠΎΡ‚ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… зависит нСпосрСдствСнно (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π±Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ…), Π½Π°Ρ‡Π°Ρ‚ΡŒ ΡΠ»ΡƒΡˆΠ°Ρ‚ΡŒ ΠΏΠΎΡ€Ρ‚ ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅;
  • Π Π°Π±ΠΎΡ‚Π° - нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ осущСствляСт свою ΠΏΠΎΠ»Π΅Π·Π½ΡƒΡŽ Π΄Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ;
  • Π—Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹ - ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‰Π°ΡŽΡ‚ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ сигналы, Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°ΡŽΡ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ накопившиСся Π·Π°Π΄Π°Ρ‡ΠΈ, ΠΎΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°ΡŽΡ‚ свою Π΄Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, Π·Π°ΠΊΡ€Ρ‹Π²Π°ΡŽΡ‚ соСдинСния ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅.

Π­Ρ‚ΠΈ Ρ‚Ρ€ΠΈ Ρ„Π°Π·Ρ‹ - ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½Π½ΠΎ - ΠΈ Π΅ΡΡ‚ΡŒ основной ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» прилоТСния ΠΈ ΡƒΠΏΠΎΠΌΠΈΠ½Π°ΡŽΡ‚ΡΡ ΠΎΠ½ΠΈ вмСстС с DI ΠΏΠΎ Ρ‚ΠΎΠΉ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π΅, Ρ‡Ρ‚ΠΎ ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ» прилоТСния Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π΅ ΠΎΡΠ½ΠΎΠ²Ρ‹Π²Π°Ρ‚ΡŒΡΡ Π½Π° зависимостях ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ прилоТСния. БСзусловно, ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ ΠΈ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ вопросов ΠΈΡ… ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ (собствСнно, DI) - это всё ΠΆΠ΅ Π΄Π²Π΅ Ρ€Π°Π·Π½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ, Π½ΠΎ ΠΎΠ½ΠΈ часто Ρ€Π΅ΡˆΠ°ΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΈΠΌΠΈ ΠΈ Ρ‚Π΅ΠΌΠΈ ΠΆΠ΅ инструмСнтами, Π° Ρ‚Π°ΠΊΠΆΠ΅ связаны ΠΌΠ΅ΠΆΠ΄Ρƒ собой, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ я позволю сСбС Π²ΠΎΠ»ΡŒΠ½ΠΎΡΡ‚ΡŒ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΈΡ… ΠΊΠ°ΠΊ ΠΎΠ΄Π½ΠΎ Ρ†Π΅Π»ΠΎΠ΅ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ. Π’ΡƒΡ‚ Ρ‚Π°ΠΊΠΆΠ΅ слСдуСт Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹ ΠΊΠ°ΠΊ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ самого DI (Π²Π½Π΅Π΄Ρ€Π΅Π½ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· конструктор, сСттСр ΠΈΠ»ΠΈ свойство), Ρ‚Π°ΠΊ ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ систСмы Ρ€Π΅Π·ΠΎΠ»Π²ΠΈΠ½Π³Π° зависимостСй (DI-ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€, сСрвис Π»ΠΎΠΊΠ°Ρ‚ΠΎΡ€, Ρ‚ΠΏ), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚ΠΎΠΆΠ΅ ΠΎΠ±Π»Π°Π΄Π°ΡŽΡ‚ своими плюсами ΠΈ минусами, Π½ΠΎ это ΡƒΠΆΠ΅ вопросы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ, Π² ΠΊΠ°ΠΊΠΎΠΉ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ пишСм простой ΠΈ Ρ‚ΠΈΠΏΠΈΡ‡Π½Ρ‹ΠΉ сСрвСр, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ JSON’ы ΠΈΠ· сСти, ΠΊΠ»Π°Π΄Ρ‘Ρ‚ ΠΈΡ… Π² Π±Π°Π·Ρƒ ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Ρƒ нас Π΅ΡΡ‚ΡŒ:

  • ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ описано, ΠΊΠ°ΠΊΠΎΠΉ ΠΏΠΎΡ€Ρ‚ ΡΠ»ΡƒΡˆΠ°Ρ‚ΡŒ ΠΈ ΠΊ ΠΊΠ°ΠΊΠΎΠΉ Π±Π°Π·Π΅ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΡΡ‚ΡŒΡΡ;
  • Π‘Π΅Ρ€Π²Π΅Ρ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΡΠ»ΡƒΡˆΠ°Π΅Ρ‚ ΠΏΠΎΡ€Ρ‚;
  • НСкий ΠΊΠΎΠ½Π½Π΅ΠΊΡ‚ΠΎΡ€ (соСдинСниС ΠΈΠ»ΠΈ ΠΏΡƒΠ» соСдинСний) ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…;

Π—Π°Ρ…ΠΎΡ‚ΠΈΠΌ Π»ΠΈ ΠΌΡ‹ ΠΏΠΎΠ΄Π½ΡΡ‚ΡŒ сСрвСр ΠΈΠ»ΠΈ соСдинСниС ΠΊ Π±Π΄, Ссли Ρƒ нас Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ? Устроит Π»ΠΈ нас случай, ΠΊΠΎΠ³Π΄Π° сСрвСр ΡƒΠΆΠ΅ поднялся, ΠΏΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ Π²Ρ‹ΡΡΠ½ΠΈΠ»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎ Π½Π° самом Π΄Π΅Π»Π΅ Π±Π°Π·Π° нСдоступна ΠΈ Ρ‡Π°ΡΡ‚ΡŒ запросов ΡƒΠΆΠ΅ оказалась ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π° ΠΈ ΡƒΠΏΠ°Π»Π° с Π·Π°ΠΊΠΎΠ½ΠΎΠΌΠ΅Ρ€Π½Ρ‹ΠΌΠΈ internal server error? (ΠΈΠ»ΠΈ Π½Π°ΠΎΠ±ΠΎΡ€ΠΎΡ‚, ΠΌΡ‹ успСли ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ Π² Π±Π°Π·Ρƒ, ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ соСдинСниС ΠΈ Ρ‚ΠΏ, ΠΏΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚ нСдоступСн?) Нравится Π»ΠΈ Π½Π°ΠΌ Ρ‚Π°ΠΊΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ/пСрСзапускС ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ сСрвиса ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ ΡƒΡΠΏΠ΅Π²Π°ΡŽΡ‚ Π΄ΠΎΠ±Π΅ΠΆΠ°Ρ‚ΡŒ Π΄ΠΎ Π½Π΅Π³ΠΎ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ просто ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠΈΠ»ΠΎ Ρ€Π°Π±ΠΎΡ‚Ρƒ (Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π΄Π°ΠΆΠ΅ ΠΈ Π² сСрСдинС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ‡ΡŒΠ΅Π³ΠΎ-Ρ‚ΠΎ запроса)?

Π­Ρ‚ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Ρ€Π΅ΡˆΠ°ΡŽΡ‚ΡΡ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠ΅ΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² прилоТСния: сначала ΠΌΡ‹ считываСм ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ, ΠΏΠΎΡ‚ΠΎΠΌ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ соСдинСниС с Π±Π΄, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΡ‚ΠΎΠΌ ΠΏΠΎΠ΄Π½ΠΈΠΌΠ°Π΅ΠΌ сСрвСр ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅. ΠŸΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ ΠΆΠ΅ Π·Π°Π²Π΅Ρ‚Π½ΠΎΠ³ΠΎ SIGINT, вмСсто ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ падСния ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ сначала ΠΆΠ΄Ρ‘Ρ‚ окончания ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ всСх Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΡ… запросов, ΠΏΠΎΡ‚ΠΎΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ сСрвСр, ΠΏΠΎΡ‚ΠΎΠΌ Π°ΠΊΠΊΡƒΡ€Π°Ρ‚Π½ΠΎ Π·Π°ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ соСдинСниС с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΡ‚ΠΎΠΌ ΠΎΠΊΠΎΠ½Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ свою Ρ€Π°Π±ΠΎΡ‚Ρƒ. Π’Π°ΠΊΠΎΠ΅ "Π°ΠΊΠΊΡƒΡ€Π°Ρ‚Π½ΠΎΠ΅" бСзопасноС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², кстати, называСтся Graceful shutdown.

РСализуя Ρ‚Π°ΠΊΠΎΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΠΊΠΎΠ΄Π΅, ΠΌΡ‹ Π±Ρ‹, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΌΠΎΠ³Π»ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ прямо Π² самих ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°Ρ… Π²Ρ‹Π·ΠΎΠ²Ρ‹ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² с Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π½ΠΎ это Π±Ρ‹ Π½Π°Ρ€ΡƒΡˆΠΈΠ»ΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ Π΅Π΄ΠΈΠ½ΠΎΠΉ отвСтствСнности ΠΈ Π·Π°ΠΊΠΎΠ½ΠΎΠΌΠ΅Ρ€Π½ΠΎ ΠΏΡ€Π΅Π²Ρ€Π°Ρ‚ΠΈΠ»ΠΎ Π±Ρ‹ вСсь наш ΠΊΠΎΠ΄ Π² ΠΎΠ³Ρ€ΠΎΠΌΠ½ΡƒΡŽ ΠΊΡƒΡ‡Ρƒ спагСтти, Π±Π΅Π· возмоТности Ρ‚ΠΎΡ‡Π½ΠΎ ΠΏΠΎΠ½ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ ΠΈ ΠΊΠΎΠ³Π΄Π° вызовСтся ΠΈ ΠΊΠ°ΠΊ Π²Ρ‹Π·ΠΎΠ² ΠΎΠ΄Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ налоТится Π½Π° Π²Ρ‹Π·ΠΎΠ² Π΄Ρ€ΡƒΠ³ΠΎΠΉ. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, сущСствуСт Π΄Π²Π΅ Ρ€Π°Π·Π½Ρ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Π±Ρ‹ Ρ…ΠΎΡ‚Π΅Π»ΠΈ ΠΎΡ‚Π΄Π΅Π»ΠΈΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³Π° ΠΈ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ, примСняя DI:

  • Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠ΅ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² прилоТСния, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ, ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΡ‚ Ρ‡Π΅Π³ΠΎ зависит, Π² ΠΊΠ°ΠΊΠΎΠΌ порядкС ΠΈΡ… всСх ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΈΠ»ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½ΠΈΠΊΡ‚ΠΎ ΠΈΠ· Π½ΠΈΡ… Π²Π΄Ρ€ΡƒΠ³ Π½Π΅ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ», Ρ‡Ρ‚ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с Π΅Ρ‰Ρ‘ Π½Π΅ созданным ΠΈΠ»ΠΈ ΡƒΠΆΠ΅ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Π½Ρ‹ΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠΌ;
  • Π Π°Π±ΠΎΡ‚Ρƒ самих ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² прилоТСния: ΠΎΠ½ΠΈ просто Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚, вызывая Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΈΠΌ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ Π½Π΅ отвСчая Π·Π° вопросы ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ, ΠΏΡ€ΠΎΠ³Ρ€Π΅Π²Π° ΠΈΠ»ΠΈ остановки Ρ€Π°Π±ΠΎΡ‚Ρ‹ прилоТСния;

DI Π½Π΅ Π½ΡƒΠΆΠ΅Π½ ΠΈΠ»ΠΈ Π½ΡƒΠΆΠ΅Π½ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Java

Если ваш ΠΊΠΎΠ΄ Π½Π΅ состоит ΠΈΠ· ΠΎΠ΄Π½ΠΎΠΉ Π΄Π»ΠΈΠ½Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Ρ‚ΠΎ ΠΎΠ½ бСзусловно Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΡΡ‚ΠΎΡΡ‚ΡŒ ΠΈΠ· Π½Π°Π±ΠΎΡ€Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², ΠΏΠΎΡ‡Ρ‚ΠΈ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒ для своСй Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΊΠ°ΠΊΠΈΡ…-Ρ‚ΠΎ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ². БоотвСтствСнно, Π²Ρ‹ всё Ρ€Π°Π²Π½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚Π΅ Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ всё Ρ‚Π΅ ΠΆΠ΅ Π·Π°Π΄Π°Ρ‡ΠΈ управлСния зависимостями, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π±ΠΎΠ»Π΅Π΅ ΠΈΠ»ΠΈ ΠΌΠ΅Π½Π΅Π΅ явным способом. Π’ совсСм ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ… сСрвисах зависимостСй, ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ ΠΌΠ½ΠΎΠ³ΠΎ ΠΈ Π»ΡŽΠ±Ρ‹Π΅ вопросы Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ ΡΠ²Π»ΡΡŽΡ‚ΡΡ Ρ‡Π΅ΠΌ-Ρ‚ΠΎ Π²Ρ€ΠΎΠ΄Π΅ порядка Π½Π° вашСм столС: скорСС вопросы Π»ΠΈΡ‡Π½ΠΎΠΉ Π³ΠΈΠ³ΠΈΠ΅Π½Ρ‹ ΠΈ чувства прСкрасного, Ρ‡Π΅ΠΌ ТизнСнная Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ. Но Ρ‚ΡƒΡ‚ Π½ΡƒΠΆΠ½ΠΎ ΡƒΡ‡Π΅ΡΡ‚ΡŒ ΠΏΠ°Ρ€Ρƒ нюансов: Π²ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, наносСрвисы Π²ΠΏΠΎΠ»Π½Π΅ заслуТСнно ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚ΡΡ Π°Π½Ρ‚ΠΈΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ΠΎΠΌ (Π°, это Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Ρƒ вас Π² микросСрвисС всё-Ρ‚Π°ΠΊΠΈ Π±ΡƒΠ΄Π΅Ρ‚ достаточно ΠΌΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°), Π²ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ всСгда стрСмятся ΠΊ ΡƒΡΠ»ΠΎΠΆΠ½Π΅Π½ΠΈΡŽ ΠΈ Π½ΠΈΠΊΠΎΠ³Π΄Π° ΠΊ ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½ΠΈΡŽ (Ρ‡Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ любой наносСрвис сСйчас всё ΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠ΅ ΡˆΠ°Π½ΡΡ‹ ΡΡ‚Π°Ρ‚ΡŒ большС Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ), Π° Π² Ρ‚Ρ€Π΅Ρ‚ΡŒΠΈΡ… сущСствуСт Ρ‚Π°ΠΊ называСмая "тСория Ρ€Π°Π·Π±ΠΈΡ‚Ρ‹Ρ… ΠΎΠΊΠΎΠ½", согласно ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±Π°Ρ€Π΄Π°ΠΊ, Π½Π°Ρ‡Π°Π²ΡˆΠΈΡΡŒ Π² ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ… ΠΈ (казалось Π±Ρ‹) Π½Π΅Π²Π°ΠΆΠ½Ρ‹Ρ… частях систСмы стрСмится ΠΊ Ρ€Π°ΡΠΏΡ€ΠΎΡΡ‚Ρ€Π°Π½Π΅Π½ΠΈΡŽ Π² Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΈ ΠΌΠΎΡ€Π°Π»ΡŒΠ½ΠΎ ΠΎΠ±Π»Π΅Π³Ρ‡Π°Π΅Ρ‚ Π·Π°Π²Π΅Π΄Π΅Π½ΠΈΠ΅ Π±Π°Ρ€Π΄Π°ΠΊΠ° Π² Π±ΠΎΠ»Π΅Π΅ Π²Π°ΠΆΠ½Ρ‹Ρ… частях прилоТСния. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π»ΠΈΡ‡Π½ΠΎ я Π±Ρ‹ сказал, Ρ‡Ρ‚ΠΎ сущСствуСт ряд Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π½Ρ‹Ρ… ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ стоят, Ссли Π½Π°Ρ‡Π°Ρ‚ΡŒ ΠΈΡ… ΠΏΡ€ΠΈΠ΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒΡΡ Π½Π° стартС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, Π° ΠΈΡ… отсутствиС Π²Ρ‹Π·ΠΎΠ²Π΅Ρ‚ Ρƒ вас Π±ΠΎΠ»ΡŒΡˆΡƒΡŽ боль Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ, ΠΊΠΎΠ³Π΄Π° ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΠΉ сСрвис Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ подрастёт. НапримСр, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ тСсты ΠΈ Π·Π°ΠΌΠΎΠΊΠ°Ρ‚ΡŒ ΠΏΠ°Ρ€Ρƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², ΠΈΠ»ΠΈ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π΄Ρ€ΡƒΠ³ΠΈΠΌ.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Ρ‘ΠΌ ΠΊ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅.

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅

Данная ΡΡ‚Π°Ρ‚ΡŒΡ Π½Π΅ прСслСдуСт Ρ†Π΅Π»ΡŒ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΈΡΡ‡Π΅Ρ€ΠΏΡ‹Π²Π°ΡŽΡ‰ΡƒΡŽ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ ΠΏΠΎ прСдставлСнным Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌ ΠΈ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π°ΠΌ, поэтому ΠΌΠ½ΠΎΠΉ Π±Ρ‹Π»ΠΈ Π²Ρ‹Π±Ρ€Π°Π½Ρ‹ максимально ΡƒΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠ΄Π°, просто Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ Ρ€Π°Π·Π½ΠΈΡ†Ρƒ Π² рассматриваСмых ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°Ρ…. ЕстСствСнно, всС упомянутыС инструмСнты ΡƒΠΌΠ΅ΡŽΡ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ошибки, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ конструкторами ΠΈ ΠΎΠ±Π»Π°Π΄Π°ΡŽΡ‚ мноТСством Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… возмоТностСй, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π² ΠΈΡ… Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠ΄Π° доступны Π½Π° https://github.com/vivid-money/article-golang-di.

Π•Ρ‰Ρ‘ Π·Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅

Для всСх ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² я Π±ΡƒΠ΄Ρƒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡΡ‚Π΅Π½ΡŒΠΊΡƒΡŽ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΡŽ, ΡΠΎΡΡ‚ΠΎΡΡ‰ΡƒΡŽ ΠΈΠ· Ρ‚Ρ€Π΅Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², Logger - это интСрфСйс, написанный ΠΏΠΎΠ΄ Π»ΠΎΠ³Π³Π΅Ρ€ ΠΈΠ· стандартной Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, DBConn Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ соСдинСниС с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ…, Π° HTTPServer, Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ, сСрвСр, ΡΠ»ΡƒΡˆΠ°ΡŽΡ‰ΠΈΠΉ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚ ΠΈ производящий Π½Π΅ΠΊΠΈΠΉ (Ρ„Π΅ΠΉΠΊΠΎΠ²Ρ‹ΠΉ) запрос ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…. БоотвСтствСнно, ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ ΠΎΠ½ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π² порядкС Logger->DBConn->HTTPServer, Π° Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒΡΡ Π² ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΌ порядкС. Для дСмонстрации Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΌΠΈΡΡ ΠΈ нСблокирубщимися ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ, DBConn Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ постоянной Ρ€Π°Π±ΠΎΡ‚Ρ‹ (просто Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ DBConn.Connect()), Π° httpServer.Serve, Π½Π°ΠΏΡ€ΠΎΡ‚ΠΈΠ², Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ исполнСния.

Reflection based container

Начнём с распространСнного Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… языках Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π² ΠΌΠΈΡ€Π΅ Π³ΠΎ Π² основном прСдставлСн ΠΏΠ°ΠΊΠ΅Ρ‚Π°ΠΌΠΈ https://github.com/uber-go/dig ΠΈ Ρ€Π°ΡΡˆΠΈΡ€ΡΡŽΡ‰ΠΈΠΌ Π΅Π³ΠΎ https://github.com/uber-go/fx. ИдСя проста, Π³Ρ€Π°Ρ„ зависимостСй ΠΌΠΎΠΆΠ½ΠΎ Π»Π΅Π³ΠΊΠΎ динамичСски ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅, Ρ‚Π°ΠΌ ΠΆΠ΅ ΠΊ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΈΠ²ΡΠ·Π°Ρ‚ΡŒ Ρ…ΡƒΠΊΠΈ Π½Π° старт ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ, ΠΊΠ°ΠΊ это выглядит Π½Π° простом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅:

// Π›ΠΎΠ³Π³Π΅Ρ€ Π² качСствС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ создадим Π·Π°Ρ€Π°Π½Π΅Π΅, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Π»ΠΎΠ³ΠΈ сразу, Π΅Ρ‰Ρ‘ Π΄ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π³Ρ€Π°Ρ„Π° зависимостСй.
logger := log.New(os.Stderr, "", 0)
logger.Print("Started")

container := dig.New() // создаём ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€
// РСгистрируСм конструкторы.
// Dig Π²ΠΎ врСмя запуска ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Ρ„Π»Π΅ΠΊΡΠΈΡŽ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎ сигнатурС ΠΊΠ°ΠΆΠ΄ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ½Π° создаёт ΠΈ Ρ‡Ρ‚ΠΎ для этого Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚.
_ = container.Provide(func() components.Logger {
	logger.Print("Provided logger")
	return logger // ΠŸΡ€ΠΎΠΊΠΈΠ½ΡƒΠ»ΠΈ ΡƒΠΆΠ΅ созданный Π»ΠΎΠ³Π³Π΅Ρ€.
})
_ = container.Provide(components.NewDBConn)
_ = container.Provide(components.NewHTTPServer)

_ = container.Invoke(func(_ *components.HTTPServer) {
	// Π’Ρ‹Π·Π²Π°Π»ΠΈ HTTPServer, ΠΊΠ°ΠΊ "ΠΊΠΎΡ€Π΅Π½ΡŒ" Π³Ρ€Π°Ρ„Π° зависимостСй, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€ΡƒΠ·ΠΈΠ»ΠΎΡΡŒ всё Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅.
	logger.Print("Can work with HTTPServer")
	// Никаких срСдств для управлСния ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΌ Ρ†ΠΈΠΊΠ»ΠΎΠΌ Π½Π΅Ρ‚, ΠΏΡ€ΠΈΡˆΠ»ΠΎΡΡŒ Π±Ρ‹ всё ΠΏΠΈΡΠ°Ρ‚ΡŒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ.
})
/*
	Output:
	---
	Started
	Provided logger
	New DBConn
	New HTTPServer
	Can work with HTTPServer
*/

Π’Π°ΠΊΠΆΠ΅ fx прСдоставляСт Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ нСпосрСдствСнно с ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΌ Ρ†ΠΈΠΊΠ»ΠΎΠΌ прилоТСния:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Π›ΠΎΠ³Π³Π΅Ρ€ Π² качСствС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ создадим Π·Π°Ρ€Π°Π½Π΅Π΅, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Π»ΠΎΠ³ΠΈ сразу, Π΅Ρ‰Ρ‘ Π΄ΠΎ
// ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π³Ρ€Π°Ρ„Π° зависимостСй.
logger := log.New(os.Stderr, "", 0)
logger.Print("Started")

// На этот Ρ€Π°Π· ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ fx, здСсь ΡƒΠΆΠ΅ Ρƒ нас появляСтся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ "прилоТСния".
app := fx.New(
	fx.Provide(func() components.Logger {
		return logger // ДобавляСм Π»ΠΎΠ³Π³Π΅Ρ€ ΠΊΠ°ΠΊ внСшний ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚.
	}),
	fx.Provide(
		func(logger components.Logger, lc fx.Lifecycle) *components.DBConn { // ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π΅Ρ‰Ρ‘ ΠΈ lc - ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ».
			conn := components.NewDBConn(logger)
			// МоТно Π½Π°Π²Π΅ΡΠΈΡ‚ΡŒ Ρ…ΡƒΠΊΠΈ.
			lc.Append(fx.Hook{
				OnStart: func(ctx context.Context) error {
					if err := conn.Connect(ctx); err != nil {
						return fmt.Errorf("can't connect to db: %w", err)
					}
					return nil
				},
				OnStop: func(ctx context.Context) error {
					return conn.Stop(ctx)
				},
			})
			return conn
		},
		func(logger components.Logger, dbConn *components.DBConn, lc fx.Lifecycle) *components.HTTPServer {
			s := components.NewHTTPServer(logger, dbConn)
			lc.Append(fx.Hook{
				OnStart: func(_ context.Context) error {
					go func() {
						defer cancel()
						// Ассинхронно запускаСм сСрвСр, Ρ‚.ΠΊ. Serve - Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰Π°Ρ опСрация.
						if err := s.Serve(context.Background()); err != nil && !errors.Is(err, http.ErrServerClosed) {
							logger.Print("Error: ", err)
						}
					}()
					return nil
				},
				OnStop: func(ctx context.Context) error {
					return s.Stop(ctx)
				},
			})
			return s
		},
	),
	fx.Invoke(
		// ΠšΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ‚ΠΎΡ€Ρ‹ - "Π»Π΅Π½ΠΈΠ²Ρ‹Π΅", Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΊΠΎΡ€Π΅Π½ΡŒ Π³Ρ€Π°Ρ„Π° зависимостСй, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€ΡƒΠ·ΠΈΠ»ΠΎΡΡŒ всё Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅.
		func(*components.HTTPServer) {
			go func() {
				components.AwaitSignal(ctx) // ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌ сигнала, Ρ‡Ρ‚ΠΎΠ±Ρ‹ послС этого Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.
				cancel()
			}()
		},
	),
	fx.NopLogger,
)

_ = app.Start(ctx)

<-ctx.Done() // ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ контСкста Π² случаС ошибки ΠΈΠ»ΠΈ получСния сигнала

_ = app.Stop(context.Background())
/*
	Output:
	---
	Started
	New DBConn
	New HTTPServer
	Connecting DBConn
	Connected DBConn
	Serving HTTPServer
	^CStop HTTPServer
	Stopped HTTPServer
	Stop DBConn
	Stopped DBConn
*/

ΠœΠΎΠΆΠ΅Ρ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ вопрос, Π΄ΠΎΠ»ΠΆΠ΅Π½ Π»ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ Serve Π±Ρ‹Ρ‚ΡŒ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΌ (ΠΏΠΎ Π°Π½Π°Π»ΠΎΠ³ΠΈΠΈ с ListenAndServe) ΠΈΠ»ΠΈ Π½Π΅Ρ‚? Моя Ρ‚ΠΎΡ‡ΠΊΠ° зрСния Π½Π° это проста: ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π½Π΅Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΡ‡Π΅Π½ΡŒ просто (go blockingFunc()), Π° Π²ΠΎΡ‚ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ΅ ΠΎΡ‡Π΅Π½ΡŒ слоТно. Π’Π°ΠΊ ΠΊΠ°ΠΊ любой ΠΊΠΎΠ΄ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π² Ρ‚ΠΎΠΌ числС ΠΈ ΠΎΠ±Π»Π΅Π³Ρ‡Π°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ с собой Ρ‚Π΅ΠΌ, ΠΊΡ‚ΠΎ Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚, Π»ΠΎΠ³ΠΈΡ‡Π½Π΅Π΅ всСго ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ синхронный ΠΊΠΎΠ΄, Π° ассинхронным Π΅Π³ΠΎ ΠΏΡƒΡΡ‚ΡŒ сдСлаСт Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ, Ссли Π΅ΠΌΡƒ это понадобится.

Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡΡΡŒ ΠΊ fx, Π² особСнно слоТных ситуациях ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π°Π·Π½ΠΎΠΎΠ±Ρ€Π°Π·Π½Ρ‹Π΅ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ (fx.In, fx.Out ΠΈ Ρ‚Π΄) ΠΈ Π°Π½Π½ΠΎΡ‚Π°Ρ†ΠΈΠΈ (optional, name ΠΈ Ρ‚Π΄), ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌ, зависящим ΠΎΡ‚ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Ρ… интСрфСйсов, ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ зависимости ΠΈΠ»ΠΈ просто ΡΠ²ΡΠ·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΏΠΎ кастомным ΠΈΠΌΠ΅Π½Π°ΠΌ. Π’Π°ΠΊΠΆΠ΅ доступны Ρ…Π΅Π»ΠΏΠ΅Ρ€Ρ‹, Π΄Π°ΡŽΡ‰ΠΈΠ΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ возмоТности, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, fx.Supply позволяСт Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ ΡƒΠΆΠ΅ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π² случаС, Ссли Π²Ρ‹ ΠΏΠΎ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π΅ Π½Π΅ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Π΅Π³ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ сам ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€, Π½ΠΎ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ для Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ².

Π’Π°ΠΊΠΎΠΉ "динамичСский" ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΈΠΌΠ΅Π΅Ρ‚ свои ΠΏΠ»ΡŽΡΡ‹:

  • НСт Π½ΡƒΠΆΠ΄Ρ‹ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ порядок, ΠΌΡ‹ просто рСгистрируСм конструкторы, Π° ΠΏΠΎΡ‚ΠΎΠΌ обращаСмся ΠΊ Π½ΡƒΠΆΠ½Ρ‹ΠΌ интСрфСйсам ΠΈ всё происходит ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ, "Π²ΠΎΠ»ΡˆΠ΅Π±Π½Ρ‹ΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ". БоотвСтствСнно, ΠΏΡ€ΠΎΡ‰Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠ΄;
  • Π—Π° счёт динамичСского построСния Π³Ρ€Π°Ρ„Π° зависимостСй, Π»Π΅Π³ΠΊΠΎ ΠΊΠ°ΠΊ ΠΏΠΎΠ΄ΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠ΅-Ρ‚ΠΎ части Π½Π° ΠΌΠΎΠΊΠΈ, Ρ‚Π°ΠΊ ΠΈ вовсС Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ части прилоТСния;
  • МоТно запросто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π»ΡŽΠ±Ρ‹Π΅ внСшниС Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, просто Π΄ΠΎΠ±Π°Π²ΠΈΠ² ΠΈΡ… конструкторы Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€;
  • ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ ΠΏΠΈΡΠ°Ρ‚ΡŒ мСньшС ΠΊΠΎΠ΄Π°;
  • НС Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ xml ΠΈΠ»ΠΈ yaml;

ΠœΠΈΠ½ΡƒΡΡ‹:

  • Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΌΠ°Π³ΠΈΠΈ, слоТнСС Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ΡŒΡΡ с ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°ΠΌΠΈ;
  • ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ собираСтся динамичСски, Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅, Ρ‚ΠΎ ΠΌΡ‹ тСряСм compile-time Π³Π°Ρ€Π°Π½Ρ‚ΠΈΠΈ - ΡƒΠ·Π½Π°Ρ‚ΡŒ ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΡ… ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°Ρ… с зависимостями (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π·Π°Π±Ρ‹Π»ΠΈ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π·Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ) ΠΌΠΎΠΆΠ½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ запустив ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΈΠ½ΠΎΠ³Π΄Π° Π² особой ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ. ΠžΡ‚Ρ‡Π°ΡΡ‚ΠΈ Π½Π°Π΄Ρ‘ΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Π±Ρ‹ ΠΏΠΎΠ²Ρ‹ΡΠΈΡ‚ΡŒ тСстами, Π½ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΠΉ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ всё Ρ€Π°Π²Π½ΠΎ Π½Π΅ даст.
  • ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ для fx:
    • НСт возмоТностСй ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ошибки Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² (ΠΊΠΎΠ³Π΄Π° Serve Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎ ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ), придётся ΠΏΠΈΡΠ°Ρ‚ΡŒ свои вСлосипСды, Π±Π»Π°Π³ΠΎ, это Π΄Π΅Π»ΠΎ Π½Π΅ самоС слоТноС;

ΠšΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡ

ΠžΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ способы ΠΎΡΠ½ΠΎΠ²Ρ‹Π²Π°ΡŽΡ‚ΡΡ Π½Π° статичСском ΠΊΠΎΠ΄Π΅ ΠΈ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ ΠΈΠ· Π½ΠΈΡ… Π½Π° ΡƒΠΌ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ кодогСнСрация, которая Π² go прСдставлСна прСимущСствСнно https://github.com/google/wire Π·Π° авторством всСм извСстной ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ. Из самого названия этого ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ слСдуСт, Ρ‡Ρ‚ΠΎ вмСсто Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π΅Π·ΠΎΠ»Π²ΠΈΡ‚ΡŒ зависимости динамичСски, ΠΌΡ‹ сгСнСрируСм явный статичСский ΠΈ Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π² случаС ошибки Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ Π³Ρ€Π°Ρ„Π° зависимостСй ΠΎΠ½ ΠΈΠ»ΠΈ Π½Π΅ сгСнСрируСтся, ΠΈΠ»ΠΈ Π½Π΅ скомпилируСтся, соотвСтствСнно, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ compile-time Π³Π°Ρ€Π°Π½Ρ‚ΠΈΠΈ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ зависимостСй. ΠŸΡ€ΠΈ Ρ‚Π°ΠΊΠΎΠΌ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π΅ вСсь вопрос Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ наш Π³Ρ€Π°Ρ„ зависимостСй, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΡ‚ΠΎΠΌ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ для Π½Π΅Π³ΠΎ ΠΊΠΎΠ΄. Π’ Ρ€Π°Π·Π½Ρ‹Ρ… языках для описания связСй Π² ΠΊΠΎΠ΄Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ срСдства, ΠΎΡ‚ Π°Π½Π½ΠΎΡ‚Π°Ρ†ΠΈΠΉ Π΄ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ², Π½ΠΎ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π² ΠΌΠΈΡ€Π΅ Π³ΠΎ Π°Π½Π½ΠΎΡ‚Π°Ρ†ΠΈΠΉ Π½Π΅ сущСствуСт, Π° магичСскиС ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ - это Π²Π΅Ρ‰ΡŒ ΠΎΡ‡Π΅Π½ΡŒ спорная ΠΈ ΠΎΠ±Π»Π°Π΄Π°Π΅Ρ‚ извСстными нСдостатками, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π² ΠΈΡ‚ΠΎΠ³Π΅ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΠ»ΠΈΡΡŒ Π½Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ ΠΊΠΎΠ΄ΠΎΠΌ. Выглядит это ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

Π’ Π½Π°Ρ‡Π°Π»Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ конструкторы для Π½ΠΈΡ…, стандартным способом. Π—Π°Ρ‚Π΅ΠΌ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ ΠΌΡ‹ рСгистрируСм конструкторы ΠΏΠΎΠ΄ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΌ Π±ΠΈΠ»Π΄-Ρ‚Π΅Π³ΠΎΠΌ (Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠΎΠ΄ Π½Π΅ ΠΏΠΎΠΏΠ°Π» Π² ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡŽ ΡƒΠΆΠ΅ "Π±ΠΎΠ΅Π²ΠΎΠ³ΠΎ" прилоТСния ΠΈ Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π»ΠΎ ошибок, связанных с ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΌΠΈ ΠΈΠΌΠ΅Π½Π°ΠΌΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ):

// +build wireinject

package main

import (
	"context"

	"github.com/google/wire"

	"github.com/vivid-money/article-golang-di/pkg/components"
)

func initializeHTTPServer(
	_ context.Context,
	_ components.Logger,
	closer func(), // функция, которая Π²Ρ‹Π·ΠΎΠ²Π΅Ρ‚ остановку всСго прилоТСния
) (
	res *components.HTTPServer,
	cleanup func(), // функция, которая остановит ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
	err error,
) {
	wire.Build(
		NewDBConn,
		NewHTTPServer,
	)
	return &components.HTTPServer{}, nil, nil
}

Π’ ΠΈΡ‚ΠΎΠ³Π΅, послС Π²Ρ‹Π·ΠΎΠ²Π° ΠΎΠ΄Π½ΠΎΠΈΠΌΠ΅Π½Π½ΠΎΠΉ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ wire (ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ это Ρ‡Π΅Ρ€Π΅Π· go generate), wire просканируСт ваш ΠΊΠΎΠ΄, Π½Π°ΠΉΠ΄Ρ‘Ρ‚ всС Π²Ρ‹Π·ΠΎΠ²Ρ‹ wire ΠΈ сгСнСрируСт Ρ„Π°ΠΉΠ» с ΠΊΠΎΠ΄ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΈΡ‚ всС ΠΈΠ½ΠΆΠ΅ΠΊΡ‚Ρ‹:

func initializeHTTPServer(contextContext context.Context, logger components.Logger, closer func()) (*components.HTTPServer, func(), error) {
	dbConn, cleanup, err := NewDBConn(contextContext, logger)
	if err != nil {
		return nil, nil, err
	}
	httpServer, cleanup2 := NewHTTPServer(contextContext, logger, dbConn, closer)
	return httpServer, func() {
		cleanup2()
		cleanup()
	}, nil
}

БоотвСтствСнно ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ сразу ΠΆΠ΅ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ initializeHTTPServer ΠΏΡ€ΠΈ стартС нашСго прилоТСния ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ сгСнСрированный ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ создаст ΠΈ "ΠΏΡ€ΠΎΠΊΠΈΠ½Π΅Ρ‚" ΠΊΡƒΠ΄Π° Π½Π°Π΄ΠΎ всС зависимости:

package main

//go:generate wire

import (
	"context"
	"fmt"
	"log"
	"os"

	"errors"
	"net/http"

	"github.com/vivid-money/article-golang-di/pkg/components"
)

// ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ wire Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ lifecycle (Ρ‚ΠΎΡ‡Π½Π΅Π΅, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Cleanup-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ), Π° ΠΌΡ‹ Π½Π΅ Ρ…ΠΎΡ‚ΠΈΠΌ
// Π΄Π΅Π»Π°Ρ‚ΡŒ Π²Ρ‹Π·ΠΎΠ²Ρ‹ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π² Π½ΡƒΠΆΠ½ΠΎΠΌ порядкС Ρ€ΡƒΠΊΠ°ΠΌΠΈ, Ρ‚ΠΎ придётся Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ Π²Ρ€Π°ΠΏΠΏΠ΅Ρ€Ρ‹ для конструкторов,
// ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΈ этом Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΈ создании ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ cleanup-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для Π΅Π³ΠΎ остановки.
func NewDBConn(ctx context.Context, logger components.Logger) (*components.DBConn, func(), error) {
	conn := components.NewDBConn(logger)
	if err := conn.Connect(ctx); err != nil {
		return nil, nil, fmt.Errorf("can't connect to db: %w", err)
	}
	return conn, func() {
		if err := conn.Stop(context.Background()); err != nil {
			logger.Print("Error trying to stop dbconn", err)
		}
	}, nil
}

func NewHTTPServer(
	ctx context.Context,
	logger components.Logger,
	conn *components.DBConn,
	closer func(),
) (*components.HTTPServer, func()) {
	srv := components.NewHTTPServer(logger, conn)
	go func() {
		if err := srv.Serve(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) {
			logger.Print("Error serving http: ", err)
		}
		closer()
	}()
	return srv, func() {
		if err := srv.Stop(context.Background()); err != nil {
			logger.Print("Error trying to stop http server", err)
		}
	}
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Π›ΠΎΠ³Π³Π΅Ρ€ Π² качСствС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ создадим Π·Π°Ρ€Π°Π½Π΅Π΅, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Π»ΠΎΠ³ΠΈ сразу, Π΅Ρ‰Ρ‘ Π΄ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π³Ρ€Π°Ρ„Π° зависимостСй.
	logger := log.New(os.Stderr, "", 0)
	logger.Print("Started")

	// НуТСн способ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π΅ ΠΈΠ»ΠΈ Π² случаС ошибки. НС хочСтся ΠΎΡ‚ΠΌΠ΅Π½ΡΡ‚ΡŒ "Π³Π»Π°Π²Π½Ρ‹ΠΉ" кониСкси, Ρ‚Π°ΠΊ
	// ΠΊΠ°ΠΊ ΠΎΠ½ ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‚ΠΈΡ‚ всС Server'Ρ‹ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ, Ρ‡Ρ‚ΠΎ Π»ΠΈΡˆΠΈΡ‚ смысла использованиС cleanup-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ
	// Π΄Π΅Π»Π°Ρ‚ΡŒ это Π½Π° Π΄Ρ€ΡƒΠ³ΠΎΠΌ контСкстС.
	lifecycleCtx, cancelLifecycle := context.WithCancel(context.Background())
	defer cancelLifecycle()

	// НичСго Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ с сСрвСром, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ Serve Π² конструкторах.
	_, cleanup, _ := initializeHTTPServer(ctx, logger, func() {
		cancelLifecycle()
	})
	defer cleanup()

	go func() {
		components.AwaitSignal(ctx) // ΠΆΠ΄Ρ‘ΠΌ ошибки ΠΈΠ»ΠΈ сигнала
		cancelLifecycle()
	}()

	<-lifecycleCtx.Done()
	/*
		Output:
		---
		New DBConn
		Connecting DBConn
		Connected DBConn
		New HTTPServer
		Serving HTTPServer
		^CStop HTTPServer
		Stopped HTTPServer
		Stop DBConn
		Stopped DBConn
	*/
}

ΠŸΠ»ΡŽΡΡ‹ Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π°:

  • ΠžΡ‡Π΅Π½ΡŒ явный ΠΈ прСдсказуСмый ΠΊΠΎΠ΄;
  • Π“Π°Ρ€Π°Π½ΠΈΠΈ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ компиляции;
  • Всё Π΅Ρ‰Ρ‘ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π½ΠΈΡ‡Π΅Π³ΠΎ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ Ρ€ΡƒΠΊΠ°ΠΌΠΈ;
  • ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ выглядит достаточно минималистично, ΠΌΡ‹ просто ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π°Π΅ΠΌ интСрфСйсы ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ ΠΌΠ°Π³ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ wire.Build;
  • Всё Π΅Ρ‰Ρ‘ Π½ΠΈΠΊΠ°ΠΊΠΈΡ… xml;
  • Wire прСдоставляСт Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ ΠΊΡ€ΠΎΠΌΠ΅ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π΅Ρ‰Ρ‘ ΠΈ cleanup-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Ρ‡Ρ‚ΠΎ ΡƒΠ΄ΠΎΠ±Π½ΠΎ.

Однако Π΅ΡΡ‚ΡŒ ΠΈ минусы:

  • ΠŸΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ΡΡ Π΄Π΅Π»Π°Ρ‚ΡŒ лишниС тСлодвиТСния, Π΄Π°ΠΆΠ΅ описаниС Π³Ρ€Π°Ρ„Π° Ρ‡Π΅Ρ€Π΅Π· ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΎΡ€Ρ‹ всё-Ρ‚Π°ΠΊΠΈ Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ мСсто;
  • ВяТСлСС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для тСстов ΠΈ ΠΌΠΎΠΊΠΎΠ², ΠΈΠ·-Π·Π° отстутствия явных инструмСнтов Ρ€Π°Π±ΠΎΡ‚Ρ‹ с абстрактными зависимостями; Π­Ρ‚ΠΎ ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ Ρ€Π΅ΡˆΠ°Π΅ΠΌΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΎΠΌ конструкторов, Π½ΠΎ всё Ρ€Π°Π²Π½ΠΎ тянСт "лишниС" слоТности;
  • ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ для wire (Π½ΡƒΠΆΠ½ΠΎ ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ Π΅Ρ‰Ρ‘ Π² Π±Π΅Ρ‚Π΅):
    • НС ΡƒΠΌΠ΅Π΅Ρ‚ ΡΠΎΠΎΡ‚Π½ΠΎΡΠΈΡ‚ΡŒ конструктор, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒΡŽ ΠΎΡ‚ интСрфСйса, Ссли ΠΎΠ½ этот ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅Ρ‚;
    • НСт Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°, это заставляСт ΠΏΠΈΡΠ°Ρ‚ΡŒ свои конструкторы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΅Ρ‰Ρ‘ ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚/ΠΎΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°ΡŽΡ‚ Π΅Π³ΠΎ, Ρ‡Ρ‚ΠΎ Π½Π΅ΡƒΠ΄ΠΎΠ±Π½ΠΎ ΠΈ Π² ΠΎΠ±Ρ‰Π΅ΠΌ смыслС, ΠΈ для использования конструкторов ΠΈΠ· Π²Π½Π΅ΡˆΠ½ΠΈΡ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ;
    • По Ρ‚ΠΎΠΉ ΠΆΠ΅ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π΅ приходится ΠΈΠ·ΠΎΠ±Ρ€Π΅Ρ‚Π°Ρ‚ΡŒ свой вСлосипСд для остановки прилоТСния Π² случаС "падСния" ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ²;
    • Cleanup'Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ просто ΠΏΠΎ порядку, Ссли Π² процСссС ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· Π½ΠΈΡ… ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Ρ‘Ρ‚ ΠΏΠ°Π½ΠΈΠΊΠ°, Ρ‚ΠΎ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ Π½Π΅ вызовутся.

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Π³Ρ€Π°Ρ„ Ρ€ΡƒΠΊΠ°ΠΌΠΈ

Для ΠΏΡ€ΠΈΡˆΠ΅Π΄ΡˆΠΈΡ… ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… языков это ΠΌΠΎΠ³Π»ΠΎ Π±Ρ‹ Π·Π²ΡƒΡ‡Π°Ρ‚ΡŒ Π΄ΠΈΠΊΠΎ, Π½ΠΎ Π½Π° самом Π΄Π΅Π»Π΅ Π²Π°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ½Ρ‹ ΡΠ΅Ρ€ΡŒΡ‘Π·Π½Ρ‹Π΅ ΠΈ слоТныС инструмСнты для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ нСбольшим (ΠΈΠ»ΠΈ большим, Π½ΠΎ ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΌ) Π³Ρ€Π°Ρ„ΠΎΠΌ зависимостСй. Если это Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹, Ρ‚ΠΎ, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π»ΡƒΡ‡ΡˆΠ΅ Π²Π·ΡΡ‚ΡŒ wire ΠΈΠ»ΠΈ dig/fx, Π½ΠΎ я ΠΌΠΎΠ³Ρƒ вас ΡƒΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ с Ρ‚Π°ΠΊΠΈΠΌ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΎΠΌ Ρƒ вас Π±ΡƒΠ΄Π΅Ρ‚ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ мСньшС, Ρ‡Π΅ΠΌ Π²Π°ΠΌ каТСтся (ΠΈΠ»ΠΈ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠΎΠ±Ρ‰Π΅). Одной ΠΈΠ· ΠΏΡ€ΠΈΡ‡ΠΈΠ½ этому Π±ΡƒΠ΄Π΅Ρ‚ отсутствиС Ρƒ гошников ΠΌΠ°Π½Π΅Ρ€Ρ‹ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈΠ·Π±Ρ‹Ρ‚ΠΎΡ‡Π½ΠΎΠ΅ количСство ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² (вмСсто ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… классов-Ρ„Π°Π±Ρ€ΠΈΠΊ ΠΈΠ»ΠΈ Π΄Π°ΠΆΠ΅ Ρ„Π°Π±Ρ€ΠΈΠΊ-для-Ρ„Π°Π±Ρ€ΠΈΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ создаётся простая функция-конструктор), Π΄Ρ€ΡƒΠ³ΠΎΠΉ - Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ спСцифичСскиС возмоТности Π³ΠΎ.

Π’Π°ΠΊ Π²ΠΎΡ‚, Π΄Π°Π²Π°ΠΉΡ‚Π΅ прСдставим простой ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ сдСлаСт всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΈΠ½ΠΆΠ΅ΠΊΡ‚Ρ‹:

logger := log.New(os.Stderr, "", 0)
dbConn := components.NewDBConn(logger)
httpServer := components.NewHTTPServer(logger, dbConn)
doSomething(httpServer)

Π­Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ, это Π²ΠΏΠΎΠ»Π½Π΅ минималистично, насколько это Π²ΠΎΠΎΠ±Ρ‰Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π±Π΅Π· Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠΎΠ²ΠΎΠΉ ΠΌΠ°Π³ΠΈΠΈ Π² Π΄Π°Π½Π½ΠΎΠΌ языкС, ΠΈ Π²Π°ΠΌ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ особСнно Π΄ΠΎΡ€ΠΎΠ³ΠΎ ΠΏΠΎ нСобходимости (добавился Π½ΠΎΠ²Ρ‹ΠΉ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ ΠΈΠ»ΠΈ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π½ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚) Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Ρƒ строк Π² этот ΠΊΠΎΠ΄. Вся ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ здСсь Π±ΡƒΠ΄Π΅Ρ‚ Π² Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ», ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ² сущСствуСт нСсколько. ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ рассмотрим способ, ΠΏΡ€ΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Avito рассказывали Π²ΠΎΡ‚ Π² этом Π΄ΠΎΠΊΠ»Π°Π΄Π΅:

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ errgroup.

Выглядит ΠΎΠ½ΠΎ Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	logger := log.New(os.Stderr, "", 0)
	logger.Print("Started")

	g, gCtx := errgroup.WithContext(ctx)

	dbConn := components.NewDBConn(logger)
	g.Go(func() error {
		// dbConn ΡƒΠΌΠ΅Π΅Ρ‚ ΠΎΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒΡΡ ΠΏΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅ контСкста.
		if err := dbConn.Connect(gCtx); err != nil {
			return fmt.Errorf("can't connect to db: %w", err)
		}
		return nil
	})
	httpServer := components.NewHTTPServer(logger, dbConn)
	g.Go(func() error {
		go func() {
			// ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ httpServer (ΠΊΠ°ΠΊ ΠΈ http.ListenAndServe, кстати) Π½Π΅ ΡƒΠΌΠ΅Π΅Ρ‚ ΠΎΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒΡΡ ΠΏΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅
			// контСкста, Ρ‚ΠΎΠ³Π΄Π° придётся Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ.
			<-gCtx.Done()
			if err := httpServer.Stop(context.Background()); err != nil {
				logger.Print("Stopped http server with error:", err)
			}
		}()
		if err := httpServer.Serve(gCtx); err != nil && !errors.Is(err, http.ErrServerClosed) {
			return fmt.Errorf("can't serve http: %w", err)
		}
		return nil
	})

	go func() {
		components.AwaitSignal(gCtx)
		cancel()
	}()

	_ = g.Wait()

	/*
		Output:
		---
		Started
		New DBConn
		New HTTPServer
		Connecting DBConn
		Connected DBConn
		Serving HTTPServer
		^CStop HTTPServer
		Stop DBConn
		Stopped DBConn
		Stopped HTTPServer
		Finished serving HTTPServer
	*/
}

Как это Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚? ΠœΡ‹ запускаСм всС ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ нашСго прилоТСния Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π°Ρ…, Π½ΠΎ ΠΏΡ€ΠΈ этом запускаСм Π½Π΅ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ, Π° Ρ‡Π΅Ρ€Π΅Π· ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΡƒΡŽ структуру g, которая:

  1. Π‘ΡƒΠ΄Π΅Ρ‚ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½Ρ‹Π΅ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Ρ‘ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ (Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΡ‚ΠΎΠΌ Π΄ΠΎΠΆΠ΄Π°Ρ‚ΡŒΡΡ всСх);
  2. ΠŸΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΠ΅Ρ‚ собствСнный контСкст с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ (ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΡŽ ctx.cancel->gCtx.cancel для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ);
  3. Π‘ΡƒΠ΄Π΅Ρ‚ Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Ссли Ρ…ΠΎΡ‚ΡŒ ΠΎΠ΄Π½Π° ΠΈΠ· Π½ΠΈΡ… Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡΡ ошибкой - Ρ‚ΠΎ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ свой контСкст, Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Ρ‡Π΅Π³ΠΎ всС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ смогут ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ сигнал ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ Ρ‡Π΅Ρ€Π΅Π· ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠΌ gCtx ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ свою Ρ€Π°Π±ΠΎΡ‚Ρƒ.

Вакая схСма Π² Ρ†Π΅Π»ΠΎΠΌ Π½Π΅ΠΏΠ»ΠΎΡ…Π°, Π½ΠΎ я Π½Π°Ρ…ΠΎΠΆΡƒ Π² Π½Π΅ΠΉ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ„Π°Ρ‚Π°Π»ΡŒΠ½Ρ‹ΠΉ нСдостаток: errgroup заставляСт ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚ΡŒΡΡ Π½Π° событиС ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ контСкста. Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π½Π΅ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ порядка ΠΎΡ‚ΠΌΠ΅Π½Ρ‹ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, каТдая ΠΈΠ· Π½ΠΈΡ… ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΉ Π΅ΠΉ gCtx Π½Π° .Done() Π² любой ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ для Π½Π΅Ρ‘ ΠΌΠΎΠΌΠ΅Π½Ρ‚ ΠΈ Π² ΠΈΡ‚ΠΎΠ³Π΅ ΠΌΡ‹ тСорСтичСски ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ, ΠΊΠΎΠ³Π΄Π° Ρƒ вас соСдинСниС с Π±Π°Π·ΠΎΠΉ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎ cancel ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΠ»ΠΎΡΡŒ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Π±ΠΎΠ»Π΅Π΅ высокоуровнСвый ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ Π²Π°ΠΆΠ½Ρ‹ΠΉ сСтСвой запрос) Π·Π°Π²Π΅Ρ€ΡˆΠΈΠ» свою Ρ€Π°Π±ΠΎΡ‚Ρƒ. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ:

  • errgroup Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΠ΅Ρ‚;
  • errgroup отмСняСт контСкст Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Ρ‚ΠΎΠΌ случаС, Ссли ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π²Π΅Ρ€Π½ΡƒΠ» ΠΎΡˆΠΈΠ±ΠΊΡƒ. Если ΠΆΠ΅ ΠΏΠΎ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π΅ Π½Π΅ΠΊΠΈΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡΡ Π±Π΅Π· ошибки, Ρ‚ΠΎ систСма Π½Π΅ ΠΎΡ‚Ρ€Π΅Π°Π³ΠΈΡ€ΡƒΠ΅Ρ‚, ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΠ² Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ Π½ΠΈ Π² Ρ‡Ρ‘ΠΌ Π½Π΅ Π±Ρ‹Π²Π°Π»ΠΎ. Π”Π°, это ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠΌ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ вСлосипСдом, Π½ΠΎ Π² Ρ‚Π°ΠΊΠΎΠΌ случаС Π·Π°Ρ‡Π΅ΠΌ ΠΌΡ‹ Π²ΠΎΠΎΠ±Ρ‰Π΅ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π±Ρ€Π°Π»ΠΈ, Ссли ΠΏΠΎΡ‚ΠΎΠΌ всё Ρ€Π°Π²Π½ΠΎ придётся Π΄ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ?

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ способ - это самописный lifecycle.

ИдСя, каТСтся, Π»Π΅ΠΆΠΈΡ‚ Π½Π° повСрхности: Ссли errgroup Π½Π΅ Π΄Π°Ρ‘Ρ‚ Π½Π°ΠΌ Π½ΡƒΠΆΠ½Ρ‹Ρ… Π³Π°Ρ€Π°Π½Ρ‚ΠΈΠΉ, ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ свой вСлосипСд, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡ… Π΄Π°Ρ‘Ρ‚. Π’Π°ΠΊΠΈΡ… ΠΈΠ΄Π΅ΠΉ Π² своё врСмя Π½Π΅ ΠΈΠ·Π±Π΅ΠΆΠ°Π» ΠΈ я ΠΈ Π»ΠΈΡ‡Π½ΠΎ Ρƒ мСня ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

logger := log.New(os.Stderr, "", 0)
logger.Print("Started")

lc := lifecycle.NewLifecycle()

dbConn := components.NewDBConn(logger)
lc.AddServer(func(ctx context.Context) error { // просто рСгистриуСм Π² ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌ порядкС сСрвСры ΠΈ ΡˆΠ°Ρ‚Π΄Π°ΡƒΠ½Π΅Ρ€Ρ‹
	return dbConn.Connect(ctx)
}).AddShutdowner(func(ctx context.Context) error {
	return dbConn.Stop(ctx)
})

httpSrv := components.NewHTTPServer(logger, dbConn)
lc.Add(httpSrv) // ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ httpSrv Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅Ρ‚ интСрфСйсы Server ΠΈ Shutdowner

go func() {
	components.AwaitSignal(ctx)
	lc.Stop(context.Background())
}()

_ = lc.Serve(ctx)

И такая идСя Ρ…ΠΎΡ€ΠΎΡˆΠ° всСм, ΠΊΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ слоТным ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΡ€ΠΎΡ‰Π΅, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ срСдства самого языка. (ΠΈΠΌΠ΅Π½Π½ΠΎ поэтому Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΌΠΎΠ΅Π³ΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚Π° lifecycle я Π½Π΅ стал Π½ΠΈΠ³Π΄Π΅ Π²Ρ‹ΠΊΠ»Π°Π΄Ρ‹Π²Π°Ρ‚ΡŒ, это Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ смысла)

Бпособ Ρ„ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ

БущСствуй ΠΌΡ‹ Π² ΠΌΠΈΡ€Π΅ Java ΠΈΠ»ΠΈ Π³Π΄Π΅-Ρ‚ΠΎ Π΅Ρ‰Ρ‘, Ρ‚ΠΎ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΠ»ΠΈΡΡŒ Π±Ρ‹ Π½Π° ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π΅, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ порядок ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ, запуска ΠΈ остановки сСрвисов "Ρ€ΡƒΠΊΠ°ΠΌΠΈ" Π·Π²ΡƒΡ‡ΠΈΡ‚, ΠΊΠ°ΠΊ ΠΎΡ‡Π΅Π½ΡŒ нСблагодарная Ρ€Π°Π±ΠΎΡ‚Π° Π±Π΅Π· ΠΏΡ€Π°Π²Π° Π½Π° ΠΎΡˆΠΈΠ±ΠΊΡƒ. Но Π² Π³ΠΎ Π΅ΡΡ‚ΡŒ Ρ‚Ρ€ΠΈ ΡƒΠ΄ΠΎΠ±Π½Ρ‹Ρ… инструмСнта, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΎΠ±Π»Π΅Π³Ρ‡Π°ΡŽΡ‚ это Π΄Π΅Π»ΠΎ. ΠŸΡ€ΠΎ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Ρ‹ Π² курсС, вСроятно, всС, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‚ΡŒ Ρ‡ΡƒΡ‚ΡŒ-Ρ‡ΡƒΡ‚ΡŒ этим интСрСсовался, ΠΈ Ссли Π²Ρ‹ Π½Π΅ Π² ΠΈΡ… числС, Ρ‚ΠΎ вряд Π»ΠΈ Π²Ρ‹ поняли ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠ΄Π°, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ я Π½Π΅ стану Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ пояснСния, Ρ‚Π΅ΠΌ Π±ΠΎΠ»Π΅Π΅, Ρ‡Ρ‚ΠΎ это вопрос Π±ΡƒΠΊΠ²Π°Π»ΡŒΠ½ΠΎ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Π°Π±Π·Π°Ρ†Π° ΠΈΠ· ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΆΠ΅ ссылки Π² Π³ΡƒΠ³Π»Π΅. Π’Ρ‚ΠΎΡ€ΠΎΠΉ Ρ‚Π°ΠΊΠΎΠΉ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ инструмСнт, это контСкст, Π½Π΅ΠΊΠΈΠΉ "Π²ΠΎΠ»ΡˆΠ΅Π±Π½Ρ‹ΠΉ" интСрфСйс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚, Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅, ΡƒΠΆΠ΅ ΠΏΠΎΡ‡Ρ‚ΠΈ любая функция Π² Π³ΠΎ ΠΈ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΊΡ€ΠΎΠΌΠ΅ всСго ΠΏΡ€ΠΎΡ‡Π΅Π³ΠΎ прСдоставляСт функциям Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡƒΠ·Π½Π°Ρ‚ΡŒ, Π±Ρ‹Π» Π»ΠΈ Π΄Π°Π½Π½Ρ‹ΠΉ контСкст ΠΎΡ‚ΠΌΠ΅Π½Ρ‘Π½ (ΠΈΠ»ΠΈ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ для Π½ΠΈΠΆΠ΅Π»Π΅ΠΆΠ°Ρ‰ΠΈΡ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ). Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Ρ‚Π°ΠΊΠΎΠΉ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ Π΄Π°Ρ‘Ρ‚ Π½Π°ΠΌ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒ, позволяя каскадно Π·Π°Π²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ»ΠΈ Π³Ρ€ΡƒΠΏΠΏΡ‹ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ - Π² Ρ‚ΠΎΠΌ числС ΠΈ ΠΈΠ· main-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π’Ρ€Π΅Ρ‚ΠΈΠΉ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΈ Ρ‡ΡƒΡ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ ΠΎΡ‡Π΅Π²ΠΈΠ΄Π½Ρ‹ΠΉ инструмСт, defer, являСтся просто ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹ΠΌ словом, Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‰ΠΈΠΌ Π² Π½Π΅ΠΊΠΈΠΉ стСк Ρ‚Π΅ΠΊΡƒΡˆΠ΅ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π΄Ρ€ΡƒΠ³ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π° послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ. А это ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Π²ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, послС defer'Π° ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ сколько ΡƒΠ³ΠΎΠ΄Π½ΠΎ return'ΠΎΠ² Π½Π΅ боясь, Ρ‡Ρ‚ΠΎ Π³Π΄Π΅-Ρ‚ΠΎ Π·Π°Π±ΡƒΠ΄Π΅ΡˆΡŒ Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΡŒΡŽΡ‚Π΅ΠΊΡ ΠΈΠ»ΠΈ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„Π°ΠΉΠ» (кстати, ΠΎΡ‡Π΅Π½ΡŒ способствуСт ΡΠΎΠΊΡ€Π°Ρ‰Π΅Π½ΠΈΡŽ Π²Π΅Ρ‚Π²Π»Π΅Π½ΠΈΠΉ Π² ΠΊΠΎΠ΄Π΅), Π° Π²ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, ΠΎΠ½ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ Π² ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΌ порядкС. МоТно Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ конструкторы ΠΈ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π· ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ дСструктор ΠΈ ΠΎΠ½ΠΈ вызовутся сами, ΠΏΠΎ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ, Π² ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌ порядкС с Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния Π³Ρ€Π°Ρ„Π° зависимостСй, Π½Π΅ трСбуя Π½ΠΈΠΊΠ°ΠΊΠΈΡ… Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… инструмСнтов:

a, err := NewA()
if err != nil {
	panic("cant create a: " + err.Error())
}
go a.Serve()
defer a.Stop()

b, err := NewB(a)
if err != nil {
	panic("cant create b: " + err.Error())
}
go b.Serve()
defer b.Stop()
/*
	ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ старта: A, B
	ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ остановки: B, A
*/

ΠŸΡ€Π°Π²Π΄Π°, остаётся Π΅Ρ‰Ρ‘ вопрос ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ошибок, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° ΠΏΠ΅Ρ€Π²ΠΎΠ½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΉ ошибки (Ρ‡Ρ‚ΠΎ Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, Π½ΠΎ ΠΌΠ½Π΅ нравится Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚Π°ΠΊ). Π”Π΅Π»ΠΎ Π½Π΅ обойдётся Π±Π΅Π· Ρ‚Ρ€Π΅Ρ… ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ… Ρ…Π΅Π»ΠΏΠ΅Ρ€ΠΎΠ²:

  • ErrSet - Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ ошибок для ΠΈΡ… использования Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ старта/остановки прилоТСния;
  • Serve - ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ контСкст ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ-server, стартуСт этот server Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π΅ ΠΈ ΠΏΡ€ΠΈ этом Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ контСкст, ΠΎΠ±Π΅Ρ€Π½ΡƒΡ‚Ρ‹ΠΉ Π² WithCancel, Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ ΠΏΡ€ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ-server'Π° (Ρ‡Ρ‚ΠΎ позволяСт ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‚ΠΈΡ‚ΡŒ запуск прилоТСния Π½Π° сСрСдинС, Ссли ΠΎΠ΄ΠΈΠ½ ΠΈΠ· ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… server'ΠΎΠ² Π·Π°Π²Π΅Ρ€ΡˆΠΈΠ»ΡΡ);
  • Shutdown - просто Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ ΠΏΠΈΡˆΠ΅Ρ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΡƒΡŽ ΠΎΡˆΠΈΠ±ΠΊΡƒ Π² ErrSet, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ³Π΄Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ΡΡ, Π½Π΅Ρ‚ нСобходимости ΠΊΠ°ΠΊ-Π»ΠΈΠ±ΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ошибки Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ²;

Π’ ΠΈΡ‚ΠΎΠ³Π΅, ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"errors"
	"net/http"

	"github.com/vivid-money/article-golang-di/pkg/components"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	logger := log.New(os.Stderr, "", 0)
	logger.Print("Started")

	go func() {
		components.AwaitSignal(ctx)
		cancel()
	}()

	errset := &ErrSet{}

	errset.Add(runApp(ctx, logger, errset))

	_ = errset.Error() // ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ
	/*
		Output:
		---
		Started
		New DBConn
		Connecting DBConn
		Connected DBConn
		New HTTPServer
		Serving HTTPServer
		^CStop HTTPServer
		Stop DBConn
		Stopped DBConn
		Stopped HTTPServer
		Finished serving HTTPServer
	*/
}

func runApp(ctx context.Context, logger components.Logger, errSet *ErrSet) error {
	var err error

	dbConn := components.NewDBConn(logger)
	if err := dbConn.Connect(ctx); err != nil {
		return fmt.Errorf("cant connect dbConn: %w", err)
	}
	defer Shutdown("dbConn", errSet, dbConn.Stop)

	httpServer := components.NewHTTPServer(logger, dbConn)
	if ctx, err = Serve(ctx, "httpServer", errSet, httpServer.Serve); err != nil && !errors.Is(err, http.ErrServerClosed) {
		return fmt.Errorf("cant serve httpServer: %w", err)
	}
	defer Shutdown("httpServer", errSet, httpServer.Stop)

	components.AwaitSignal(ctx)
	return ctx.Err()
}

Π’ качСстС примСчания ΡƒΠΊΠ°ΠΆΡƒ, Ρ‡Ρ‚ΠΎ Π² Π΄Π°Π½Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ всС ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ ΠΈΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π² Ρ„ΠΎΠ½ΠΎΠ²ΠΎΠΌ контСкстС ΠΈ напомню, Ρ‡Ρ‚ΠΎ это лишь дСмонстрационный ΠΎΠ±Ρ€Π°Π·Π΅Ρ†, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π΅ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ части ошибок ΠΈ ΠΏΡ€ΠΎΡ‡ΠΈΡ… Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Π² ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π΅ Π²Π΅Ρ‰Π΅ΠΉ.

Π§Ρ‚ΠΎ Π½Π°ΠΌ Π΄Π°Ρ‘Ρ‚ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄?

  • Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² происходит ΠΊΠ°ΠΊ ΠΈ Ρ€Π°Π½ΡŒΡˆΠ΅, копипастом магичСских Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅Ρ… слов New-Serve-defer-Shutdown (Π±ΡƒΠ΄ΡŒ Ρƒ нас Π΄ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΊΠΈ, кстати, ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Π±Ρ‹ Π΅Ρ‰Ρ‘ Π½Π°Π±Ρ€ΠΎΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΡΡ‚Π΅Π½ΡŒΠΊΠΈΠΉ Ρ…Π΅Π»ΠΏΠ΅Ρ€, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ‹Π»ΠΎ Π΅Ρ‰Ρ‘ мСньшС ΠΊΠΎΠ΄Π° ΠΈ совсСм симпатично);
  • ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΏΡ€ΠΈ Ρ‚Π°ΠΊΠΎΠΌ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π΅ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Ρ‚ΠΎΠΌ порядкС, Π² ΠΊΠ°ΠΊΠΎΠΌ ΠΎΠ½ΠΈ зависят Π΄Ρ€ΡƒΠ³ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³Π°, Ρ‚ΠΎ ошибка, ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π²Ρ‹ Π½Π°Ρ‡Π½Ρ‘Ρ‚Π΅ ΠΈΠ»ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚Π΅ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π² Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌ порядкС свСдСна ΠΊ Π½ΡƒΠ»ΡŽ;
  • Ошибка Π² сСрСдинС ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сСрвиса ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ досрочному Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ прилоТСния;
  • Π—Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² происходит Π² ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΉ (с Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния порядка зависимостСй) ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ;
  • Ошибка Ρ€Π°Π±ΠΎΡ‚Ρ‹ случайного ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ прилоТСния, Π½ΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ всё Ρ€Π°Π²Π½ΠΎ останСтся ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΉ, ΠΎΡ‚ ΠΊΠΎΠ½Ρ†Π° ΠΊ Π½Π°Ρ‡Π°Π»Ρƒ;
  • ΠœΡ‹ 100% доТдёмся окончания всСх ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², ΠΏΡ€Π΅ΠΆΠ΄Π΅, Ρ‡Π΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅;
  • Π’Π΅ΡΡŒ ΠΊΠΎΠ΄, ΠΎΡΡƒΡ‰Π΅ΡΡ‚Π²Π»ΡΡŽΡ‰ΠΈΠΉ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°, описан ΠΎΡ‡Π΅Π½ΡŒ явно ΠΈ Π½Π΅ содСрТит Π½ΠΈΠΊΠ°ΠΊΠΈΠΉ ΠΌΠ°Π³ΠΈΠΈ;

НСдостатки

  • ΠŸΠΈΡˆΠ΅Ρ‚ΡΡ Ρ€ΡƒΠΊΠ°ΠΌΠΈ, Π° Π·Π½Π°Ρ‡ΠΈΡ‚ ΠΏΡ€ΠΈ сотнях зависимостСй ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΊ ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ;

Π’Ρ‹Π²ΠΎΠ΄Ρ‹

Π‘Π°ΠΌΠΎΠΉ Π»ΡƒΡ‡ΡˆΠ΅ΠΉ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΎΠΉ всСгда остаётся Π²Ρ‹Π±ΠΎΡ€ подходящСго инструмСнта ΠΏΠΎΠ΄ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ. ВсС рассмотрСнныС ΠΌΠ½ΠΎΠΉ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΈΠΌΠ΅ΡŽΡ‚ свои достоинства ΠΈ нСдостатки, ΠΊΠ°ΠΊ сами ΠΏΠΎ сСбС, Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊ спСцификС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π½Π° golang. ΠžΠΏΠΈΡΠ°Π½Π½Ρ‹ΠΉ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ fx нСсмотря Π½Π° свою Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π½Π΅ΠΈΠ΄ΠΈΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ (Π² контСкстС go), выглядит Ρ…ΠΎΡ€ΠΎΡˆΠΎ ΠΏΡ€ΠΎΡ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹ΠΌΠΈ ΠΈ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ практичСски всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ, Π° Ρ‡Ρ‚ΠΎ Π½Π΅ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ - нСслоТно Π΄ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ€ΡƒΠΊΠ°ΠΌΠΈ. Wire нСсмотря Π½Π° Π³Ρ€ΠΎΠΌΠΊΠΎΠ΅ имя создатСлСй выглядит сыроватым ΠΈ нСсколько Π½Π΅Π΄ΠΎΡ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹ΠΌ, Π½ΠΎ ΠΏΡ€ΠΈ этом бСзусловно ΠΈΠ΄ΠΈΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π΅Π½ ΠΈ Π² состоянии ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ прСимущСства ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ. ΠŸΡ€ΠΈ этом ΠΈΠ½ΠΆΠ΅ΠΊΡ‚Ρ‹ Ρ€ΡƒΠΊΠ°ΠΌΠΈ Π½Π΅ выглядят (Π΄Π° ΠΈ Π½Π΅ ΡΠ²Π»ΡΡŽΡ‚ΡΡ, ΠΏΠΎ ΠΌΠΎΠ΅ΠΌΡƒ ΠΎΠΏΡ‹Ρ‚Ρƒ) особСнно Π±ΠΎΠ»Π΅Π·Π½Π΅Π½Π½Ρ‹ΠΌΠΈ, Π° всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Π·Π°Π΄Π°Ρ‡ΠΈ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ стандартных go, context, defer ΠΈ ΠΏΠ°Ρ€Ρ‹ Ρ…Π΅Π»ΠΏΠ΅Ρ€ΠΎΠ² минимального Ρ€Π°Π·ΠΌΠ΅Ρ€Π°. Π’Π°ΠΆΠ½Π΅ΠΉΡˆΠΈΠΌ Π΄Π΅Π»ΠΎΠΌ всСгда являСтся Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°, ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠ΅ ΠΌΠΎΠ΄Π΅Π»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΡ€Π΅Π΄ΠΌΠ΅Ρ‚Π½ΠΎΠΉ области ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠ΅ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π»ΠΎΠ³ΠΈΠΊΠΈ прилоТСния Π½Π° части с ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΌΠΈ Π·ΠΎΠ½Π°ΠΌΠΈ отвСтствСнности, Π° вопрос Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΎΠ² зависимостСй Π½Π΅ являСтся ΠΊΡ€ΠΈΡ‚ΠΈΡ‡Π½Ρ‹ΠΌ, Π΄ΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° ΠΈΠ»ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠΉ слоТности. Π›ΠΈΡ‡Π½ΠΎ я Π±Ρ‹ Π΄ΠΎ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ сотСн ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π±Π΅Π· ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ использовал ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ сбора Π³Ρ€Π°Ρ„Π° зависимостСй Ρ€ΡƒΠΊΠ°ΠΌΠΈ, Π° ΡƒΠΆΠ΅ ΠΏΠΎΡ‚ΠΎΠΌ присмотрСлся ΠΊ wire (ΠΌΠΎΠΆΠ΅Ρ‚, ΠΊ Ρ‚ΠΎΠΌΡƒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΎΠ½ Π½Π°ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ Π²ΠΎΠΎΠ±Ρ‰Π΅ всС Π·Π°Π΄Π°Ρ‡ΠΈ, Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ Π±Ρ‹ ΠΎΡ‚ Π½Π΅Π³ΠΎ ΠΎΠΆΠΈΠ΄Π°Ρ‚ΡŒ).

Releases

No releases published

Packages

No packages published

Languages

  • Go 100.0%