27.09.20225 min

Luccas CorreaFull-stack DeveloperEstúdio 89

Jak organizować projekt w Django

Poznaj kilka przydatnych lekcji na temat organizacji i struktury projektów Django.

Jak organizować projekt w Django

Architektura projektu oprogramowania jest punktem definiującym jego długoterminowy sukces. Jeśli architektura nie jest dobrze określona, utrzymanie staje się coraz trudniejsze, a wdrażanie nowych funkcji z czasem staje się uciążliwe i wymaga ponownego napisania sporych części aplikacji.

W tym artykule omówię krótko kilka wyciągniętych przez lata lekcji, które posłużą do lepszej organizacji projektów Django. Znajdują się tutaj rzeczy, które można by zastosować do każdego projektu programistycznego, ale dodam tu i ówdzie kilka porad dotyczących konkretnie Django.

To nie jest w żadnym wypadku ostateczny przewodnik, ponieważ niektóre z tych tematów mogą być łatwo rozbudowane o wiele artykułów (a może nawet książek!), jednak powinny dostarczyć materiału do przemyśleń.


Samodzielne aplikacje

Django zachęca do rozdzielenia kawałków kodu na osobne aplikacje. Nie jest to przypadek, ponieważ jest to absolutnie niezbędne do utrzymania aplikacji w stanie czystym i łatwym do pracy.

Podczas zapoznawania się z wymaganiami projektu, nad którym pracujesz, jednym z pierwszych kroków, jakie powinieneś wykonać, jest pogrupowanie powiązanych funkcji, przy jednoczesnym wyznaczeniu wyraźnych granic pomiędzy niepowiązanymi częściami. Te niepowiązane części będą tworzyły różne aplikacje Django w twojej aplikacji.

Ważną kwestią jest to, że aplikacje powinny być całkowicie oddzielne, bez bezpośrednich odniesień między nimi. Sprawdzona zasada mówi, że aplikacja nigdy nie powinna mieć potrzeby bezpośredniego importowania modelu z innej aplikacji. Jeśli kiedykolwiek aplikacja potrzebuje interakcji z inną, powinna to zrobić poprzez wywołanie jakiejś funkcji pomocniczej, która jest zaimplementowana w tej drugiej aplikacji (lub jeszcze lepiej, użyć sygnały do obsługi komunikacji między aplikacjami).

Powinno to utrzymać wewnętrzne elementy każdej aplikacji osłonięte przed światem zewnętrznym, co znacznie ułatwia wprowadzanie zmian bez konieczności rozłączenia niepowiązanych części aplikacji.


Oddzielenie logiki modelu od widoków

Django używa paradygmatu model-view-template (MVT), który jest analogiczny do paradygmatu model-view-controller (MVC). Ten wzorzec architektoniczny zachęca do utrzymywania frontend kodu oddzielonego od wewnętrznej logiki aplikacji. Jednak bardzo łatwo jest mieszać logikę modelu i widoku.

Ogólnie rzecz biorąc, widok powinien być odpowiedzialny za parsowanie wszelkich danych, które pochodzą z twojej aplikacji frontendowej. Oznacza to konwersję ciągów znaków na daty, walidację parametrów i przyjazny dla użytkownika komunikat o błędzie, gdy jest to konieczne. Z drugiej strony nie powinien być odpowiedzialny za manipulowanie instancjami modelu, modyfikowanie ich właściwości czy uruchamianie zapytań.

Twój kod widoku powinien być czysty i prosty z wyłącznym celem przygotowania parametrów, które powinny zostać wysłane do twojej logiki backendu. Twoja logika backendu może być wykonywana przez niestandardowe metody menedżera lub twoje własne klasy i funkcje, które będą manipulować instancjami modelu i uruchamiać zapytania.

Dzięki temu logika backendu jest osłonięta przed światem zewnętrznym, co pozwala na jej ponowne wykorzystanie bez względu na to, w jaki sposób jest udostępniana. Przykładowo, możesz mieć pewną logikę, która jest uruchamiana przez punkt końcowy REST, który wykorzystuje framework Django Rest i wykorzystuje tę samą logikę gdzieś indziej, gdzie używasz formularza Django do odbierania danych wejściowych. Równocześnie, kiedy zapewnia taką elastyczność, pisanie chirurgicznie precyzyjnych testów staje się również znacznie łatwiejsze.


Izolowanie zależności

