W tym artykule postaram się pokazać jak unikać błędu, który popełniają programiści podczas pisania kodu aplikacji, nawet tego najmniejszego i najprostszego kodu. Błędem tym jest brak zastanowienia się, co tak na prawdę chcemy kodować. Samemu nieraz popełniłem ten błąd. Możesz mi wierzyć, albo i nie, ale nawet nad jednym, prostym fragmentem kodu można zmarnować wiele godzin, jeżeli wcześniej nie zastanowimy się, co on ma robić.
Wszystko zaczyna się od zadania, pomysłu, który mamy do wykonania zimplementowania. Pokażę sposób, który stosuję na co dzień podczas tworzenia oprogramowania. Praktyczne zastosowanie poniższego sposobu można znaleźć w moim artykule Od czego zacząć tworzenie aplikacji? – Przestań pisać kod źródłowy – praktyczny przykład.
Sposób, który stosuję składa się z trzech prostych kroków:
- Analiza – pozwala głębiej zastanowić się nad tym, co zamierzamy kodować oraz spisać naszą wizję tworzonego oprogramowania, aplikacji.
- Projekt – systematyzuje i dokumentuje informacje uzyskane podczas procesu analizy, które później można wykorzystać do implementacji.
- Implementacja – poprzedzona analizą i projektem nie jest już chaotycznym zbiorem kodu oprogramowania, który trzeba często modyfikować.
Nie należy zrażać się widząc takie pojęcia jak analiza i projekt, bo pod tymi pojęciami w moim przypadku kryją się proste metody i rozwiązania.
Ad. 1. Analiza – Dlaczego analiza jest taka ważna? Dzięki niej możemy spojrzeć na tworzone oprogramowanie z szerszej perspektywy, co pozwoli nam dokładniej zrozumieć tworzony kod. Analiza pozwala nam dowiedzieć się, co tak naprawdę ma realizować tworzone oprogramowanie. Przeprowadzam analizę tak, aby nie utonąć w morzu “dokumentacji”. Która, to z założenia jest nieaktualna w momencie jej tworzenia, bo jedyną stałą w programowaniu jest zmiana kodu.
Dla analizy również mam kilka kroków do wykonania:
- Opis w formie tekstu, spisanego np. w notatniku.
- Wybranie rzeczowników i czasowników z opisu.
- Karty CRC – Class Responsibility Collaborators.
Ad. 2. Projekt – Nawet najprostszy projekt pozwala uniknąć dużej ilości refaktoryzacji kodu. Oczywiście współczesne IDE (Integrated Development Environment) wspiera i automatyzuje proces refaktoryzacji, ale po, co dodawać sobie więcej pracy? Dodatkowo projekt pokaże zależności między elementami tworzonego oprogramowania, co pozwoli z wyprzedzeniem np. podzielić aplikację na warstwy i/lub moduły.
Dla projektu również mam kilka kroków do wykonania:
- Diagram klas w UML.
- Makiety GUI.
- Lista end-point’ów REST i/lub API.
Ad. 3. Implementacja – W trakcie implementacji używam TDD (Test Driven Development) prawie dla całego kodu. Dlaczego TDD? Na początku, jak zaczynamy implementować metody z naszego diagramu klas UML, to nie wiemy jak dokładnie będzie działać dana metoda. Wtedy należy zadeklarować metodę, a implementację dodawać podczas tworzenia i rozwijania testów jednostkowych.
To tyle teorii, teraz czas na praktyczne wykorzystanie przedstawionej wiedzy. Mógłbym napisać dużo więcej teorii, ale chcę pokazać, że proces jest na prawdę bardzo prosty, a jego praktyczne zastosowanie daje bardzo dobre rezultaty.
Praktyczne wykorzystanie trzech kroków:
Analiza, Projekt i Implementacja.
Zacznijmy od początku, dostajemy “proste” zadanie, zaimplementowanie systemu do przechowywania notatek. Należy pamiętać, jeżeli zadanie byłoby “proste”, to można by było rozwiązać je za pomocą kreatora. Każde nawet proste zadnie możemy sobie skomplikować nie rozkładając go na czynniki.
Analiza – Opis w formie tekstu:
System umożliwia przechowywanie notatek, które użytkownik tworzy, notatka zawiera informacje o autorze oraz dacie utworzenia i ostatniej modyfikacji. Każda notatka posiada tytuł oraz treść, którą można modyfikować. Jeżeli użytkownik ma więcej notatek, to można wyświetlić je w postaci listy notatek. Notatki można usunąć oraz wyświetlić ich zawartość. Autor może podać swoje imię i nazwisko jak również pseudonim artystyczny.
Analiza – Wybranie rzeczowników i czasowników z opisu:
Dlaczego z tekstu wybieramy tylko rzeczowniki i czasowniki? Ponieważ, to pozwoli nam zidentyfikować i określić przyszłe klasy języka Java (rzeczowniki) oraz metody w klasach Java (czasowniki). Docelowo wszystkie nazwy klas i metod będą w kodzie zapisane po angielsku dla ułatwienia na czas analizy pozostawiam polskie wyrazy.
| Rzeczowniki (przyszłe klasy Java) |
|---|
| System, Notatka, Data utworzenia notatki, Data modyfikacji notatki, Tytuł notatki, Treść notatki, Autor, Imię autora, Nazwisko autora, Pseudonim autora |
| Czasowniki (przyszłe metody w klasach Java) |
|---|
| Przechowywanie, Tworzenie, Modyfikacja, Wyświetlenie listy, Wyświetlenie zawartości |
Powyższa lista może wydawać się banalnie prosta, ale chodzi o przedstawienie idei, za pomocą, której możemy przeanalizować dowolnie duży, złożony system informatyczny.
Analiza – Karty CRC – Class Responsibility Collaborators:
Zanim przystąpimy do tworzenia kart CRC muszę powiedzieć o dwóch ważnych relacjach pomiędzy klasami. W telegraficznym skrócie:
– Pierwsza relacja, to IS-A (jest) – dziedziczenie (inheritance) oznacza, to że Car IS-A Vehicle – Samochód jest Pojazdem.
– Druga relacja, to HAS-A (ma) – kompozycja (composition) oznacza, to że Car HAS-A Engine – Samochód ma Silnik.
Więcej informacji Inheritance (IS-A) vs. Composition (HAS-A) Relationship
Dlaczego piszę o tych relacjach właśnie teraz? Ponieważ pewne rzeczowniki nie będą oddzielnymi klasami, ale ich składowymi, a niektóre kasy będą bardziej ogólnym przypadkiem innych, np.:
– Autor IS-A (jest) Użytkownik(iem),
– Notatka HAS-A (ma) Autor(a), Treść, itp.
Karty CRC (Class, Responsibility, Collaborators) służą do przedstawienia dla klasy (Class) jej odpowiedzialności/zależności (Responsibilities) oraz powiązań z innymi klasami w ramach tworzonego systemu.
| Class: | Notatka |
| Responsibility | Collaborators |
| Przechowuje (HAS-A) dane notatki: – Tytuł, Treść, Autor | Autor (klasa) |
| Class: | Autor (Użytkownik) |
| Responsibility | Collaborators |
| Przechowuje (HAS-A) dane autora: – Imię, Nazwisko, Pseudonim | Notatka (klasa) |
Projekt – Diagram klas w UML
Na podstawie analizy, a konkretnie kart CRC stworzymy diagram klas w języku UML. Oczywiście w tym przypadku będzie, to bardzo prosty diagram, ale tak samo jak na etapie analizy chodzi o przedstawienie idei, za pomocą, której możemy stworzyć diagram klas (projekt) tworzonego systemu.
Do tworzenia diagramów w języku UML używam darmowego narzędzia – https://www.diagrams.net, dostępnego online, bez konieczności instalacji – jest również dostępna aplikacja typu desktop.
Elementy z diagramu UML w telegraficznym skrócie:
1. Note – nazwa klasy,
2. + title: String – znak + (plus), zmienna publiczna; title – nazwa zmiennej; String – typ zmiennej,
3. Połączenie, relacja między klasami <>— agregacja.
Projekt – Makiety GUI
Jeżeli tworzymy interfejs użytkownika dla naszej aplikacji, to należy stworzyć makiety GUI nawet, jeżeli są, to bardzo proste makiety GUI. Interfejs użytkownika może być dla aplikacji web’owej i/lub aplikacji desktop. Przez makiety GUI rozumiem, zobrazowanie w formie graficznej elementów interfejsu użytkownika takich jak np.: przyciski, etykiety, pola do wprowadzania danych itp.. Dlaczego warto tworzyć nawet najprostsze makiety GUI takie, jak poniższe? Takie makiety pozwolą zrozumieć, przybliżyć biznesowy aspekt tworzonego systemu oraz będą dobrą bazą do tworzenia kolejnych makiet.


