Ponowne opracowanie projektu systemu dla Scali


35

Wiele, wiele księżyców temu, zrobiłem moich mistrzów w inżynierii oprogramowania obiektowego. Omówiłem wszystko: inicjację projektu, wymagania, analizy, projektowanie, architekturę, rozwój itp. Itp. Moją ulubioną książką informatyczną wszechczasów było tworzenie oprogramowania obiektowego, podejście oparte na doświadczeniu (IBM-1996). Książka stworzona przez grupę prawdziwych ekspertów swoich czasów. Opisuje podejście zorientowane na produkt pracy do obiektowych metod analizy, projektowania i rozwoju.

Zaprojektowałem, opracowałem i byłem szczęśliwy na samym początku mojej gry, ale zacząłem czuć się trochę przestarzały: zwinne ruchy stały się modą tego dnia i przemodelowałem kilka dobrze znanych iteracyjnych i przyrostowych podejść nowymi modnymi słowami. Nagle niedoświadczeni programiści zmarszczyli brwi, kiedy powiedziałem „wymagania” lub „architektura”, jakby te rzeczy zostały zastąpione magią.

Projektowanie i rozwój straciły przyjemność i miałem zamiar zostawić za sobą całą branżę IT.

Potem odkryłem Scalę. Och, jak miękki deszcz na zakurzonej drodze. Wszystko właśnie stało się czyste, powietrze znów stało się słodkie, a światło mojego dysku twardego migotało głęboko w noc, wesoło utrzymując mnie w towarzystwie mojego odkrywczego świata.

Lubię projektowanie systemu. Jestem sercem architektem, więcej niż programistą. Uwielbiam analizować, projektować, myśleć, kłócić się, ulepszać - po prostu uwielbiam proste, czyste i wyraziste projekty.

Jak projektujemy czyste rozwiązania Scala?

Z pewnością konwencjonalne diagramy sekwencji, diagramy interakcji, diagramy obiektów itp. Mogłyby zostać zastąpione lub ulepszone dla dobra mieszania imperatywnych i funkcjonalnych systemów obiektowych. Z pewnością jest szansa na coś zupełnie innego!

Nie szukam rozdętej złożoności - szukam elastycznej prostoty. Podobnie jak Scala jest w rzeczywistości prosty i łatwy (choć inny), ale można go rozszerzyć, aby pasował do twoich wymagań, jak para spodni do jogi. Musi istnieć system projektowania tego pięknego języka, który zacznie się w prosty sposób i można go rozszerzyć, aby pasował do twoich wymagań i domeny. Na pewno UML nie może być!

Jak więc projektujemy czyste systemy Scala? Wyobraź sobie przez chwilę, że masz luksus zaprojektować kompletny system od podstaw i wiesz, że będziesz używać tylko Scali - jak będą wyglądać twoje modele? Jakie rodzaje diagramów musiałbyś opisać strukturę i zachowanie? Jak modelowałbyś opcje, dopasowania, mixiny, obiekty singletonowe itp. Bez wciągania się w rozbudowę istniejących technik modelowania zamiast świeżego, lekkiego, innowacyjnego zestawu narzędzi.

Czy taki projekt / proces / rozwiązanie istnieje , czy nadszedł czas, aby go wymyślić?


+1 za „można rozszerzyć, aby pasowało do twoich wymagań jak para spodni do jogi”.
Russell

FWIW, widziałem pytanie dotyczące UML i Scali, które może Cię zainteresować. Ponadto, jeśli przejdziesz do strony funkcji, warto przyjrzeć się notacjom teorii kategorii. Gregory Meredith zwykle prowadzi do interesujących prezentacji na ten temat, choć nie jestem pewien, co ma na swoim blogu - i tak warto to sprawdzić.
Daniel C. Sobral

Jest dużo wart ;-) Daje mi wskazówki do kopania. Dzięki Daniel
Jack

Warto sprawdzić, „zmodyfikowany” UML dla Scali, github.com/mnn/Dia2Scala/blob/master/other/Notation.md
WeiChing Lin

Odpowiedzi:


12

Naprawdę nie potrafię odpowiedzieć na to pytanie, ale pozwólcie, że przedstawię kilka przemyśleń.

Jestem studentem inżynierii komputerowej na uniwersytecie, aw zeszłym semestrze ja i grupa wykonaliśmy duży projekt oprogramowania, w którym naszym podstawowym językiem był Scala. Nasz projekt wykonaliśmy w tradycyjny sposób: przypadki użycia, model domeny, diagramy sekwencji, diagramy klas UML; zwykłe obciążenie. I, jak już wiesz, są źle dopasowane. Oto kilka powodów.

