Non-anemic entities

4

@Bambo: gorzej! Pomyśl że będziesz miał jeszcze na koniec DTO do wypchnięcia z jakichś kontrolerów, które też będą pewnie bardzo podobne!
Tylko w zasadzie czemu robi ci to wielki problem? Przecież efektywnie będziesz miał jakiś konstruktor twojego obiektu domenowego który dostaje obiekt jpa i analogicznie np. konstruktor DTO który dostaje domain object, narzut będzie mikroskopijny.

Wiem że potem ludzie narzekają że klepią tzw mappery, tylko że ich brak to jest właśnie wspomniane wyżej encja na twarz i pchasz i spinanie sobie logiki aplikacji ze sposobem przechowywania danych, czy spinanie widoku z jakąś wewnętrzną reprezentacją danych w aplikacji. A chcemy żeby to były niezależne elementy. To że zmieniam coś wewnętrznie w bazie danych, nie powinno zmuszać mnie do zmiany logiki aplikacji czy do zmiany widoku.

0

@Shalom:

No i właśnie tego się obawiałem, że tak będę musiał robić. Tylko nadal nie pasuje mi własnie ten konstruktor obiektu domenowego, który przyjmuje encje jpa - przecież uzależniamy wtedy nasz biznes od głupich struktur jpa czyż nie ? Zmiana struktury encji jpa spowoduje jakąś tam zmianę w naszym obiekcie domenowym.

0

Ale zmienisz tylko mapper czy konstruktor. Wyobraź sobie że chcesz zmienić strukturę danych w bazie i nagle nie masz już klasy Address. Zmiana mappera jest łatwa i w jednym miejscu. A jak używasz tej klasy w połowie systemu to nie ma szans na taką zmianę.

No i to nie musi być konstruktor, to był tylko przykład. Może to być jakieś factory.

3

Zawsze pozostaje pytanie. Z czym jest wiecej roboty. Czy z dopasowaniem logiki do pozmienianej bazy danych? Czy z ciągłym rypaniem się z durnymi DTO i mapperami, które nic nie wnoszą poza próbą udawania, że zrobiliśmy coś innego niż encja na twarz?

0

Ok, pooglądałem kila filmów na ten temat i przeanalizowałem repo Jakuba. I nie mogło być inaczej niż kilka wątpliwości.

Stworzyłem jakiś najprostszy przykładowy projek (nie zrobiłem konfiguracji tego itd, to tylko w celach dydaktycznych):
https://github.com/skax/tasks-example

Czy to ma mniej więcej tak wyglądać ? Wzorowałem się na tym wszystkim co widziałem, ale mam kilka wątpliwości:

  1. Obiekty domenowe typu TaskCreator, TaskUpdater zależą od klasy Task, która jest niedomenowa tylko jest detalem bazy danych - robicie to jakoś lepiej czy tak to zostawić ?

  2. Nie rozdzieliłem commandów od query. Czy teoretycznie powinienem zrobić drugie repozytorium: TaskQueryRepository ? I za pomocą niego zwracać obiekty TaskQueryDto ?

  3. Dlaczego w większości przykładów encje jpa znajdują się w pakiecie domain ? Przecież to jest szczegół i nie należy do domeny ?


  1. https://github.com/jakubnabrdalik/hentai-cloudy-rental/blob/master/films/src/main/java/eu/solidcraft/hentai/films/FilmCatalogueController.java
    Czy tutaj jest wypadek przy pracy ? Idzie encja na twarz :D
1

3 i 4 - jeżeli jesteś świadomy wyboru i takie rozwiązanie póki co jest dla ciebie OK, bo to prosta klasa i za bardzo nie przecieka to moim zdaniem nie ma tragedii i może być. Ale jeżeli zacznie się tam pojawiać kod, który będzie spawać obiekt domenowy i tabelę/cokolwiek (np musisz użyc takiego mapowania, bo inaczej JPA nie łyknie/będzie nie wydajne/cokolwiek takiego) to wtedy wypadałoby rozdzielic.
2. Nie musisz.

IMHO zrób sobie bardziej zaawansowany przykład, niech twoja domena zależy od czegoś wiecej niż tylko bazy danych, np niech konsumuje jakieś dane z resta i dorób sobie drugi moduł, żeby ogarnąć komunikację między modułami

0

