Tygodniowe wyzwanie programistyczne – #4

By 17 października 2016#main, ITlogy, Wydarzenia

Czwarty dzień wyzwania oznacza, że jesteśmy w połowie drogi! Początkujących czeka dziś praca z bibliotekami i „cudzym” kodem, zaawansowanych krótka programistyczna wprawka z małą niespodzianką :) Gotowi?

Wyzwanie dla początkujących

Przed przystąpieniem do zadania, zastanów się nad rezultatem Twojej wczorajszej pracy: Czego dowiedziałeś się o swoich umiejętnościach? Czego się nauczyłeś? Co zrobisz z tą wiedzą?

 

Software development to nie tylko tworzenie nowego kodu i rozwijanie go, ale też umiejętność zrozumienia rozwiązań innych i radzenie sobie z problemami jakie mogą się tam pojawić. Pewnie usłyszałaś już jakaś historię o kodzie, który przypomina wykopaliska i nikt nie chce go dotknąć ;) No cóż, czasem trzeba. Dlatego od samego początku warto nauczyć się rozumieć pracę innych. A jak to można zrobić? Ano czytając kod na głos. Więcej o samej metodzie znajdziecie, tradycyjnie w naszym wpisie. Czytanie kodu jest super ćwiczeniem, bo pozwala Ci zrozumieć logiczny ciąg przyczynowo-skutkowy zapisanego programu, a także może być świetnym sposobem na poznanie nowych bibliotek i wzorców ;)

Wyszukaj na GitHubie jakiś projekt open source/ popularną bibliotekę w Twoim języku programowania i zacznij go czytać. Znajdź jeden plik, najlepiej taki, który ma metody pomocnicze (np. SpringReflectionUtils albo IOUtils z biblioteki Apache Commons) i linijka po linijce opowiadaj sobie co w danym miejscu się dzieje.

Po 45 min takiego czytania odpowiedź na pytania:

  • czego dotyczył czytany przeze mnie kod?
  • jakie rozwiązania zastosowane w czytanym kodzie już znalałam?
  • co było dla mnie nowością?
  • co z tego mogę również zastosować w swoim kodzie?

Nasza odpowiedź

Wybrałam do „poczytania” klasę IOUtils z biblioteki Apache Commons.
Jest to biblioteka, która służy do pracy z I/O, czyli w praktyce możesz używać ją w pracy z obrabianiem strumieni danych np. działając z danymi zebranymi w pliku csv. Tak, oczywiście, możesz to wszystko robić „samemu” w Javie (java.io), jednak, jako, że takie zadania są częste powstała właśnie taka biblioteka, która pozwala Ci korzystać z gotowych metod związanych z przetwarzaniem takich strumieni informacji. Dzięki temu, że skorzystasz z jej interfejsów, możesz skupić się na faktycznym zadaniu, a nie „kodować” koło na nowo. Jednak zobaczenie jak to wygląda w środku jest ciekawym doświadczeniem.
W Klasie IOUtils mamy kilka podstawowych metod związanych z obróbką danych, a także statyczne zmienne reprezentujące różne sposoby dzielenia linii w zależności od systemu.
  • W klasie możemy znaleźć metodę closeQuietly(), która od metody z javy.io różni się tym, że ignoruje IO Exception – tutaj warto zwrócić uwagę, na to, że taki pusty catch jest oznaczony komentarzem //ignore (czyli wiemy, czemu jest on pusty).
  • rozróżnione zostało kopiowanie i kopiowane dużych Obiektów (metody copy() i copyLarge()),
  • zastosowany został koncept overloadingu (przeciążania), czyli pod taką samą nazwą mamy takie metody, które przyjmują różny zestaw argumentów

Większość tego kodu przypomina to, co samemu musiałabyś napisać nie używając biblioteki. Dzięki jej zastosowaniu, kod staje się trochę czystszy i masz pewność, ze nie zapomnisz o żadnym szczególe.

Wyzwanie dla praktyków

Przed przystąpieniem do zadania, zastanów się nad rezultatem wczorajszej pracy: Czego dowiedziałeś się o swoich umiejętnościach? Czego się nauczyłeś? Co zrobisz z tą wiedzą?

Code Kata, to sposób na ćwiczenie się w pisaniu kodu. I dzisiaj mamy dla Was takie właśnie ćwiczenie. Założenie jakie przyjmumjesz na początku: to zadanie, jest jak prawdziwe życie :), a wytyczne przyrastają z każdym rozwiązaniem. Czytaj je więc po kolei, nie przechodź do kolejnej części bez zaimplementowania poprzedniej, bo odbierzesz sobie całą zabawę!

