Czysta architektura (nawet z Django!) Sebas an PyWaw 72

Podobne dokumenty
Kurs rozszerzony języka Python

Laboratorium Kierunki Rozwoju oprogramowania REST, Django

Spring Framework - wprowadzenie i zagadnienia zaawansowane

Zaawansowany kurs języka Python

Aplikacje WWW. Krzysztof Ciebiera. 3 kwietnia 2014

Program szkolenia: Receptury testowania automatycznego - problemy, strategie, taktyki, techniki, narzędzia

Testy aplikacji webowych

Programowanie w Ruby

Szkolenie wycofane z oferty. Program szkolenia: Enterprise Java Beans 3.0/3.1

Aplikacje webowe z wykorzystaniem Node.js oraz Express

Kurs rozszerzony języka Python

Behavior Driven Development (BDD)

Implementacja Domain Driven Design - wzorce architektoniczne (część

Programowanie zorientowane obiektowo. Mateusz Kołecki

Programowanie komponentowe 5

Testowanie aplikacji. Kurs języka Ruby

TDD w Django South Sorl Haystack + Whoosh Małe, a cieszy Deployment Koniec. Wspomagacze Django. Jan Filipowski. 25 maja 2010

Program szkolenia: Architektura aplikacji i systemów - Wzorce architektoniczne dla projektantów

Programowanie i projektowanie obiektowe

Paweł Rajba

Zwinna współpraca programistów i testerów z wykorzystaniem BDD i. by Example (JBehave/Spock/SpecFlow)

Tworzenie aplikacji Web Alicja Zwiewka. Page 1

Program szkolenia: Wzorce projektowe i ich implementacja w C# oraz testowanie automatyczne

Program szkolenia: REST i Microservices w PHP

PHP revisited - odświerzenie spojrzenia na programowanie w PHP

Wieloplatformowe aplikacje sieciowe. dr inż. Juliusz Mikoda mgr inż. Anna Wawszczak

Program szkolenia: Test Driven Development (TDD) using Spock or JUnit 5

Techniki efektywnego testowania kodu dla programistów Java (Spock

Kurs rozszerzony języka Python

Poznaj ASP.NET MVC. Kamil Cieślak Microsoft Student Partner

Produktywne tworzenie aplikacji webowych z wykorzystaniem Groovy i

Aplikacja webowa w Javie szybkie programowanie biznesowych aplikacji Spring Boot + Vaadin

W celu uruchomienia kontrolera należy w katalogu głównym kontrolera z wiersza poleceń wydać następujące polecenie: $ java -jar target/floodlight.

Drobne błędy w portalach WWW

Projektowanie obiektowe oprogramowania Wzorce architektury aplikacji (3) Wykład 11 Repository, Unit of Work Wiktor Zychla 2017

Testowanie aplikacji mobilnych na platformie Android - architektura, wzorce, praktyki i narzędzia

Michał Sierzputowski. Zautomatyzuj swoje testy automatyczne oparte o Selenium

Instrukcja laboratoryjna

Kurs języka Python. Wykład 14. Marcin Młotkowski. 25 stycznia Python i Apache Pythonowe platformy aplikacyjne. Dystrybucja aplikacji w U*IX

Programowanie obiektowe

Dekoratora używa się wstawiając linijkę zaczynającą się przed definicją dekorowanego obiektu (klasy czy funkcji).

Plan. krótkie opisy modułów. 1 Uwagi na temat wydajności CPython a. 2 Podstawowe techniki poprawiające wydajność obliczeniową

Web Services w połączeniu z aplikacjami uruchamianymi na urządzeniach mobilnych

Zrąb webowy dla perfekcjonistów z terminami. autor: Kamil Adamczyk

SSL Reseller. Dokumentacja techniczna v.1.0 z dnia

Program szkolenia: Wzorce projektowe w C++

Projektowanie obiektowe oprogramowania Wzorce architektury aplikacji (3) Wykład 11 Repository, Unit of Work Wiktor Zychla 2016

Programowanie w Ruby

Test-Driven Development

n+1 sposobów na automatyczne testy aplikacji mobilnych WrotQA, webinar Łukasz Siudakiewicz Damian Szczurek Automation Test Engineer

Kurs języka Python. Wykład 5. Marcin Młotkowski. 9 listopada Rodzaje parametrów funkcji. 2 Biblioteka Tk. 3 Układanie kontrolek w oknie

Omówienie wzorców wykorzystywanych w Prism 5.0. Dominika Różycka

Receptury - niezbędnik projektanta i architekta

Programowanie i projektowanie obiektowe

PRZETWARZANIE ROZPROSZONE ZADAN` Mariusz Gil 4Developers 2012, Poznań

Laboratorium 2. def detail(request, question_id): return HttpResponse("Patrzysz na pytanie %s." % question_id)

Tworzenie zaawansowanych aplikacji w środowisku ios. Wykład 2 Objective-C. Tomasz Idzi

Architektura systemów webowych wysokiej przepustowości. na przykładzie Wikia

Wzorce projektowe i architektura dla platformy Java EE

WICKET VS. DJANGO. Leszek Gawron vs. Michał Leszczyński

Pico. Wstęp do kontenerów IoC.

Zagadnienia Programowania Obiektowego Agata Hejmej

Nowoczesne projektowanie aplikacji intrnetowych - opis przedmiotu

Kurs języka Python. Wątki

1 Wprowadzenie do J2EE

Zaawansowany kurs języka Python

Full Stack JavaScript z Angular i Nest. Dni: 5. Opis: Adresaci szkolenia

Programowanie poprzez testy z wykorzystaniem JUnit

Całościowe podejście do testowania automatycznego dla programistów. /C#/PHP (TDD, BDD, Spec. by Example, wzorce, narzędzia)

NoSQL Not Only SQL, CouchDB. I.Wojnicki, NoSQL. Apache CouchDB has started. Time to relax. Igor Wojnicki

METODY PROGRAMOWANIA

Instrukcja 10 Laboratorium 13 Testy akceptacyjne z wykorzystaniem narzędzia FitNesse

Programowanie obiektowe

Grzegorz Ruciński. Warszawska Wyższa Szkoła Informatyki Promotor dr inż. Paweł Figat

Projektowanie obiektowe oprogramowania Testowanie oprogramowania Wykład 13 Wiktor Zychla 2014

Metaprogramowanie w Ruby

AKADEMIA GÓRNICZO-HUTNICZA Wydział Elektrotechniki, Automatyki, Elektroniki i Informatyki

Kurs rozszerzony języka Python

Aplikacje WWW - lab 11

Programowanie Zespołowe

Celem tych ćwiczeń jest zapoznanie się z klasyfikacją za pomocą sieci neuronowych.

Programowanie w Ruby

Automatyzacja testów aplikacji webowych w Selenium podstawy. Natalia Krawczyk

Serwer WWW na przykªadzie Django

Narzędzia OWASP dla developerów OWASP ESAPI & AppSensor OWASP The OWASP Foundation

Zaawansowany kurs języka Python

Program szkolenia: Wprowadzenie do Domain Driven Design dla biznesu (część 0)

Programowanie obiektowe

Całościowe podejście do testowania automatycznego dla programistów. (TDD, BDD, Spec. by Example, wzorce, narzędzia)

Zaawansowany kurs języka Python

Automatyczne testowanie aplikacji Android


Testowanie aplikacji Java Servlets

Wątki i komunikacja między nimi w języku Python

Komunikacja Człowiek-Komputer

Programowanie kontraktowe w Javie

Programowanie dla iphone projektowanie interfejsu użytkownika


Transkrypt:

Czysta Architektura (nawet z Django!) Sebastian Buczyński @ PyWaw 15.01.2018

Domain Driven Design Łukasz Balcerzak @ PyWaw 64 Event Sourcing w aplikacjach opartych o framework Django Wojtek Erbetowski @ PyWaw 68 Czysta architektura (nawet z Django!) Sebas an Buczyński @ PyWaw 72

Co daje Czysta Architektura? 1. Niezależność od frameworków 2. Testowalność 3. Niezależność od UI 4. Niezależność od bazy danych

Projekt: Aukcje online

Historyjki użytkownika Jako licytujący chcę złożyć ofertę na aukcji by ją wygrać Jako licytujący chcę zostać powiadomiony mailowo gdy moja oferta jest najwyższa Jako administrator chcę wycofać ofertę z aukcji

Django django-admin startproject mysite. django-admin startapp auctions

Modele przodem class Auction(models.Model): title = models.charfield(...) initial_price = models.decimalfield(...) current_price = models.decimalfield(...) def withdraw_bids(self, bids):... @property def winners(self):... class Bid(models.Model): amount = models.decimalfield(...) bidder = models.foreignkey(...) auction = models.foreignkey(auction, on_delete=protect)

Historyjki użytkownika Jako licytujący chcę złożyć ofertę na aukcji by ją wygrać Jako licytujący chcę zostać powiadomiony mailowo gdy moja oferta jest najwyższa Jako administrator chcę wycofać ofertę z aukcji

def save_related(self, request, form, formsets, *args, **kwargs): ids_of_deleted_bids = self._get_ids_of_deleted_bids(formsets) bids_to_withdraw = Bid.objects.filter( pk in=ids_of_deleted_bids) auction = form.instance old_winners = list(auction.winners) auction.withdraw_bids(bids_to_withdraw) new_winners = list(auction.winners) self._notify_new_winners(new_winners) super().save_related(request, _form, formsets, *args, **kwarg

def save_related(self, request, form, formsets, *args, **kwargs): ids_of_deleted_bids = self._get_ids_of_deleted_bids(formsets) bids_to_withdraw = Bid.objects.filter( pk in=ids_of_deleted_bids) auction = form.instance old_winners = list(auction.winners) auction.withdraw_bids(bids_to_withdraw) new_winners = list(auction.winners) self._notify_new_winners(new_winners) super().save_related(request, _form, formsets, *args, **kwarg

def save_related(self, request, form, formsets, *args, **kwargs): ids_of_deleted_bids = self._get_ids_of_deleted_bids(formsets) bids_to_withdraw = Bid.objects.filter( pk in=ids_of_deleted_bids) auction = form.instance old_winners = list(auction.winners) auction.withdraw_bids(bids_to_withdraw) new_winners = list(auction.winners) self._notify_new_winners(new_winners) super().save_related(request, _form, formsets, *args, **kwarg

class WithdrawingBid: def withdraw_bids(self, auction_id, bids_ids): auction = Auction.objects.get(pk=auction_id) bids_to_withdraw = Bid.objects.filter( pk in=ids_of_deleted_bids) old_winners = list(auction.winners) auction.withdraw_bids(bids_to_withdraw) new_winners = list(auction.winners) self._notify_new_winners(new_winners)

Czysta architektura - element #1 UseCase Interactor

UseCase - odpowiedzialności Orkiestracja całego procesu Jedyny sposób zmiany stanu aplikacji

A testy?!

from django.test import TestCase class LoginTestCase(TestCase): def test_login(self): Testy przez widoki # First check for the default behavior response = self.client.get('/sekrit/') self.assertredirects(response, '/accounts/login/?next=/se

Co zrobiliśmy nie tak? Poszukajmy w necie... class MyTest(unittest.TestCase): def test_add(self): expected = 7 self.assertequal(add(3, 4), 7) Obserwacja: Brak efektów ubocznych i zależności ułatwia testowanie

class WithdrawingBidUseCase: def withdraw_bids(self, auction_id, bids_ids): auction = Auction.objects.get(pk=auction_id) bids_to_withdraw = Bid.objects.filter( pk in=ids_of_deleted_bids) old_winners = list(auction.winners) auction.withdraw_bids(bids_to_withdraw) new_winners = list(auction.winners) self._notify_new_winners(new_winners)

class WithdrawingBidUseCase: def withdraw_bids(self, auction_id, bids_ids): auction = self.auctions_repository.get(auction_id) bids = self.bids_repository.get_by_ids(bids_ids) old_winners = list(auction.winners) auction.withdraw_bids(bids) new_winners = list(auction.winners) self.auctions_repository.save(auction) for bid in bids: self.bids_repository.save(bid) self._notify_new_winners(new_winners)

Czysta architektura - element #2 class AuctionsRepo(metaclass=ABCMeta): @abstractmethod def get(self, auction_id): pass @abstractmethod def save(self, auction): pass Interface / Port

Czysta architektura - element #3 class DjangoAuctionsRepo(AuctionsRepo): def get(self, auction_id): return Auction.objects.get(pk=auction_id) Interface / Port Adapter

Łączymy razem class WithdrawingBidUseCase: def init (self, auctions_repository: AuctionsRepo): self.auctions_repository = auctions_repository django_adapter = DjangoAuctionsRepo() withdrawing_bid_uc = WithdrawingBidUseCase(django_adapter)

class WithdrawingBidUseCase: Dependency Injection auctions_repo: AuctionsRepo =... class WithdrawingBidUseCase: auctions_repo: AuctionsRepo = inject.attr(auctionsrepo) import inject def configure_inject(binder: inject.binder): binder.bind(auctionsrepo, DjangoAuctionsRepo()) inject.configure_once(configure_inject) Dependency Injec on pozwala odwrócić zależności i utrzymać kod jeszcze czystszym Cześć konfiguracji; w Django dobrym miejscem jest AppConfig.ready()

Korzyści z dodatkowej warstwy Ułatwia zrozumienie Prawdziwe testy jednostkowe logiki aplikacji Zrównoleglenie pracy nad tym samym zadaniem Możliwość odroczenia decyzji

Nadal logika jest splątana z bazą danych! class WithdrawingBidUseCase: def withdraw_bids(self, auction_id, bids_ids): auction = self.auctions_repository.get(auction_id) bids = self.bids_repository.get_by_ids(bids_ids) old_winners = list(auction.winners) auction.withdraw_bids(bids) new_winners = list(auction.winners) self.auctions_repository.save(auction) for bid in bids: self.bids_repository.save(bid) self._notify_new_winners(new_winners)

Czysta architektura - element #0 class Auction: def init (self, id: int, title: str, bids: List[Bid]): self.id = id self.title = title self.bids = bids def withdraw_bids(self, bids: List[Bid]):... def make_a_bid(self, bid: Bid):... @property def winners(self):... En ty

Czysta architektura - element #3 class DjangoAuctionsRepo(AuctionsRepo): def get(self, auction_id: int) -> Auction: auction_model = Auction.objects.prefetch_related( 'bids' ).get(pk=auction_id) bids = [ self._bid_from_model(bid_model) for bid_model in auction_model.bids.all() ] return Auction( auction_model.id, auction_model.title, bids ) Interface / Port Adapter

Zostało już tylko zawołać UseCase z Django

Wszystko razem na jednym obrazku

Na co uważać? więcej kodu (type hinty pomagają) "przerzucanie" danych z jednych obiektów do drugich walidacja? uwaga na overengineering

Kiedy się opłaca? Nowy projekt odraczanie decyzji testowalność skomplikowana domena

Co dalej mogę z tym zrobić? CQRS Event Sourcing Domain Driven Design

Pytania?

Więcej informacji h ps://8thlight.com/blog/uncle bob/2012/08/13/the clean architecture.html Clean Architecture: A Cra sman's Guide to So ware Structure and Design Clean Architecture Python (web) apps Przemek Lewandowski So ware architecture chronicles seria blog postów Boundaries Gary Bernhardt Przykładowy projekt w PHP (blog post) Przykładowy projekt w PHP (repo) Przykładowy projekt w.net (repo) Przykładowy projekt w Pythonie (repo) breadcrumbscollector.tech @EnforcerPL