Pozwolicie, że wznowię temat z racji tego, że wreszcie miałem czas usiąść do większego projektu. Wzoruję się na WJUGU Jakuba Nabrdalika, który poleciliście, czyli w każdym module jedyną klasą publiczną jest fasada. I teraz tak, mam moduł nazwany weather, który odpowiada za dostarczanie pogody na podstawie nazwy miasta oraz szerokości i długości - skąd te dane są brane jest dla reszty systemu oczywiście nieważne. Póki co pogodę biorę z jednego API, ale być może będę brał z innego + z bazy danych. Zrobiłem zatem taką strukturę modułu weather:

  1. domain

    • WeatherFacade - publiczna
    • WeatherProvider - interfejs
    • WeatherConfiguration - konfiguracja wstrzykiwania beanów, żeby nie robić @Component oraz @Service jak radził pan Jakub
      1.1 dto
      - WeatherDto
  2. infrastructure

    • 2.1 api1
      • Api1Client
      • Api1DataConverter - logika konwersji odpowiedzi z API na WeatherDto
        2.1.1 dto - modele odpowiedzi z API
        • ...

Kilka słów wyjaśnień:
WeatherFacade posiada instancję jednego (lub w przyszłości kilku) WeatherProvidera. Chciałem zrobić tak, że jedną z implementacji WeatherProvidera jest Api1Client - w końcu implementacja tego interfejsu jest szczegółem i dałem ją do paczki infrastructure ii .. zonk! WeatherProvider w końcu ma dostęp pakietowy, więc w klasie Api1Client nie mogę go implementować :D. Jakieś sugestie ?

EDIT :

Dobra, widzę właśnie, że jak Pan Jakub tworzy interfejs, który będzie implementowany gdzieś tam to czyni go publicznym jednak.

1

Generalnie jest kilka podejść, opiszę ci dwa z nich:
Ports and adapters - WeatherProvider faktycznie musi być publiczny jako interfejs i oprócz fasady będziesz miał publiczne interfejsy, ale implementacje są poza domeną, jako szczegół. Wtedy masz dependency inversion - kod domenowy nie jest zależny od kodu z zewnątrz i będzie się cały czas kompilowac, bo w końcu pusty interfejs tylko masz w domenie. Jak coś zmienisz to klasy z infrastruktury przestaną się kompilować, nie twój kod.

Package by component - wtedy implementacje wrzucasz do tego samego pakietu, interfejs może być package scoped. Plus jest taki, że masz wszystko w jednym miejscu, minus taki, że w kodzie domenowym będzie też kod związany z infrastrukturą.

Ja bym wybrał podejście pierwsze.

1
Bambo napisał(a):

Dobra, widzę właśnie, że jak Pan Jakub tworzy interfejs, który będzie implementowany gdzieś tam to czyni go publicznym jednak.

Nie sugeruj się tylko Jakubem. Tutaj jest wszystko to czego potrzebujesz:
https://github.com/heynickc/awesome-ddd
Polecam sekcję Sample projects.

Dodatkowo poczytaj na temat hexagonal archiotecture, czyli portow i adapterow: https://herbertograca.com/2017/09/14/ports-adapters-architecture/

0

czy wg Martina Fowlera **nie **pisanie funkcji biznesowych w klasach z adnotacją @Entity - jest anty-wzorcem? bo chyba zle to rozumiem

A czy Folwer gdziekolwiek tam mówi cokolwiek o JPA, Hibernate czy @Entity? On mówi generalnie o tym że nie lubi podejścia stosowanego czesto w SoA, że masz serwisy które łykają jakieś DTO i wypluwają DTO/struktury danych.

To jak poprawnie te serwisy powinny działać? Co przyjmować i co wypluwać? I czy jeśli w encji są funkcje biznesowe to czy to nie jest naruszenie SRP i właśnie nie powinno być w serwisach?

0

youtube.com/watch?v=SxqK8jo7vdY&feature=youtu.be&t=31m05s
youtu.be/SxqK8jo7vdY?t=46m57s
Czemu jeśli w encji jest "state" (enum) to nie powinno się używać gettera getState() jeśli chodzi tylko o wyświetlenie danych do tabelki?

0
Błękitny Programista napisał(a):