Część 1: Pogoda

Napisz aplikację wyciągającą dane o pogodzie (np. z https://developer.yahoo.com/weather/). Możesz wybrać maksymalną temperaturę, opis, czy całą prognozę…

Część 2: Sport

Napisz drugą aplikację przetwarząjącą dane o zawodnikach sportowych(np. z użyciem https://developer.yahoo.com/fantasysports/guide/).

<<<Tutaj jest 3 część zadania, zaznacz, by przeczytać>>>

Część 3: DRY

Połącz obie aplikacje ze sobą, korzystając z zasady DRY.

Podsumowanie:

    • w jaki sposób decyzje, które podejmowałeś pisząc każdy z tych fragmentów wpływał na to, że połaczenie ich było później łatwiejsze/trudniejsze?
    • czy sposób pisania drugiego programu był w jakimś stopniu dostosowany do pierwszej aplikacji?
    • co osiągnąłeś poprzez wyciągnięcie wspólnych elementów? Co musiałeś poświęcić/w czym takie ;wspólne’ rozwiązanie jest gorsze? Które wersje byłyby łatwiejsze w utrzymaniu i rozwijaniu w przyszłości?

Zadanie pochodzi ze strony: http://codekata.com/kata/kata04-data-munging/

Nasza odpowiedź

Jako dwa źródła danych wybrałem nieco inne API niż w zadaniu – pierwsze to API serwisu Wikipedia, z którego odczytuję kiedy miała miejsce ostatnia zmiana strony głównej oraz jej opis. Drugie API dotyczy pogody, pobieram pogodę dla Wrocławia i wyświetlam jej opis na najbliższy dzień. Kod obu rozwiązań znajdziesz na GitHub’ie: https://gist.github.com/jderda/a7b3f4e14370f264ec932bce037e0d08

Oczywiście pomijamy tutaj kwestię nieczytelnego kodu czy braku podziału na mniejsze bloki kodu – nie o clean code w tym zadaniu przede wszystkim chodziło ;)

Kwestia, która od razu rzuca się w oczy to fakt, że pomimo są to całkowicie odmienne API, większość kodu pozostaje taka sama – różni się adres URL, konkretna ‘ścieżka’ w odpowiedzi, którą chcemy pobrać z JSONa oraz (ewentualnie) rodzaj zwracanych danych.

Daje nam to trzy metody, które na pewno możemy wyłączyć jako abstrakcyjne i zależne od przypadku, niech będą to:

buildRequestURI – jej celem jest zbudowanie konkretnego URI, pod którym otrzymamy dane

readRawData – ma za zadanie zamienić odpowiedź z serwera na obiektową reprezentację

convert – ma za zadanie zamienić obiektową reprezentację odpowiedzi serwera na docelową odpowiedź

Całość jak zapewne zauważyłaś przypomina proces ETL (ang. Extract-Transform-Load; i nim w istocie jest) – najpierw pobieramy dane, konwertujemy je w sposób pozwalający na filtrowanie/obróbkę, wyciągamy interesujące nas informacje i zwracamy je. W praktyce moglibyśmy wykorzystać dowolne narzędzie przeznaczone do pracy z tego rodzaju procesami, i także by zadziałało :)

Jako że treść zadania była jasna – połączyć kod w sposób, który jak najbardziej eliminuje duplikacje, zaimplementowałem rozwiązanie z użyciem generyków i klas bazowych. Pozwala na implementacje logiki ETL dla dowolnego źródła danych opartego o protokół HTTP, niezależnie od formatu danych (wystarczy zaimplementować odpowiednią logikę konwertującą).

Oczywiście całość implementacji mogła wyglądać jeszcze lepiej, można było użyć interfejsów funkcyjnych itp, ale jak już wspomniałem idealny Clean code nie był celem tego zadania ;)

Oczywiście drugie rozwiązanie jest zdecydowanie łatwiejsze do utrzymania i rozwijania w przyszłości.

Kod rozwiązania po refaktorze znajdziesz na https://gist.github.com/jderda/3a9ddea19734c0e1a83cdc7fd07cbb3c

Pamiętaj, że nowe zadania będą się pojawiać codziennie o godzinie 11. Rozwiązania będziemy umieszczać pod zadaniami kolejnego dnia o godzinie 18. Nie zapomnij podzielić się swoimi odpowiedziami i przemyśleniami na wydarzeniu na facebooku, a jak masz ochotę to też w komentarzu ;)!