Najpierw rozważ schematy sekwencji. Czuć diagramu sekwencji jest kilka stajni, długowieczne, pół-autonomiczne podmioty rozmawiają ze sobą. W Scali obiekty są zwykle tworzone przez krótki czas. Ponadto klasy przypadków zachęcają do „głupich” obiektów, zawierających tylko dane i bez kodu, więc koncepcja przekazywania wiadomości jest nie na miejscu. Ale najtrudniejszym wyzwaniem dla diagramów sekwencji jest to, że nie mają dobrego sposobu na włączenie funkcji pierwszej klasy; w projekcie OO używającym tylko wywołania zwrotnego tutaj lub tam można go uruchomić, ale jeśli jest to twój główny sposób przekazywania kontroli, schemat sekwencji odzwierciedla niewiele z faktycznego kodu.

Diagramy klas UML są bardziej podatne na Scalę; tak, miksy nie działają dobrze, ale jest to coś, co można „ulepszyć”, a nie przerobić. Ale myślę, że może to nie mieć sensu.

Zastanów się jeszcze raz, dlaczego Scala ma „głupie przedmioty”. Jeśli napiszesz klasę sprawy bez metod:

case class NewInvite(user: User, league: League)

nie potrzebujesz żadnych metod, ponieważ typy członków obiecują coś o tym, co możesz z nimi zrobić. W rzeczywistości obiecują wszystko . I, w każdym zakresie w programie, zmienne w zakresie i ich typy obiecują coś o tym, gdzie kod może iść w tym momencie.

Więc może, jeśli cofniemy się nieco i zamiast drobiazgowo zastanawiać się nad typami per se, zaprojektuj nasz program pod kątem kontekstów, w których będzie żył nasz kod i co obiecane jest programistom (i ostatecznie użytkownikowi ) w każdym z tych kontekstów znajdziemy opis bardziej odpowiedni dla Scali. Jednak tutaj tylko zgaduję i myślę, że masz rację, że w tej dziedzinie należy zbadać znacznie więcej.


„Co obiecano programistom” - to ma cudowny dźwięk ;-)
Jack

12

UML wyłonił się z „wojen wojennych” z przełomu lat 80. i 90. To zawsze był kompromis dla zapisu , a nie metoda projektowania. Wiele oszczerstw przypisywanych UML jest potajemnie wynikiem metody projektowania, która mówi „Krok 1: narysuj model klasy”.

Sugeruję, że nie potrzebujemy nowych metod projektowania tak bardzo, jak powinniśmy ożywić niektóre stare. Zacznij od zdefiniowania i przydzielenia obowiązków, a następnie przejdź do zrozumienia ich realizacji, a następnie postępuj zgodnie z dobrymi notacjami i reprezentacjami, aby przekazać te pomysły.

Obowiązki

CRC działa równie dobrze dla Scali, jak dla każdego innego języka OO, co oznacza, że ​​działa bardzo dobrze! Modelowanie podziału obowiązków przez antropomorfizację aktorów i zrozumienie ich współpracy nadal działa dobrze.

Na dużą skalę powinieneś nadal projektować za pomocą obiektów. Granice obiektów są granicami enkapsulacji. Zachowaj zmienny stan i szczegóły implementacji wewnątrz tych granic obiektów. Klasy przypadków tworzą dobre obiekty interfejsu, podobnie jak kolekcje wanilii i struktury danych.

Zrozumienie implementacji

Przekaż te struktury danych ponad granice obiektów, a nie inne obiekty, a zobaczysz: a) łatwiej jest ukryć wnętrzności obiektu, oraz b) funkcjonalne implementacje zachowań obiektów mają sens.

Nie będziesz chciał traktować struktury programu na dużą skalę jako „ogromnej puli małych funkcji”. Zamiast tego będziesz naturalnie dążyć do wąskich interfejsów między izolowanymi częściami systemu. Te i tak wyglądają i przypominają przedmioty, więc śmiało i zaimplementuj je jako obiekty!

Reprezentacja i notacja

Tak więc w ramach tej struktury projektowania nadal musisz wyciągać myśli z głowy i dzielić się nimi z kimś innym.

Sugeruję, że UML nadal może być przydatny do opisywania wielkoskalowej struktury twojego systemu. Nie pomoże to jednak na niższych poziomach szczegółowości.