youtube.com/watch?v=SxqK8jo7vdY&feature=youtu.be&t=31m05s
youtu.be/SxqK8jo7vdY?t=46m57s
Czemu jeśli w encji jest "state" (enum) to nie powinno się używać gettera getState() jeśli chodzi tylko o wyświetlenie danych do tabelki?

Nie bardzo rozumiem pytanie, ale jeżeli chcesz encję (persistence model) ładować do widoku to to już jest zły pomysł. Nie oglądałem calej prezentacji, ale zakolejkowałem, z urwanego kontekstu wywnioskowałem, że prezenter ma różne metody biznesowe np isRunning, generalnie fajnie, enkapsulacja. Tylko on też te sama klase (urwany kontekst, nie ogladalem calosci) chce pchac do widoku i po to mu getState (lamie enkapsulacje, bo z tego co rozumien to metoda isRunning to jeden z możliwych stanów, a potem on ten stan i tak udostępnia publicznie, bo klient chce to w tabelce). Dlatego rozwiazaniem jest osobna klasa do widoków (różnych) i klasa biznesowa (czasem tez jest to encja, czyli klasa mapujaca obiekt na tabele/dokument/cokolwiek w bazie - ale tego purysci DDD nie akceptuja), na ktorej faktycznie wykonuje sie akcje, ma zachowania, jest w pelni zenkapsulowana etc etc. Wniosek - chcesz opierdolić wszystko jedną klasą to możesz się starac i glowic, ale i tak predzej czy pozniej sie to zawali

edit:
o tym też mówił koleś na prezentacji - on robi ubogiego CQRSa i też na widok pcha inne obiekty niż encje i problem się sam rozwiązuje

0

Dzięki, teraz rozumiem. Czyli w tym DDD to rzeczywiście trzeba dużo pisać. Tylko w jakim folderze umieszczać te klasy do widoków? Związanym z widokami, czyli gdzieś na poziomie już templatów czy gdzieś w modelu? I pod jaką nazwą?

A co powiesz o tym:

I czy jeśli w encji są funkcje biznesowe to czy to nie jest naruszenie SRP i właśnie nie powinno być w serwisach?

0

Czyli w tym DDD to rzeczywiście trzeba dużo pisać.

Nie powiedzialbym. Na początku może się to wydawać dużo, ale trzeba pamiętać, że wtedy zachowujemy SRP (jeden powód do zmian) i wszystko generalnie jest proste, a jak pakujesz to jednej klasy to ona rośnie, komplikuje się, czasami niektóre rzeczy są ze sobą w konflikcie.

Tylko w jakim folderze umieszczać te klasy do widoków? Związanym z widokami, czyli gdzieś na poziomie już templatów czy gdzieś w modelu? I pod jaką nazwą?

Jak chcesz, jak ci pasuje, nie ma konwencji. To generalnie bedą zwykłe DTOsy, możesz nazwac je też widokami, ostatnio ktoś na forum wrzucił to do pakietu api, bo faktycznie to jest kontrakt modułu. Pakiet dto/view też były OK, nie ma reguł.

A co powiesz o tym:
I czy jeśli w encji są funkcje biznesowe to czy to nie jest naruszenie SRP i właśnie nie powinno być w serwisach?

To jest naruszenie SRP, ale z innego powodu. Generalnie pomijając DDD obiekty mają zachowania (w tym funkcje biznesowe). Więc trzymanie całej logiki w serwisach jest złem, bo nie jest obiektowe i intuicyjne (tytuł tematu). Zatem wg purystów powinieneś mieć osobną klasę, która będzie reprezentować obiekt/model domenowy i osobną klasę encje (do mapowania na bazę danych czy co tam chcesz). Wtedy nie musisz mieć nic w serwisach. Oczywiście pisząc zwykłe aplikacje będą serwisy, bo nie można wszystkiego trzymać w modelu domenowym (zależności do innych serwisów, innych agregatów). IMHO proste rozróżnienie co w serwisie co w obiekcie domenowym: zapłać dla faktury - ustawienie pól, sprawdzenie warunków, przejście w inny stan - to się dzieje w obiekcie domenowym. Wysłanie maila do klienta z potwierdzeniem o płatności - to się dzieje w serwisie. Generalnie to faktura wie kiedy może być opłacona i w jaki sposób, żaden serwis nie musi zaglądać do jej środka i internali. Ale taka faktura to już nie ma zielonego pojęcia o zewnętrznym świecie i jakiś mailach, więc robi to serwis odpowiedzialny za to.