Linki do wszystkich zadań znajdziesz w innym wpisie na naszym blogu. Powodzenia!

  •  
  •  
  •  
  •  
  •  
  • Ania

    Cześć,

    próbowałam rozwiązać zadanie korzystając z API Yahoo. O ile pogoda okazała się prosta i nie wymagała autoryzacji, o tyle pobranie danych dotyczących sportu wymaga autoryzacji OAuth i okazało się wyzwaniem nie do pokonania. Próbowałam autoryzacji przy pomocy biblioteki oauth.signpost Niestety serwer zwraca:
    Please provide valid credentials. OAuth oauth_problem=”signature_invalid”, realm=”yahooapis.com”. A używam clientID i sectet wygenerowanych tak jak w instrukcji Yahoo.
    Dlatego z niecierpliwością czekałam na przykładowe rozwiązanie. Wielka szkoda, że nie pokazaliście przykładu z autoryzacją OAuth, czy mogłabym liczyć na udostępnienie działającego przykładu?

    • Ok postaramy się wieczorem/jutro pokazać przykładową pracę z OAuth ;)

    • Cześć,
      samo wysyłanie zapytań z OAuthem jest banalne – zerknij na przykładowy kod tutaj: https://gist.github.com/jderda/ec4ec4349e20ea8ad91e85398c3839dd#file-sendoauthrequest-java-L9 (linijka 9 to różnica pomiędzy zapytaniem bez OAuth a takim z OAuth; oczywiście adres URL w tym kodzie należy zmienić na właściwy dla danego API).

      Pytanie skąd wziąć ten token? Każdy usługodawca może mieć inną procedurę – np. GitHub pozwala wygenerować takie tokeny na swojej stronie (tak, że można przekleić je do aplikacji – instrukcja tutaj: https://help.github.com/articles/creating-an-access-token-for-command-line-use/), Yahoo z kolei wymaga generowania i odświeżania. Otóż dokumentacja Yahoo wydaje się być fatalna pod tym względem (przykłady, które nie bardzo mają prawo działać…) – niestety procedura w przypadku Yahoo wymaga użycia przeglądarki i ‚manualnego’ wygenerowania tokenu. Dopiero wtedy aplikacja może z niego korzystać (pod warunkiem, że odświeża go odpowiednio często).

      Wygenerowałem swój token bazując na instrukcji https://developer.yahoo.com/oauth2/guide/flows_authcode/ .
      Z wpisu wnioskuję, że masz już wygenerowany swój clientId i secret. Pierwszy krok to odwiedzenie w przeglądarce adresu https://api.login.yahoo.com/oauth2/request_auth?client_id=dj0yJmk9enVHTGFYU0dIS2xqJmQ9WVdrOVVYWlpVVkYwTXpBbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD00Yw–&redirect_uri=oob&response_type=code&language=en-us

      Oczywiście podmieniając client_id na swój client_id. Po potwierdzeniu tożsamości, otrzymasz kod – 6 liter, które musisz wykorzystać w kolejnym zapytaniu. To jednak musi być wysłane za pomocą metody POST – najprościej wykorzystać do tego jakieś narzędzie do testowania API (ja skorzystałem z online’owego narzędzia hurl.it – bo było pierwsze w Google ;) ). Na podstawie powyższej dokumentacji uzupełniłem formularz w ten sposób: http://prnt.sc/cwehaw (pamiętaj, żeby w sekcji Authentication wpisać swój clientId i secret, a w body wpisać kod otrzymany w poprzednim kroku). Po wysłaniu zapytania w odpowiedzi powinnaś otrzymać JSONa podobnego do tego na screenie – token OAuth to ten długi ciąg znaków zaczynający się od „P8WoePecowJwzD4YFICRpfyjupvT9pS0QCUMmu0Ys…” – to właśnie tą część trzeba dokleić w nagłówku po ‚Bearer’.

      To trochę inny sposób niż ten pokazany w przykładach na Yahoo – na moje oko tamten kod nie ma prawa działać (może to jakiś ich starszy proces?), ale może się mylę ;) Powyższy sposób pozwala generować tokeny do wykorzystania w API.

      Dobór przykładu API w zadaniu był nieco niefortunny – API do GitHuba nawet jest dużo łatwiejsze do współpracy i lepiej udokumentowane – lekcja dla nas, żeby lepiej weryfikować zewnętrzną dokumentację na przyszłość ;)

      Mam nadzieję, że pomogliśmy =)

      • Ania

        Bardzo dziękuję za wskazówki, w wolnej chwili zmierzę się z tym zadaniem jeszcze raz. Mam nadzieję, że tym razem się uda :)