W najdrobniejszych szczegółach spróbuj wypróbować techniki programowania.

Lubię też używać minidoców. Minidoc to jedno- lub dwustronicowy dokument opisujący określony aspekt zachowania systemu. Powinien znajdować się w pobliżu kodu, aby był aktualizowany, i powinien być na tyle krótki, aby umożliwić naukę w odpowiednim momencie. Osiągnięcie odpowiedniego poziomu abstrakcji wymaga pewnej praktyki: musi być wystarczająco szczegółowe, aby było przydatne, ale nie tak szczegółowe, aby zostało unieważnione przy następnej zmianie kodu.


9

Jak projektujemy czyste rozwiązania Scala?

Myślę, że pod tym kątem podchodzisz niewłaściwie. Ogólny projekt rozwiązań nie powinien być powiązany z konkretnym językiem; powinien raczej odpowiadać danemu problemowi. Wspaniałą rzeczą w Scali jest to, że jest wystarczająco elastyczna, aby nie przeszkadzać, gdy przyjdzie czas na wdrożenie projektu. Z drugiej strony Java wymusza pewne decyzje projektowe (przede wszystkim mentalność „wszystko to klasa”), która sprawi, że poczuje się trochę niezręcznie.

Podczas projektowania staraj się jawnie modelować stan . Niezmienne dane i jawny stan prowadzą do projektów, które są znacznie łatwiejsze do uzasadnienia. Przez większość czasu będzie to ładnie przekładać się na funkcjonalne rozwiązanie programistyczne, chociaż czasami może się okazać, że użycie mutacji i trybu imperatywnego jest bardziej wydajne lub łatwiejsze; Scala mieści oba ładnie.

Innym powodem, dla którego Scala jest tak dobry, jest możliwość tworzenia DSL, które odpowiadają Twoim potrzebom . Możesz stworzyć swój własny mały język, który rozwiązuje pewien problem w „normalny” sposób, a następnie po prostu zaimplementować go w Scali.

Podsumowując, moim głównym celem jest to, że nie powinieneś próbować „projektować czystych rozwiązań Scala”. Powinieneś projektować rozwiązania w jak najbardziej naturalny i zrozumiały sposób, a tak się składa, że ​​Scala jest niezwykle elastycznym narzędziem, które może pomóc Ci we wdrożeniu tych rozwiązań na różne sposoby. Kiedy wszystko, co wiesz, to młotek, każdy problem zaczyna wyglądać jak gwóźdź, więc zapoznaj się z różnymi dostępnymi metodami. Nie próbuj zamykać procesu projektowania do kroków X, Y i Z, aby nie przegapić możliwości od A do W.


4

Masz rację, że OOD jest ograniczony i nieaktualny. Jego główną zaletą jest to, że jest tak dobrze sprecyzowany i zrytualizowany, z fantazyjnymi nazwami dla każdego banalnego wzoru i sztuczki projektowej. Nie znajdziesz porównywalnego systemu dla bardziej nowoczesnych i racjonalnych podejść do projektowania systemów.

Mogę wymienić tylko kilka rzeczy: semantyczne podejście do projektowania, którego podzbiór nazywa się programowaniem zorientowanym na język (i jest powszechnie używany przez społeczność Scala) oraz projektowaniem opartym na domenie. To drugie jest uproszczonym i OOPised poglądem na bardziej ogólne podejście do projektowania semantycznego, będziesz mógł cieszyć się nim tylko, jeśli lubisz OOD.

Poleciłbym także nauczyć się sztuczki od dwóch innych społeczności programowania funkcjonalnego - np. Haskell i Scheme, nie wszystkie ich umiejętności projektowe zostały już przekazane Scali.


3

Pytanie brzmiało: w jaki sposób projektujemy czyste rozwiązania Scala?

Odpowiedzi typu:

  1. Używamy XYZ, ponieważ ....
  2. Używamy ABC, ale tak ...
  3. Zaczęliśmy używać XYZ, ale potem stwierdziliśmy, że ABC jest lepsza, ponieważ ...

wskazywałoby na pewną dojrzałość lub ogólnie zaakceptowane istnienie takiego zestawu narzędzi lub rozwiązania.

