{"id":3566,"date":"2022-01-10T15:47:14","date_gmt":"2022-01-10T15:47:14","guid":{"rendered":"http:\/\/the-codest.localhost\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/"},"modified":"2026-04-28T14:05:25","modified_gmt":"2026-04-28T14:05:25","slug":"modularyzacja-ruby-on-rails-z-packwerk-odcinek-ii","status":"publish","type":"post","link":"https:\/\/thecodest.co\/pl\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/","title":{"rendered":"Modularyzacja Ruby on Rails za pomoc\u0105 Packwerk Episode II"},"content":{"rendered":"<h2 class=\"wp-block-heading\">Aplikacja jako pakiet<\/h2>\n\n\n\n<p>Podej\u015bcie do modularyzacji naszej aplikacji polega na przekszta\u0142ceniu ca\u0142ej aplikacji w pakiet.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tworzenie struktury<\/h3>\n\n\n\n<p>Najpierw musimy utworzy\u0107 <code>app\/packages<\/code> w kt\u00f3rym umie\u015bcimy wszystkie nasze pakiety. Aby odizolowa\u0107 nasze pakiety, musimy oddzieli\u0107 ka\u017cdy z nich <strong>Koncepcja MVC<\/strong> w jednym folderze. Bior\u0105c <strong>CodeTriage <a href=\"https:\/\/thecodest.co\/pl\/dictionary\/why-do-projects-fail\/\">projekt<\/a><\/strong> Jako przyk\u0142ad otrzymamy co\u015b takiego jak na poni\u017cszym obrazku.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/2.png\" alt=\"struktura pakietu \" title=\"Przyk\u0142ad struktury pakietu\"\/><\/figure>\n\n\n\n<p>Je\u015bli spr\u00f3bujemy uruchomi\u0107 serwer, nie uda mu si\u0119 znale\u017a\u0107 sta\u0142ych. Dlatego te\u017c musimy doda\u0107 lini\u0119 konfiguracji do naszego pliku <code>application.rb<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\">config.paths.add 'app\/packages', glob: '*\/{*,*\/concerns}', eager_load:true<\/code><\/pre>\n\n\n\n<p>Teraz aplikacja dzia\u0142a, ale nie mo\u017ce znale\u017a\u0107 widok\u00f3w, wi\u0119c musimy doda\u0107 kolejn\u0105 lini\u0119 konfiguracji do naszej aplikacji <code>application_controller.rb<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\">append_view_path(Dir.glob(<a href=\"https:\/\/thecodest.co\/pl\/blog\/ways-to-increase-your-rails-performance\/\">Szyny<\/a>.root.join('app\/packages\/*\/views'))<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tworzenie pakiet\u00f3w<\/h3>\n\n\n\n<p>Nasza struktura jest gotowa, wi\u0119c teraz mo\u017cemy rozpocz\u0105\u0107 tworzenie pakiet\u00f3w. Aby to zrobi\u0107, musimy tylko doda\u0107 plik<code>package.yml<\/code> do ka\u017cdego folderu z nast\u0119puj\u0105c\u0105 konfiguracj\u0105:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\">enforce_privacy: false\nenforce_dependencies: true<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/1.png\" alt=\"package.yml\" title=\"Przyk\u0142ad package.yml\"\/><\/figure>\n\n\n\n<p><code>enforce_privacy<\/code>daje <a href=\"https:\/\/thecodest.co\/pl\/blog\/why-us-companies-are-opting-for-polish-developers\/\">my<\/a> mo\u017cliwo\u015b\u0107 odizolowania wszystkich sta\u0142ych pakietu i pracy z publicznymi <a href=\"https:\/\/thecodest.co\/pl\/blog\/compare-staff-augmentation-firms-that-excel-in-api-team-staffing-for-financial-technology-projects\/\">API<\/a>. Aby wyeksponowa\u0107 sta\u0142e publiczne, musimy doda\u0107 sta\u0142e w, na przyk\u0142ad&nbsp;<code>packages\/users\/app\/public.<\/code>Na razie ustawimy t\u0119 konfiguracj\u0119 na <em> fa\u0142szywy<\/em>.<\/p>\n\n\n\n<p><code>enforce_dependencies<\/code> wymusi zale\u017cno\u015b\u0107 pakietu i sprawdzi wszystkie sta\u0142e odniesienia. Je\u015bli zale\u017cno\u015b\u0107 nie jest wyra\u017anie zdefiniowana, b\u0119dzie to naruszenie granicy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Weryfikacja systemu pakiet\u00f3w<\/h3>\n\n\n\n<p><strong>Packwerk<\/strong> ustanowi\u0142a kryterium, kt\u00f3rego musimy przestrzega\u0107, aby mie\u0107 prawid\u0142owy system pakiet\u00f3w. Mo\u017cemy rozpocz\u0105\u0107 uruchamianie <code>walidacja packwerk<\/code> w naszej konsoli.<\/p>\n\n\n\n<p>&nbsp;Spowoduje to sprawdzenie struktury folder\u00f3w, <strong>konfiguracja pakietu<\/strong>i automatyczne \u0142adowanie pami\u0119ci podr\u0119cznej \u015bcie\u017cki.<\/p>\n\n\n\n<p>W tej chwili nasza aplikacja nie jest prawid\u0142owa i musimy naprawi\u0107 \u015bcie\u017cki \u0142adowania w<strong><code>packwerk.yml<\/code>.<\/strong> Aby to zrobi\u0107, musimy tylko doda\u0107 brakuj\u0105ce \u015bcie\u017cki.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\"># packwerk.yml\n\nload_paths:\n.\n.\n.\n\n# Users\n- app\/packages\/users\/controllers\n- app\/packages\/users\/models\n- app\/packages\/users\/package.yml\n- app\/packages\/users\/views<\/code><\/pre>\n\n\n\n<p>W tym momencie jeste\u015bmy gotowi do sprawdzenia narusze\u0144 granic w naszej aplikacji. Aby sprawdzi\u0107 naruszenia, mo\u017cemy uruchomi\u0107<code>packwerk update-deprecations<\/code> to polecenie wygeneruje <code>deprecated_references.yml<\/code> dla ka\u017cdego pakietu. W ka\u017cdym pliku znajdziemy nazw\u0119 pakietu, typ naruszenia i \u015bcie\u017ck\u0119 pliku. Dzi\u0119ki tym wszystkim informacjom wiemy, gdzie wyst\u0119puje naruszenie i mo\u017cemy podj\u0105\u0107 decyzj\u0119 o jego rozwi\u0105zaniu.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/4.png\" alt=\"deprecated_references.yml\" title=\"Przyk\u0142ad deprecated_references.yml\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\"># deprecated_references.yml\n\n.\n.\n.\n\napp\/packages\/repos:\n  \"::Repo\":\n    naruszenia:\n    - zale\u017cno\u015b\u0107\n    pliki:\n    - app\/packages\/users\/models\/user.rb<\/code><\/pre>\n\n\n\n<p>Bior\u0105c przyk\u0142ad, opiszemy ka\u017cd\u0105 cz\u0119\u015b\u0107 wygenerowanych informacji<br>przez <strong>Packwerk<\/strong>.<\/p>\n\n\n\n<p>- <code>app\/packages\/repos<\/code> &nbsp;- pakiet, w kt\u00f3rym sta\u0142ym naruszeniem jest<br>znaleziono.<\/p>\n\n\n\n<p>- <code>::Repo<\/code> &nbsp;- \u015bcie\u017cka do pliku zawieraj\u0105cego naruszon\u0105 sta\u0142\u0105.<\/p>\n\n\n\n<p>- <code>zale\u017cno\u015b\u0107<\/code> &nbsp;- rodzaj naruszenia, zale\u017cno\u015b\u0107 lub prywatno\u015b\u0107.<\/p>\n\n\n\n<p>- <code>app\/packages\/users\/models\/user.rb<\/code> &nbsp;- \u015bcie\u017cka do pliku zawieraj\u0105cego naruszon\u0105 sta\u0142\u0105.<\/p>\n\n\n\n<p>Ostatnim krokiem w tej sekcji jest dodanie nowo wygenerowanych \u015bcie\u017cek plik\u00f3w do sekcji <code>packwerk.ym<\/code>l i ponownie uruchomi\u0107 walidacje.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wizualizacja zale\u017cno\u015bci<\/h3>\n\n\n\n<p>Ze wszystkimi informacjami w package.yml i <code>deprecated_references.yml<\/code>mo\u017cemy wtedy<br>wizualizowa\u0107 wykres zale\u017cno\u015bci. Aby to zrobi\u0107, musimy doda\u0107 kolejny klejnot, w tym przypadku u\u017cyjemy <a href=\"https:\/\/github.com\/mquan\/pocky\" rel=\"nofollow\">Pocky<\/a>.<\/p>\n\n\n\n<p>Zgrabiarka <code>pocky:generate<\/code> wygenerujemy plik o nazwie <code>packwerk.png<\/code> gdzie mo\u017cemy zwizualizowa\u0107 nasz pierwszy wykres zale\u017cno\u015bci.<\/p>\n\n\n\n<p>Po zdefiniowaniu wszystkich pakiet\u00f3w nasz wykres b\u0119dzie wygl\u0105da\u0142 nast\u0119puj\u0105co.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/5.png\" alt=\"wykres bez zaakceptowanych zale\u017cno\u015bci\" title=\"Przyk\u0142ad wykresu bez zaakceptowanych zale\u017cno\u015bci\"\/><\/figure>\n\n\n\n<p>zale\u017cno\u015bci ju\u017c istniej\u0105, ale nie oznacza to, \u017ce s\u0105 one akceptowane przez <strong>Packwerk<\/strong>. Do<br>zaakceptowa\u0107 zale\u017cno\u015b\u0107, musimy doda\u0107 konfiguracj\u0119 zale\u017cno\u015bci do <code>package.yml<\/code><br>w ka\u017cdym pakiecie. Skupimy si\u0119 na <code>mail_builders<\/code> poniewa\u017c jest to pakiet bez zale\u017cno\u015bci ko\u0142owych. Warto wspomnie\u0107, \u017ce <strong>Packwerk<\/strong> nie pozwoli nam zaakceptowa\u0107 zale\u017cno\u015bci ko\u0142owych.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\"># app\/packages\/mail_builders\/package.yml\n\n``ruby\nenforce_privacy: false\nenforce_dependencies: true\ndependencies:\n- app\/packages\/docs\n- app\/packages\/issues\n- app\/packages\/repos<\/code><\/pre>\n\n\n\n<p>Po dodaniu tej konfiguracji, <strong>Pocky<\/strong> pokoloruje zaakceptowane zale\u017cno\u015bci na zielono.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/6.png\" alt=\"graf z zaakceptowanymi zale\u017cno\u015bciami \" title=\"Przyk\u0142ad wykresu bez zaakceptowanych zale\u017cno\u015bci\"\/><\/figure>\n\n\n\n<p>Mo\u017cemy usun\u0105\u0107 <code>deprecated_references.yml<\/code> z <code>app\/packages\/mail_builders<\/code> i uruchomi\u0107<br><code>packwerk update-deprecations<\/code> ponownie. Plik nie zostanie wygenerowany ponownie, poniewa\u017c wszystkie<br>naruszenia zosta\u0142y naprawione dla tego pakietu. Wa\u017cne jest, aby wspomnie\u0107, \u017ce nawet je\u015bli nie Graph z zaakceptowanymi zale\u017cno\u015bciami<\/p>\n\n\n\n<p><strong><a href=\"https:\/\/thecodest.co\/pl\/blog\/hire-ror-developer\/\">Ruby<\/a> Modularyzacja w Railsach z Packwerk<\/strong> zaakceptowa\u0107 zale\u017cno\u015bci, nasza aplikacja nadal b\u0119dzie dzia\u0142a\u0107 jak poprzednio, ale teraz mamy wi\u0119cej<br>informacje do podejmowania decyzji i refaktoryzacji.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Usuni\u0119cie zale\u017cno\u015bci ko\u0142owych<\/h3>\n\n\n\n<p>W naszym poprzednim wykresie mieli\u015bmy wiele zale\u017cno\u015bci ko\u0142owych, kt\u00f3re trzeba by\u0142o jako\u015b rozwi\u0105za\u0107. Mamy na to r\u00f3\u017cne strategie:<\/p>\n\n\n\n<p>- Nie r\u00f3b nic,<\/p>\n\n\n\n<p>- Zaakceptuj zale\u017cno\u015bci, Scal pakiety,<\/p>\n\n\n\n<p>- Przeprowadzka <a href=\"https:\/\/thecodest.co\/pl\/dictionary\/what-is-code-refactoring\/\">kod<\/a> mi\u0119dzy pakietami,<\/p>\n\n\n\n<p>- Powielanie funkcji,&nbsp;<\/p>\n\n\n\n<p>- Wykonaj wstrzykiwanie zale\u017cno\u015bci lub wstrzykiwanie zale\u017cno\u015bci z typowaniem.<\/p>\n\n\n\n<p>Jedn\u0105 z kwestii jest to, \u017ce aby wykona\u0107 w\u0142a\u015bciwy refaktoring, musimy zna\u0107 baz\u0119 kodu. Nie jestem zaznajomiony z baz\u0105 kodu tego projektu, poniewa\u017c wzi\u0105\u0142em go jako przyk\u0142ad, wi\u0119c ze wzgl\u0119d\u00f3w praktycznych wybierzemy pierwsz\u0105 strategi\u0119, nie r\u00f3b nic. Nawet je\u015bli unikniemy wi\u0119kszo\u015bci refaktoryzacji, chcemy popracowa\u0107 nad zale\u017cno\u015bciami w <em>korze\u0144<\/em> pakiet.<\/p>\n\n\n\n<p>Pakiet g\u0142\u00f3wny zawiera wszystkie klejenia z <strong>Framework Rails<\/strong>Wszystkie klasy, po kt\u00f3rych dziedziczymy, b\u0119d\u0105 ze sob\u0105 wsp\u00f3\u0142pracowa\u0107. Tak wi\u0119c, aby rozwi\u0105za\u0107 problem zale\u017cno\u015bci ko\u0142owych, utworzymy nowy pakiet o nazwie rails w nast\u0119puj\u0105cych krokach:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Przenie\u015b wszystkie pliki i foldery application_ z aplikacji do folderu <code>app\/packages\/rails<\/code>.<\/li>\n\n\n\n<li>Utw\u00f3rz<code>package.yml<\/code> dla pakietu z tak\u0105 sam\u0105 konfiguracj\u0105 jak poprzednie pakiety.<\/li>\n\n\n\n<li>Dodaj wszystkie nowe \u015bcie\u017cki plik\u00f3w do <code>packwerk.yml<\/code>.<\/li>\n\n\n\n<li>Dodaj <code>app\/packages\/rails<\/code> jako zale\u017cno\u015b\u0107 od reszty pakiet\u00f3w.<\/li>\n<\/ol>\n\n\n\n<p>Po utworzeniu pakietu zaczniemy zauwa\u017ca\u0107 wiele plik\u00f3w, kt\u00f3re mo\u017cna przeorganizowa\u0107. Po przeniesieniu wszystkiego do odpowiedniego pakietu i zaakceptowaniu<br>b\u0119dziemy mieli now\u0105 struktur\u0119 i czystszy wykres.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/graph.png\" alt=\"Struktura pakietu z pakietem szyn \" title=\"Struktura pakietu z przyk\u0142adem pakietu rails\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/8.png\" alt=\"Wykres bez g\u0142\u00f3wnych zale\u017cno\u015bci ko\u0142owych\" title=\"Przyk\u0142ad wykresu bez g\u0142\u00f3wnych zale\u017cno\u015bci ko\u0142owych\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usuni\u0119cie zale\u017cno\u015bci z pakietu g\u0142\u00f3wnego<\/h3>\n\n\n\n<p>Teraz nasz wykres wygl\u0105da znacznie lepiej, by\u0142oby \u015bwietnie, gdyby\u015bmy mogli usun\u0105\u0107 wszystkie zale\u017cno\u015bci z pakietu root. Je\u015bli sprawdzimy deprecated_references.yml w pakiecie g\u0142\u00f3wnym, zauwa\u017cymy, \u017ce wi\u0119kszo\u015b\u0107 z nich pochodzi z <code>test<\/code> , <code>lib\/tasks<\/code> , <code>db<\/code> i <code>konfiguracja<\/code><br>folder. Aby rozwi\u0105za\u0107 te zale\u017cno\u015bci, utworzymy folder testowy w ka\u017cdym pakiecie. Maj\u0105c co\u015b takiego jak <code>app\/packages\/users\/test<\/code>. Nast\u0119pnie zamierzamy wykluczy\u0107 <code>lib\/tasks<\/code> , <code>db<\/code> i <code>konfiguracja<\/code>w\u015br\u00f3d innych folder\u00f3w z <strong>Packwerk<\/strong> poniewa\u017c te zale\u017cno\u015bci nie s\u0105 tak naprawd\u0119 wa\u017cne w naszej analizie i nie mamy \u0142atwego sposobu na ich rozwi\u0105zanie. Dodamy nast\u0119puj\u0105ce elementy do naszego <em>packwerk.yml<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\">exclude:\n- \"{bin,node_modules,script,tmp,vendor,lib,db,config,perf_scripts}\/**\/*\"\n- \"lib\/tasks\/**\/*.rake\"<\/code><\/pre>\n\n\n\n<p>Po przeniesieniu wszystkich test\u00f3w z pakietu root i wykluczeniu folder\u00f3w z analizy otrzymamy nowy wykres bez zale\u017cno\u015bci root.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/9.png\" alt=\"Wykres bez zale\u017cno\u015bci g\u0142\u00f3wnych\" title=\"Wykres bez zale\u017cno\u015bci g\u0142\u00f3wnych\"\/><\/figure>\n\n\n\n<p>Jak widzimy, wci\u0105\u017c mamy zale\u017cno\u015bci ko\u0142owe w<code>u\u017cytkownicy<\/code> , <code>repozytoria<\/code> oraz <code>dokumenty<\/code> . Chocia\u017c ich nie rozwi\u0105zali\u015bmy, mamy teraz wa\u017cne informacje do przekazania. Wiemy, \u017ce ka\u017cdy <a href=\"https:\/\/thecodest.co\/pl\/blog\/how-to-hire-the-best-outsourced-development-team-for-a-scaleup\/\">zesp\u00f3\u0142<\/a> kt\u00f3ry wprowadza zmiany w jednym z tych pakiet\u00f3w, prawdopodobnie b\u0119dzie musia\u0142 wprowadzi\u0107 zmiany w pakietach z zale\u017cno\u015bci\u0105 cyrkularn\u0105. Z drugiej strony wiemy, \u017ce zesp\u00f3\u0142 mo\u017ce pracowa\u0107 nad <code>github_fetchers<\/code> wy\u0142\u0105cznie wiedz\u0105c, jakie pakiety s\u0105<br>ulegaj\u0105c zmianom w ka\u017cdej chwili.<\/p>\n\n\n\n<p>Mo\u017cesz znale\u017a\u0107 ko\u0144cowy rezultat projektu <a href=\"https:\/\/github.com\/niconisoria\/codetriage-packwerk\" rel=\"nofollow\">tutaj<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Nast\u0119pny krok<\/h3>\n\n\n\n<p>Nast\u0119pnym krokiem mo\u017ce by\u0107 wymuszenie sta\u0142ej prywatno\u015bci w ka\u017cdym pakiecie i ujawnienie tylko publicznego interfejsu API, kt\u00f3ry b\u0119dzie dost\u0119pny z innych pakiet\u00f3w. Mo\u017cesz \u0142atwo skonfigurowa\u0107, gdzie tw\u00f3j interfejs API zostanie umieszczony w <em>package.yml<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"ruby\" class=\"language-ruby\">enforce_privacy: true\nenforce_dependencies: true\npublic_path: my\/custom\/path\/<\/code><\/pre>\n\n\n\n<p><code> <\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wnioski<\/h2>\n\n\n\n<p><strong>Packwerk<\/strong> daje nam wiele informacji o naszej aplikacji i dzi\u0119ki tym informacjom mo\u017cemy podejmowa\u0107 decyzje maj\u0105ce na celu popraw\u0119 przep\u0142ywu pracy naszych zespo\u0142\u00f3w. Chocia\u017c proces wydawa\u0142 si\u0119 d\u0142ugi i wymaga\u0142 wielu konfiguracji, nie musi tak by\u0107 zawsze. Mo\u017cemy zacz\u0105\u0107 tworzy\u0107 pakiety tylko dla nowego kodu dodanego do naszej aplikacji, a nast\u0119pnie stopniowo modularyzowa\u0107. Teraz mo\u017cemy zacz\u0105\u0107 m\u00f3wi\u0107 o stopniowej modularyzacji, kt\u00f3ra jest koncepcj\u0105 wprowadzon\u0105 przez Stephana Hagemanna. <em>\"Po raz pierwszy mo\u017cemy zdecydowa\u0107 si\u0119 na rozpocz\u0119cie modularyzacji cz\u0119\u015bci kodu w aspiracyjny spos\u00f3b... Pozwala nam to stworzy\u0107 stopniowo rozwijaj\u0105cy si\u0119 system wsparcia w kierunku lepszej struktury aplikacji\".<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u0179r\u00f3d\u0142a<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/leanpub.com\/package-based-rails-applications\" rel=\"nofollow\">Stopniowa modularyzacja dla Ruby on Rails - Stephan Hagemann<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/shopify.engineering\/enforcing-modularity-rails-apps-packwerk\">Wymuszanie modu\u0142owo\u015bci w aplikacjach Rails za pomoc\u0105 Packwerk<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/Shopify\/packwerk\">Packwerk Github<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/niconisoria\/codetriage-packwerk\">Kod \u017ar\u00f3d\u0142owy artyku\u0142u<\/a><\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/thecodest.co\/contact\"><img decoding=\"async\" src=\"\/app\/uploads\/2024\/05\/cta_2.jpeg\" alt=\"Doradztwo w zakresie rozwoju produkt\u00f3w cyfrowych\"\/><\/a><\/figure>\n\n\n\n<p><strong>Czytaj wi\u0119cej<\/strong><\/p>\n\n\n\n<p><a href=\"https:\/\/thecodest.co\/blog\/graphql-ruby-what-about-performance\">GraphQL Ruby. Co z wydajno\u015bci\u0105?<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/thecodest.co\/blog\/rails-and-other-means-of-transport\">Szyny i inne \u015brodki transportu<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/thecodest.co\/blog\/rails-development-with-tmux-vim-fzf-ripgrep\">Rails Development z TMUX, Vim, Fzf + Ripgrep<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>W drugim odcinku naszej modularyzacji Ruby on Rails z Packwerk przyjrzymy si\u0119 bli\u017cej koncepcji aplikacji jako pakietu.<\/p>","protected":false},"author":2,"featured_media":3567,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[8],"tags":[],"class_list":["post-3566","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Ruby on Rails modularization with Packwerk Episode II - The Codest<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/thecodest.co\/pl\/blog\/modularyzacja-ruby-on-rails-z-packwerk-odcinek-ii\/\" \/>\n<meta property=\"og:locale\" content=\"pl_PL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ruby on Rails modularization with Packwerk Episode II\" \/>\n<meta property=\"og:description\" content=\"In the second episode of our Ruby on Rails modularization with Packwerk we will take a close look at the concept of application as an package.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/thecodest.co\/pl\/blog\/modularyzacja-ruby-on-rails-z-packwerk-odcinek-ii\/\" \/>\n<meta property=\"og:site_name\" content=\"The Codest\" \/>\n<meta property=\"article:published_time\" content=\"2022-01-10T15:47:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-28T14:05:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"960\" \/>\n\t<meta property=\"og:image:height\" content=\"540\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"thecodest\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"thecodest\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minut\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/\"},\"author\":{\"name\":\"thecodest\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/person\\\/7e3fe41dfa4f4e41a7baad4c6e0d4f76\"},\"headline\":\"Ruby on Rails modularization with Packwerk Episode II\",\"datePublished\":\"2022-01-10T15:47:14+00:00\",\"dateModified\":\"2026-04-28T14:05:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/\"},\"wordCount\":1295,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png\",\"articleSection\":[\"Software Development\"],\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/\",\"url\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/\",\"name\":\"Ruby on Rails modularization with Packwerk Episode II - The Codest\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png\",\"datePublished\":\"2022-01-10T15:47:14+00:00\",\"dateModified\":\"2026-04-28T14:05:25+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#breadcrumb\"},\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#primaryimage\",\"url\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png\",\"contentUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/05\\\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png\",\"width\":960,\"height\":540},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/blog\\\/ruby-on-rails-modularization-with-packwerk-episode-ii\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/thecodest.co\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruby on Rails modularization with Packwerk Episode II\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#website\",\"url\":\"https:\\\/\\\/thecodest.co\\\/\",\"name\":\"The Codest\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/thecodest.co\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pl-PL\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#organization\",\"name\":\"The Codest\",\"url\":\"https:\\\/\\\/thecodest.co\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/03\\\/thecodest-logo.svg\",\"contentUrl\":\"https:\\\/\\\/thecodest.co\\\/app\\\/uploads\\\/2024\\\/03\\\/thecodest-logo.svg\",\"width\":144,\"height\":36,\"caption\":\"The Codest\"},\"image\":{\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/pl.linkedin.com\\\/company\\\/codest\",\"https:\\\/\\\/clutch.co\\\/profile\\\/codest\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/thecodest.co\\\/#\\\/schema\\\/person\\\/7e3fe41dfa4f4e41a7baad4c6e0d4f76\",\"name\":\"thecodest\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g\",\"caption\":\"thecodest\"},\"url\":\"https:\\\/\\\/thecodest.co\\\/pl\\\/author\\\/thecodest\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Modularyzacja Ruby on Rails za pomoc\u0105 Packwerk Episode II - The Codest","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/thecodest.co\/pl\/blog\/modularyzacja-ruby-on-rails-z-packwerk-odcinek-ii\/","og_locale":"pl_PL","og_type":"article","og_title":"Ruby on Rails modularization with Packwerk Episode II","og_description":"In the second episode of our Ruby on Rails modularization with Packwerk we will take a close look at the concept of application as an package.","og_url":"https:\/\/thecodest.co\/pl\/blog\/modularyzacja-ruby-on-rails-z-packwerk-odcinek-ii\/","og_site_name":"The Codest","article_published_time":"2022-01-10T15:47:14+00:00","article_modified_time":"2026-04-28T14:05:25+00:00","og_image":[{"width":960,"height":540,"url":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png","type":"image\/png"}],"author":"thecodest","twitter_card":"summary_large_image","twitter_misc":{"Written by":"thecodest","Est. reading time":"8 minut"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#article","isPartOf":{"@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/"},"author":{"name":"thecodest","@id":"https:\/\/thecodest.co\/#\/schema\/person\/7e3fe41dfa4f4e41a7baad4c6e0d4f76"},"headline":"Ruby on Rails modularization with Packwerk Episode II","datePublished":"2022-01-10T15:47:14+00:00","dateModified":"2026-04-28T14:05:25+00:00","mainEntityOfPage":{"@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/"},"wordCount":1295,"commentCount":0,"publisher":{"@id":"https:\/\/thecodest.co\/#organization"},"image":{"@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#primaryimage"},"thumbnailUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png","articleSection":["Software Development"],"inLanguage":"pl-PL","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/","url":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/","name":"Modularyzacja Ruby on Rails za pomoc\u0105 Packwerk Episode II - The Codest","isPartOf":{"@id":"https:\/\/thecodest.co\/#website"},"primaryImageOfPage":{"@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#primaryimage"},"image":{"@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#primaryimage"},"thumbnailUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png","datePublished":"2022-01-10T15:47:14+00:00","dateModified":"2026-04-28T14:05:25+00:00","breadcrumb":{"@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#breadcrumb"},"inLanguage":"pl-PL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/"]}]},{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#primaryimage","url":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png","contentUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/05\/ruby_on_rails_modularization_with_packwerk_-__-_episode_2.png","width":960,"height":540},{"@type":"BreadcrumbList","@id":"https:\/\/thecodest.co\/blog\/ruby-on-rails-modularization-with-packwerk-episode-ii\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/thecodest.co\/"},{"@type":"ListItem","position":2,"name":"Ruby on Rails modularization with Packwerk Episode II"}]},{"@type":"WebSite","@id":"https:\/\/thecodest.co\/#website","url":"https:\/\/thecodest.co\/","name":"The Codest","description":"","publisher":{"@id":"https:\/\/thecodest.co\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/thecodest.co\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pl-PL"},{"@type":"Organization","@id":"https:\/\/thecodest.co\/#organization","name":"The Codest","url":"https:\/\/thecodest.co\/","logo":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/thecodest.co\/#\/schema\/logo\/image\/","url":"https:\/\/thecodest.co\/app\/uploads\/2024\/03\/thecodest-logo.svg","contentUrl":"https:\/\/thecodest.co\/app\/uploads\/2024\/03\/thecodest-logo.svg","width":144,"height":36,"caption":"The Codest"},"image":{"@id":"https:\/\/thecodest.co\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/pl.linkedin.com\/company\/codest","https:\/\/clutch.co\/profile\/codest"]},{"@type":"Person","@id":"https:\/\/thecodest.co\/#\/schema\/person\/7e3fe41dfa4f4e41a7baad4c6e0d4f76","name":"thecodest","image":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/secure.gravatar.com\/avatar\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5dbfe6a1e8c86e432e8812759e34e6fe82ebac75119ae3237a6c1311fa19caf4?s=96&d=mm&r=g","caption":"thecodest"},"url":"https:\/\/thecodest.co\/pl\/author\/thecodest\/"}]}},"_links":{"self":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts\/3566","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/comments?post=3566"}],"version-history":[{"count":10,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts\/3566\/revisions"}],"predecessor-version":[{"id":7983,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/posts\/3566\/revisions\/7983"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/media\/3567"}],"wp:attachment":[{"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/media?parent=3566"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/categories?post=3566"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thecodest.co\/pl\/wp-json\/wp\/v2\/tags?post=3566"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}