0

Czyli obiekt domenowy i encja mają te same pola/właściwości i różnią się zachowaniem? Właściwie w Encji zachowania nie ma tylko zwykłe gettery i settery, żeby dobrze to działało z frameworkiem?
Wielkie dzięki za pomoc.

0

Generalnie tak robią puryści nie musisz iść od razu tą drogą i możesz mieć zachowanie w encji. No i nie zawsze obiekt domenowy/encja mają te same pola, bo czasem żeby coś zamapowac pod framework to robisz to tak jak framework nakazuje, ale nie zawsze bys tak zrobił w czystej javie. Po drugie często się wrzuca do encji jakieś pola do utrzymania, które nie maja znaczenia biznesowego np. data ostatniej modyfikacji.

Właściwie w Encji zachowania nie ma tylko zwykłe gettery i settery, żeby dobrze to działało z frameworkiem?

Generalnie tak. Zależy jak wielka jest aplikacja, na której chcesz iśc drogą DDD, jeżeli zaczynasz od zera to możesz sobie pozwolić na rozdzielenie od razu, jeżeli istniejąca apka to może być ciężko, więc warto robić krokami. Nawet jak zaczynasz projekt od 0 i masz te same pola w obiekcie domenowym co w encji to IMHO mozna sobie pozwolic na 1 klase, ale z zastrzezeniem, ze jezeli sytuacja bedzie wymagac hackow/dopasowania obiektu domenowego do frameworka/pol utrzymaniowych/cokolwiek co nie ma sensu dla obiektu domenowego to wtedy rozdzielasz.

1

To jak poprawnie te serwisy powinny działać? Co przyjmować i co wypluwać? I czy jeśli w encji są funkcje biznesowe to czy to nie jest naruszenie SRP i właśnie nie powinno być w serwisach?

To zależy co te serwisy robią. Jak są wołane przez jakiegoś RESTa albo wysyłają do jakiegoś dane to faktycznie mają DTO na wejsciu/wyjściu, to jest akurat mało istotne.
Idea jest taka, zeby logika "biznesowa" była w obiektach domenowych i żeby była wołana z poziomu serwisu, który stoi gdzieśtam na styku pomiędzy systemami/modułami. Wyobraźmy sobie, że chcesz w aplikacji wczytać plik konfiguracyjny i potem na jego podstawie cośtam robić. Która wersja wydaje sie bardziej logiczna:

  • Wczytujemy konfiguracje do stringa i tego stringa sobie gdzieśtam trzymamy. Robimy sobie ConfigurationService który potrafi z tego stringa wyciągać jakieśtam informacje, więc w kodzie mamy np. configurationService.getNumberOfConnections(configString).
  • Wczytujemy konfiguracje za pomocą obiektu klasy Configuration, która parsuje konfiga i wystawia metody dostępowe do zgromadzonej konfiguracji, wiec w kodzie mamy np. configuration.getNumberOfConnections()

? Szczególnie że opcja 1 zakłada że jakoś ten ConfigurationService trzeba przekazać tam gdzie z niego korzystamy, podczas gdy obiekt Configuration jest self-contained :)

0

Ponownie zgłębianie problemu i kłótnie z kolegami w pracy doprowadziły mnie do tego, że muszę dalej ciągnąć ten temat. Kłótnia dotyczyła tego, czy encje JPA to domena czy nie ?

Bo mówiliście tutaj, że to nie ma nic wspólnego z domeną, że nie powinny mieć metod biznesowych, żadnych getterów, ani setterów - jedynie zwracanie dtosa, po czym daliście np. przykład DDD Sobótki taki:

https://github.com/BottegaIT/ddd-leaven-v2/blob/master/src/main/java/pl/com/bottega/ecommerce/sales/domain/purchase/Purchase.java

gdzie klasa Purchase należy do domeny, jest encją JPA, a dodatkowo posiada metodę biznesową confirm() i zestaw getterów.

A wg @Shaloma i konferencji Pawła Szulca nie powinno tak być.

1