Komentarze dotyczące tego, czy należy rozważyć zestaw narzędzi do projektowania specyficznych dla Scali, to inna sprawa. Uważam, że Scala jest rewolucyjna, ponieważ łączy programowanie imperatywne i funkcjonalne. Scala uchwyca niesamowity powiew praktyk, koncepcji i zasad rozwoju, dlatego też, znajdując rozwiązanie, które idealnie pasuje do Scali, prawdopodobnie odkryjemy rozwiązanie, dla którego podzbiór będzie również bardzo dobrze obsługiwał wiele innych języków.

Czy można zatem powiedzieć, że znamy odpowiedź na pytanie rezerwowe:

„... czy nadszedł czas na wynalezienie jednego?”

Czy to możliwe, że tak ? (Jeżeli „ tak ” nie określa środków rozwiązania. Można to osiągnąć poprzez rozszerzenie istniejącego rozwiązania lub stworzenie jednego od podstaw. Przyznaje jednak, że istnieją znaczne niedociągnięcia w istniejących opcjach projektowych)

Jeśli nie zgadzasz się, możesz głosować za odrzuceniem mojej odpowiedzi. Wezmę to jak mężczyzna.


Rewolucyjny? Czemu? Lisp od dziesięcioleci stanowił idealne połączenie imperatywnego i funkcjonalnego podejścia. Scala jest interesująca ze względu na swój system typów.
SK-logic

3
Przepraszamy, jeśli „rewolucyjny” jest silnym, silnym słowem. Nie sugeruję, że Scala wynalazł koło na nowo - ale to na pewno, jak cholera, usunęła gumę. W rzeczywistości Scala jest uroczym połączeniem wszystkich zalet wielu języków programowania. Jestem pewien, że również mocno pożycza od Lispa. Dla mnie i nie rości sobie pretensji do innych, język Scala jest rewolucyjny, ponieważ myślę o kodzie w sposób, który przychodzi dość cholernie naturalnie. Język projektowania / modelowania, który robi to samo, z pewnością byłby komplementarny. To był mój jedyny punkt - bez urazy wobec Lispa i wszystkich innych wspaniałych języków.
Jack

2