Projekt – Lista end-point’ów REST i/lub API
Dlaczego przed przystąpieniem do implementacji/programowania systemu należy ustalić end-point’y i/lub API? Wypisanie takich elementów pozwoli nam zobaczyć szerszy kontekst, obraz tworzonego systemu. Co, to jest w ogóle end-point? End-point jest, to punkt styku, komunikacji między różnymi elementami oprogramowania i/lub systemów.
Uwaga! Poniższy opis jest niewystarczający, dodatkowy opis wybiega poza ten artykuł. Należy uzupełnić wiedzę o takie elementy jak: 1. Należy odróżnić end-point od API, 2. Co to jest REST? 3. Co to jest API? 3. Protokół HTTP. 4. Usługi sieciowe – WebService. 5. Aplikacja Web.
End-point powinien być udokumentowany i dobrze znany osobom, które z niego korzystają. Jest, to komunikacja typu żądanie/odpowiedź (request/response), która odbywa się za pośrednictwem adresu URL, pod którym dostępna jest funkcjonalność systemu. W większości przypadków jest, to komunikacja typu klient-serwer.
Dla aplikacji web z interfejsem użytkownika w postaci stron html będzie, to zbiór adresów URL ze stronami do wyświetlenia użytkownikowi. Natomiast dla aplikacji REST będzie, to zbiór adresów URL (konkretnie URI), które zwracają dane mniej czytelne dla zwykłego użytkownika, np. w formacie JSON.
Aplikacja web z GUI służy do komunikacji człowiek-komputer, a aplikacja REST służy do komunikacji komputer-komputer.
Poniższa tabela prezentuje adresy URL, pod którymi będą dostępne strony w ramach aplikacji.
| Działanie | Web URL | HTTP Method | HTML Page |
|---|---|---|---|
| Lista notatek | /notes | GET | notes.html |
| Dodaj notatkę | /notes/add | POST | manage-note.html |
| Szczegóły notatki | /notes/details | GET | manage-note.html |
| Edycja notatki | /notes/edit | POST | manage-note.html |
| Usunięcie notatki | /notes/delete | POST | notes.html |
Dlaczego używam tylko metod GET i POST protokołu HTTP? Ponieważ formularz HTML obsługuje właśnie tylko te dwie metody GET i POST. Co mam na myśli pisząc formularz HTML? Wizualnie jest, to zbiór elementów HTML umożliwiających wprowadzanie danych takich jak pole tekstowe, przycisk wysyłający dane, przykładem może być formularz logowania, zakładania konta lub umożliwiający dodanie postu na Facebook. Technicznie umożliwia komunikację, wysyłanie wprowadzonych danych na serwer celem ich przetworzenia.
Poniższa tabela prezentuje end-point’y zgodne z architekturą REST, która działa w oparciu o metody protokołu HTTP, np.: GET, POST.
| Działanie | REST | HTTP Method |
|---|---|---|
| Lista notatek | /api/notes | GET |
| Dodaj notatkę | /api/notes + (body/payload) | POST |
| Szczegóły notatki | /api/notes/{id} | GET |
| Edycja notatki | /api/notes + (body/payload) | PUT |
| Usunięcie notatki | /api/notes/{id} | DELETE |
Implementacja
Przyszedł czas na upragnioną implementację, zanim do tego przejdziemy, kilka słów wyjaśnienia. Tak, tak znów odwlekamy implementację, ale im więcej czasu poświęcimy na analizę i projekt tym więcej błędów, nieporozumień unikniemy podczas implementacji. Jak widać sam proces implementacji jest poprzedzony słownym opisem, który w tym przypadku składa się z “tysiąca słów”. Moim zdaniem pokazuje, to jak wiele elementów poprzedza sam proces pisania kodu źródłowego aplikacji.
Zawsze powtarzam, że zanim przystąpimy do kodowania musimy zrozumieć, co tak na prawdę mamy do zakodowania. Żeby zrozumieć tworzony system musimy zapytać, uzgodnić szczegóły z osobą i/lub firmą, która zleca nam stworzenie systemu. Pozwoli, to nam uniknąć wielu nieporozumień, nieprzyjemnych sytuacji oraz wielu godzin refaktorowania i/lub przepisywania tworzonego systemu.
Implementację wykonujemy w naszym ulubionym środowisku programistycznym np. IntelliJ IDEA. Mając przygotowany diagram klas, po prostu tworzymy klasy oraz ich zawartość zgodnie z elementami na diagramie. Dodajemy pola w klasie oraz metody. W tym miejscu gorąco zachęcam do skorzystania z techniki TDD, czyli najpierw piszemy klasę testową, a potem implementację tworzonej metody.
Podsumowując, implementacja nawet najprostszego systemu polecam rozpocząć od analizy, następnie stworzyć projekt, a dopiero na samym końcu zabrać się za kodowanie, najlepiej zgodnie z TDD. Powyższy przykład pozwala wyrobić nam dobry nawyk, który zaowocuje w przyszłości.
Zapraszam do regularnego odwiedzania mojej strony, będą pojawiać się kolejne artykuły oraz do kontaktu przez email kontakt(at)juniorjavadeveloper.pl.
Aktualna oferta dostępna na https://www.juniorjavadeveloper.pl/oferta/

Fajny artykuł, skorzystam 🙂