Prawda jest taka - nikt ci nie zabroni do encji JPA ładować zachowań obiektów, przez co będą jednoczesnie obiektem domenowym i encją JPA. Dawno nie pisalem przy użyciu JPA, ale każdy framework, który ci pomaga zarzadzać cyklem życia obiektu i zapisywać gdzieś ma swoje narzuty i prędzej czy później te narzuty wyjdą bokiem. Ja u siebie stosuje takie połączenie dla prostych encji, ale że zdążyło to pokasąć (konkretnie spring data) to wiem, że dla bardziej skomplikowanych lepiej jest oddzielić obiekt domenowy i obiekt, który będzie persystowany - takie podejscie jest ksiązkowe, tru i w ogóle.

Wady i zalety jednej klasy dla obiektu domenowego i 'encji'

  • na poczatku jest łatwo
  • mniej roboty (też na początku)
  • przy skomplikowanych obiektach w pewnym momencie zaczną się problemy - czy idziemy w czystą domenę i po bożemu czy musimy iść na pewne skróty/hacki, bo framework tego wymaga
  • mniej wprawieni programiści mogą modelować obiekty tak jakby modelowali encje JPA, a nie obiekt domenowy
  • ilość adnotacji zaciemnia kod

Wady i zalety podejścia książkowego

  • na początku jest wiecej roboty (z czasem wchodzi to w krew i nie ma to znaczenia)
  • nie ma narzutu frameworka
  • czysta domena

Ja stosuję oba na raz - dla prostych encji mam dwa w jednym, ale jeżeli zaczyna się encja niebezpiecznie rozrastać i/lub framework wymaga hacków to przechodzę na podejście książkowe

4

@Bambo: inżynieria oprogramowania to nie jest exact science, nie ma tu aksjomatów. Wczoraj wszyscy mówili ze X jest dobre a dziś mówią że Y. Pewne rzeczy wychodzą dopiero po czasie. Poza tym wszystko ma swoje plusy i minusy. Rozdzielenie modelu persystencji od modelu domenowego daje ci dużo większą elastyczność i niezależność, ale wymaga zabawy w jakieś mapowanie i czasie przepisywanie X na X wte i wewte. Nie ma tu chyba panaceum, a przynajmniej ja go nie znam.

No i uwaga na temat ślepej wiary w jakieś "autorytety", bo "ktośtam powiedział że XYZ". Zalecam wątpić we wszystko i sprawdzać wszystko samemu. A już koniecznie jeśli chcesz się powoływać na mnie :)

0

@Shalom:

Po prostu jestem pasjonatem tego wszystkiego i czasem potrafię to rozkminiać po nocach, stosować w robocie, kłócić się z seniorami o różne rzeczy itd .. a tutaj na forum obrałem sobie kilka autorytetów i już - czuj się od 3 lat jednym z nich :D

Koresponduję właśnie z Jakubem -> wg niego nie ma nic złego w stosowaniu metod biznesowych w encji jpa .. czyli totalnie sprzeczne z tym co mówiłeś w pierwszym poście tu w temacie.

0

Jeśli oddzielisz encje od domeny, wtedy domena staję się mniej zależna od frameworków i jeśli będziesz chciał to łatwiej potem podmieniać.

3

wg niego nie ma nic złego w stosowaniu metod biznesowych w encji jpa

Bo nie ma w tym nic "złego". Nikt nie zabija szczeniaków kiedy tak robisz :P Ba, jak piszesz Generic CRUDa to pewnie takie rozwiązanie będzie dobrym pomysłem, bo to mniej roboty. Ale rozwiazania i narzędzia dobiera się do problemów. Przy większej komplikacji domeny czy po prostu przy większym systemie takie rozwiązanie będzie boleć. Odcięcie domeny od zewnętrznych elementów (frameworków, interfejsów niezależnych od nas itd) zwykle wychodzi na dobre, bo z jednej strony masz elastyczność w zmienianiu kodu domenowego, a z drugiej strony jakaś zewnętrzna zmiana wpływa jedynie na warstwę mapowania/fasad/adapterów a nie na logikę biznesową.

0

@Shalom:

Jak najbardziej zgadzam się z tym, że moduły powinny się komunikować po dto. A jak rozwiązujesz sytuację, kiedy jakaś encja z modułu A ma mapowanie @ManyToOne do encji do modułu B ?

Encje nie są publiczne - nie widzą się przecież :)

1