Nie rozróżniałbym języków, zrobiłbym to samo w java. Jestem jednak ze szkoły OO, a nie z funkcjonalnej (algebraiczna Haskell lub seplen). Projekt aplikacji Haskell naprawdę różni się od Scali lub Clojure. Również projekt aplikacji Scala.js jest inny ze względu na stanowy DOM - trudno jest walczyć z częściową aplikacją, która jest obowiązkowa. Z czasem przyzwyczaiłem się do robienia tego w sposób OO, starając się w jak największym stopniu wyeliminować stan i zmienność. Gdybym był fanem czcionek lub skala, moje aplikacje prawdopodobnie wyglądałyby zupełnie inaczej.

  1. Decydując się na stos technologii i najważniejsze decyzje projektowe, takie jak odpowiedzialność klient / serwer, rozproszony charakter - czy naprawdę potrzebujemy trwałości danych? Co najbardziej odpowiada naszej aplikacji? (na pewno jeszcze nie biblioteki ani frameworki)

  2. Zaczynając od jednego App.scalapliku, w którym definiuję kluczowe typy (cechy i klasy przypadków) oraz role - wiele kontemplacji i myślenia podczas bycia AFK. Jest tak łatwo z nim grać, gdy jest w jednym pliku. Nawet prototyp może powstać, jeśli jest to raczej prosta aplikacja. Poświęcam dużo czasu na tę fazę, ponieważ nic nie jest ważniejsze niż posiadanie najbardziej poprawnego, a przede wszystkim przejrzystego i rozsądnego prototypu. Wszystko to sprawia, że ​​nasze dalsze rozważania są dokładniejsze i zwiększa prawdopodobieństwo sukcesu.

  3. Teraz, gdy udowodniliśmy poprawność naszego rozwiązania, mamy jasną wizję i ujawniono wszystkie potencjalne problemy, nadszedł czas, aby zastanowić się, jakie biblioteki stron trzecich lub metodologie wprowadzić. Czy potrzebujemy frameworku, czy tylko kilku bibliotek? Czy zrobimy z tych stanowych aktorów, czy naprawdę potrzebujemy odporności Akki, .., ... a może nie? Czy używamy Rx dla tych strumieni? Czego używamy do interfejsu użytkownika, abyśmy nie oszaleli po 10 interaktywnych funkcjach?

  4. podziel App.scalaplik na wiele, ponieważ nowe cechy i klasy pojawiły się i stały się większe. Interfejs powinien opowiadać o ich rolach. Teraz nadszedł czas, aby pomyśleć o wykorzystaniu klas typów i polimorfizmu ad hoc tam, gdzie to możliwe. Aby ktokolwiek dzwonił do twojego interfejsu, musi być dla niego elastyczny. Chodzi o to, aby wdrożyć tylko ogólną funkcjonalność, pozostawiając szczegóły dzwoniącemu. Czasami to, co próbujesz zaimplementować, może być podobne do Turinga, więc powinieneś umożliwić dzwoniącym samodzielne wdrożenie specyficznych szczegółów zamiast gromadzenia żądań funkcji w GitHub. Trudno to później dodać. Trzeba to przemyśleć na samym początku. Jak również zaprojektowanie DSL.

  5. przemyślenie projektu, ponieważ aplikacja będzie się rozwijać i musi być gotowa na nowe funkcje, optymalizacje, trwałość, interfejs użytkownika, zdalne sterowanie itp. - rzeczy, które nie zostały jeszcze zaimplementowane lub zostały w jakiś sposób wyszydzone lub wyabstrahowane. Pamiętaj, że chociaż wszystko jest w jednym pliku, dość łatwo jest zmieniać rzeczy. Ludzki mózg zaczyna go tracić, gdy rozprzestrzeni się na ponad 10 plików. I to jest jak guz, który rośnie, tak zaczyna się nadinżynieria. Zauważyłem, że moje aplikacje kończą się kilkoma długimi funkcjami częściowymi, które stanowią swego rodzaju kręgosłup. Łatwo się z nią pracuje. Chyba zaraziłem się aktorami Akka.

  6. Teraz, gdy istnieją już pierwsze rzeczywiste funkcje, a nie tylko podstawowe funkcje, czas zacząć pisać testy. Dlaczego tak późno? Ponieważ w tym czasie prawdopodobnie dokonałeś poważnych przeróbek i marnowałbyś czas na utrzymywanie tych testów. Nie należy pisać testów, chyba że naprawdę jest się pewnym, że nie będzie większych zmian. Wolę testy integracyjne, które z łatwością wytrzymują ciągłe refaktoryzowanie i nie spędzę więcej czasu na testowaniu rzeczy, które faktycznie się rozwijają. Kilka razy zdarzyło mi się, że spędziłem zbyt dużo czasu na utrzymywaniu testów. Naprawianie potencjalnych błędów z pewnością opłacałoby się bardziej niż złe testy. Złe testy lub testy napisane od pierwszej chwili mogą powodować duży ból. Zauważ, że z pewnością nie jestem fanem TDD - IMHO to bzdury.

  7. Refaktoryzacja, tworzenie i utrzymywanie czytelności projektu aplikacji, jasne role komponentów. Gdy aplikacja rośnie, nie ma możliwości, aby pozostała w ten sposób, chyba że jesteś genialnym programistą i jeśli przeczytasz tę odpowiedź, prawdopodobnie nie jesteś :-) Ja też nie. Zazwyczaj istnieją pewne stanowcze rzeczy, ponieważ nie wiesz, jak uniknąć że - może to powodować problemy, spróbuj je wyeliminować. Pamiętaj też o wyeliminowaniu zapachów kodu, które przeszkadzały ci przez pewien czas. W tym momencie kierownik projektu (jeśli go masz) prawdopodobnie zaczyna kręcić głową. Powiedz mu, że się opłaci.

  8. Gotowe, czy aplikacja jest dobrze zaprojektowana? To zależy: czy komponenty mają dobrze zdefiniowane role, które mają sens nawet poza twoją głową? Czy możesz wziąć niektóre z nich i otworzyć je bez większego wysiłku? Czy istnieje wyraźny podział troski między nimi? Czy możesz dodać nową funkcję, nie martwiąc się, że ulegnie awarii w innym miejscu (znak, że wiesz dokładnie, co robisz)? Ogólnie rzecz biorąc, powinna być czytelna jako książka z prostymi pragmatycznymi rozwiązaniami problemów. Który jest IMHO głównym znakiem dobrego designu.

Podsumowując, to tylko ciężka praca i czas, którego prawdopodobnie nie dostaniesz od swoich menedżerów. Wszystko, co tu opisałem, zajmuje dużo czasu, wysiłku, kawy, herbaty, a zwłaszcza myślenia AFK. Im więcej dajesz, tym lepszy projekt. Nie ma ogólnej recepty na projektowanie aplikacji, zdrowy rozsądek, pragmatyzm, KISS, ciężka praca, doświadczenie oznacza dobry projekt.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.