Zawsze, gdy dodajesz zależności do projektu, powinieneś naprawdę uważnie się nad tym zastanowić. Biblioteki dodają kruchości twojej aplikacji, ponieważ będziesz zależny od kodu, który nie został napisany przez ciebie lub twój zespół, z którym być może nie miałeś jeszcze nic wspólnego. Biblioteka, która dziś może wyglądać obiecująco, może zostać pozostawiona przez jej autorów na pastwę losu i pozostawić cię z nierozwiązanym bugiem.

Nie oznacza to jednak, że powinieneś być całkowicie przeciwny dodawaniu zależności do swoich projektów. Budowanie wszystkiego od podstaw za każdym razem nie byłoby najmądrzejszą decyzją. Istnieje subtelna równowaga pomiędzy szybkim dodawaniem funkcji do aplikacji i upewnieniem się, że aplikacja może sprawnie rozwijać się przez lata.

Generalnie, zawsze gdy potrzebuję dodać zależność do projektu, najpierw zgłębiam dokładnie to, co muszę rozwiązać i jak dana biblioteka to rozwiązuje. Oznacza to przejrzenie dokumentacji biblioteki i jej kodu źródłowego. Jeśli widzę, że sposób, w jaki biblioteka rozwiązuje problem, jest wystarczająco prosty, sam go zaimplementuję. Jeśli nie, sprawdzę, czy biblioteka ma wystarczająco dużą liczbę opiekunów i czy jej kod źródłowy jest dobrze uporządkowany.

Następnie, gdy zdecydujesz, że zależność rzeczywiście musi zostać dodana do projektu i nie ma prostego sposobu na obejście tego, jest jeszcze jedna wskazówka, której możesz użyć, aby ułatwić sobie życie, jeśli kiedykolwiek będziesz musiał ją zastąpić. Sztuczka polega na tym, żeby całkowicie odizolować bibliotekę od reszty twojej aplikacji.

Powiedzmy, że potrzebujesz biblioteki do wysyłania powiadomień push na urządzenia mobilne. Zamiast importować bibliotekę bezpośrednio, gdy potrzebujesz wysłać powiadomienie, zdefiniuj własną klasę lub funkcję, której jedynym celem jest wysyłanie powiadomień push (najlepiej w swojej własnej aplikacji, która jest odpowiedzialna za obsługę logiki powiadomień push). Następnie wywołaj tę pojedynczą funkcję w całej aplikacji.

Jeśli kiedyś przyjdzie taki dzień, że ta biblioteka stanie się przestarzała lub wkradnie się do niej paskudny, nierozwiązany błąd, możesz po prostu zastąpić ją inną lub nawet zakodować własną implementację bez konieczności modyfikowania jakiejkolwiek logiki aplikacji. Jest to lżejsza wersja koncepcji głoszonej przez Czystą architekturę (co może być przesadą w zależności od projektu, ale zdecydowanie powinieneś się temu przyjrzeć).

Ta strategia nie jest niczym nowym, samo Django używa tego w całym swoim kodzie źródłowym do radzenia sobie z różnymi backendami baz danych, backendami emaili, cache’owaniem, itp. To pewny sposób, aby utrzymać kod zabezpieczony przed światem zewnętrznym, pozwalając na zamianę zależności bez przeszkód.


Testy, testy, testy

Napisałem kilka innych artykułów na temat tego, jak testować swoje aplikacje i zawsze warto podkreślać, jak ważne są testy dla długoterminowego przetrwania twojej aplikacji.

Nawet jeśli podejmiesz wszystkie środki ostrożności opisane w tym artykule, są szanse, że w pewnym momencie zdasz sobie sprawę, że aby wdrożyć pewną funkcję, będziesz musiał refaktoryzować jakąś logikę, która działała dobrze przez długi czas. To właśnie wtedy posiadanie dobrze napisanych testów pozwoli Ci odetchnąć z ulgą.

Testy pomagają upewnić się, że Twoja aplikacja będzie działać w przyszłości tak samo dobrze jak obecnie. Dzięki temu będziesz miał również dużo więcej pewności siebie, gdy będziesz musiał refaktoryzować duże porcje kodu.


Wnioski

Myślę, że architektura oprogramowania to coś, czego tak naprawdę nigdy nie przestajesz się uczyć. Czytanie artykułów takich jak ten może wskazać ci kierunek i pokazać rzeczy, na które możesz spojrzeć głębiej, jeśli jesteś tym zainteresowany, jednak wszystko to ulotni się, gdy zaczniesz mierzyć się z tymi problemami w prawdziwym świecie.


Tekst w oryginale znajdziesz na Better Programming.

<p>Loading...</p>