generalnie JPA(a wcześniej hibernate) nie było projektowane jako narzędzie wspomagające pracę w architekturze DDD, samo DDD zaczęło się popularyzować po sukcesie jpa/hibernate i szczerze wątpię by kiedykolwiek mieli robić jakiekolwiek ukłony w stronę DDD, bo JPA to ORM, a zasada jest taka, że masz się uwolnić od frameworków/infrastruktury, czyli pod spodem możesz sobie zrobić encje oparte na JPA, ale domena ma nic o tym nie wiedziec, więc jak ktoś chce to klocki łączyć razem to niech się nie dziwi, że nie zawsze bedą pasować ;)

0

@hcubyc:
A jak u siebie robisz ?

0

Pisałem w poprzednim poście - nie korzystam z JPA, ale myslę że w tym przypadku byłoby tak samo - proste encje/obiekty mam łączone, czyli obiekt domenowy z zachowaniem i adnotacjami JPA. Jeżeli gdzieś muszę iść na ustępstwo w kierunku JPA, bo mnie ogranicza i/lub muszę coś zrobić na potrzeby frameworka, psując przez to domenę to wtedy rozdzielam. Mam o tyle prościej, że nie korzystam z systemu relacyjnego, ale nie oszukujmy się, to że w JPA masz referencję do innej encji to nic innego jak ID pod spodem, tabela łącząca czy inne podejście oparte na IDkach. Jest też tak, jak pisał Shalom - nie każdy projekt/problem będziesz robił domenowo, bo jest to jakiś narzut, ale jeżeli masz skomplikowaną domenę i wiesz, że produkt będzie miał długi cykl życia to nie opłaca się iść na skróty, bo potem to gryzie po dupie, wystarczy popatrzeć na niektóre projekty, gdzie jest misz masz zapytania SQL porozrzucane wszędzie, przeplatane z kodem springa i największe combo jak ktoś jeszcze np. logike wyrzuca na UIa i nie ma żadnych testów, potem się robi zebrania jak to uratować, IMHO dużego projektu się nie da pisanego w taki sposób

0

A co do: architekci w mojej firme przeczytali książke, pojechali na konrefencję.... to można by ładny poemat napisać. Jak ktoś całą głowę ma prostokątną, bo 5 lat tłukł CRUDy do tabelek, to łatwo z tego nie wyjdzie.

Co...?
A po co tłuc jak można sobie do tego generyczną biblioteke zrobić i wszystko generowac dynamicznie?

To jakiej niby architektury potrzebuje CRUD ?

0

@Shalom:
mając rozdzieloną domenę od encji, skąd wiedzieć jak zapisać obiekt, np. które atrybuty? robić dirty-checking manualnie?
Tak swoją drogą to mam wrażenie że żyjemy w czasach programistycznego kamienia łupanego, a część wzorców rozwiązuje problemy z frameworkami, a nie ogólne problemy koncepcyjne. Relacyjne bazy danych to też nieporozumienie z funkcjonalnego punktu widzenia- nie można wyciągnąć w zasadzie samych relacji, chcemy wyciągnąć hierarchiczną strukturę danych (robiąć JOINa) a dostajemy na twarz płaską tabelę, to jest jakiś joke

0

@Shalom:
mając rozdzieloną domenę od encji, skąd wiedzieć jak zapisać obiekt, np. które atrybuty? robić dirty-checking manualnie?
Tak swoją drogą to mam wrażenie że żyjemy w czasach programistycznego kamienia łupanego, a część wzorców rozwiązuje problemy z frameworkami, a nie ogólne problemy koncepcyjne. Relacyjne bazy danych to też nieporozumienie z funkcjonalnego punktu widzenia- nie można wyciągnąć w zasadzie samych relacji, chcemy wyciągnąć hierarchiczną strukturę danych (robiąć JOINa) a dostajemy na twarz płaską tabelę, to jest jakiś joke

Drity cheacking...? a co validacja inputa ma do domeny? Może być jedynie zakresem jej rozwiązania ale z samy modelem domeny nie ma nic wspólnego.

Jak to w zasadzie nie można wyciągnąc samych relacji. Ty chyba sam, żyjesz w epoce kamienia łupanego i nawet nie rozumiesz co to jest relacja w relacyjnej bazie danych i jak ona działa...

1 użytkowników online, w tym zalogowanych: 0, gości: 1