Silv
2019-08-07 04:36

Moja aplikacja bracket-string-validator nabiera piór i kształtów nie, kształtów nie.

Mięśni raczej nie. Nadal dwie funkcjonalności: sprawdzanie poprawności wyrażenia nawiasowego oraz testowanie wydajności (benchmarking). (Co by tu można dodać?)

Ale za to część odpowiedzialną za sprawdzanie poprawności wyrażenia nawiasowego mam już napisaną (zbyt dużo powiedziane) w Angularze. (Jeszcze muszę dodać testowanie wydajności.) To raz. Dwa, że planuję przepisać część logiki na Javę, nadto dodać GUI w C oraz bazę danych obsługującą SQL.

Kłopot trochę z testami jednostkowymi i integracyjnymi. Same testy pisze się w miarę zwyczajnie, przynajmniej w JavaScripcie. Oby tylko w innych technologiach nie było innych podejść (?). W Javie to jeszcze mogę sobie to jakoś wyobrazić, "zekstrapolować" z JavaScriptu, ale w C i w Bashu nie... będę musiał się nauczyć. Nie ma rady! Też testowanie na różnych środowiskach – trzeba mi ogarnąć Travisa i jego konfigurację. Nie wiem, czy da się ustawić konkretną dystrybucję Linuksa. Zresztą, czego ja oczekuję za darmo? Przy czym jest też plan, z początków tworzenia aplikacji, by postarać się o większą generyczność implementacji, co bym nie musiał martwić się dystrybucją. Jednak to mniej ważna sprawa, dodatek w zasadzie. Aplikacja ma działać na jednym środowisku bezbłędnie; inne – opcjonalnie i w nieokreślonej przyszłości.

W tym świetle na dalszy plan schodzi rozbudowa obecnego interfejsu CLI. Planuję m.in. dodać debug mode. I tyle. Miałbym pewnie więcej pomysłów, ale w sumie nie ma sensu, dopóki (eee... albo "skoro") nikt tego nie używa.

Z bardziej operacyjnych spraw: nadal nie wiem, jak powinien u mnie wyglądać deployment (zob. też wątek na naszym forum). Przy tylu technologiach robi się skomplikowanie... ale przy tym fajnie. :) (W teorii. Najprzyjemniej rozmyślać o tym, czego to ja nie zaimplementuję.)

Myślę też... nad PHP (tak ostrożnie). Ale prawie go nie znam. Nie wiem, czy chce mi się uczyć na tę imprezę. Ale jakby... byłby przyczynek dla mnie do ruszenia Coyote. Ale to znów... Docker. A Dockera nie mam w planach. (Jeszcze?)

Dla chętnych: planowanych jest parę innych, mniej "przebojowych" spraw – można rzucić okiem: https://github.com/silvuss/si[...]acket-string-validator/issues


Nie jest to celem tego wpisu, ale – jeśli ktoś chciałby pomóc (wiedzą), to bardzo chętnie. :) Tutaj wątek, w którym proszę o ocenę: Ocena małego projektu JS (Node.js) + Bash

#bracket-string-validator #javascript #c #bash #cli #gui #web #angular #java #sql #database #deployment #php #recenzja #nodejs

somekind

Tzn. ja się nie odnoszę do Twojego programu, nie zaglądałem nawet do kodu. Piszę ogólnie.

macabre13
2019-07-14 13:29
Haskell

Mam plan: za 5 lat nie będę pracował na etacie.

mateuszd
2019-07-08 12:10

Pojawił się nowy wpis na blogu: "Trzy rzeczy, które powinieneś wiedzieć o Hibernate"

#Java #Hibernate

http://nullpointerexception.p[...]inienes-wiedziec-o-hibernate/

Shalom

Z tym LAZY to oczywiście należy pamiętać, że dociąganie danych działa póki sesja jest otwarta! Jeśli wyjdziemy poza scope transakcji to poleci LazyInitializationException, więc generalnie lepiej robić jakieś fetch join niż polegać na tym.

kelog

Spoko artykuł, faktycznie bardzo istotne rzeczy. Dodałbym czwartą nawet: jeśli masz w aplikacji Hibernate, to nie znaczy że jesteś zobligowany używać go wszędzie. Nie ma nic złego w stosowaniu w krytycznych miejscach zwykłego em.createQuery i wyciągania danych w stringach. Kiedyś "naprawiałem" wydajność w jednym projekcie (trochę legacy już) klejąc SQL-e ręcznie w często używanych miejscach i było nawet spoko.

danek
2019-06-03 11:44

No i w końcu się nadziałem na te legendarne pułapki springa

Krótkie tło fabularne:
Potrzebuje w swojej aplikacji na starcie całości odczytać z bazy daty rozpoczęcia wydarzeń, aby wiedzieć o której zacząć próbować pobierać ich wynik. Jako, że kiedyś byłem leniwy niektóre moduły korzystają ciągle z spring data zamiast JOOQ i tak było też w tym przypadku.

Godziny wydarzeń (meczy) są zamieniane na odpowiednie opóźnienie względem teraz i lądują w ScheduledExecutorService. Samo pobranie wyniku jest trochę bardziej złożoną operacją, ponieważ trzeba:

  • pobrać z bazy konfigurację dla danego źródła danych (pobieram wyniki z różnych stron, każda ma swój format danych)
  • pobrać sam wynik, zapisać go
  • sprawdzić czy któryś z graczy nie powinien dostać jakichś punktów i zapisać jego nowy stan

Testy przechodzą, czas na pierwsze odpalenie całości. Startuje i... nic. Lekkie wtf, sprawdzam bazę, faktycznie nic się nie stało. Zapinam debuggera i lecę linijka po linii.
Drugie wtf. W pewnym momencie debbuger jakby sam się odpinał. Tym razem przechodzę całość wchodząc w każdą metodę po drodze: debugger znika po pobraniu przez springowe repository.
Tutaj krótkie info poboczne: mam napisany adapter do springowego repository, aby pasował do mojego interface. Metoda która pobiera jeden obiekt wygląda tak:

@Override  
public Option<D> findOne(UUID uuid) {  
     Option<E> entity = Option.of(repository.findOne(uuid));  //debugger twierdzi, że tu obiekt jest
     return entity.map(entityToDomainMapper);  //po wyjsciu z tej metody debugger znika
}

No więc patrze co siedzi w tym obiekcie entity: jest i moja encja! Wygląda ona tak:

 @NoArgsConstructor  
@AllArgsConstructor  
@Getter  
@Entity  
class LeagueDetails {  
    @Id  
    private UUID leagueUUID;  
    @OneToMany(cascade = CascadeType.ALL)  
    private List<LeagueDetailsSetting> config;  
    private String clientShortcut;  

}

No właśnie: List. Debugger zdążył mnie uprzedzić i już wyświetlał hibernatowy błąd związany z lazy loadingiem.

Podejście drugie.
Dodałem wszędzie fetch = FetchType.EAGER (nie są to duże dane, więc nie ma problemu). Odpalenie całości, patrzę w logi, selecty latają. Dla pewności jeszcze sprawdzam debuggerem, wszystko przechodzi jak powinno.

Ale

Nie bez powodu na początku wpisu zaznaczyłem zapisać. Kod może i się wykonał, ale w bazie pustka.
W tym momencie dostałem potężnymi flashbackami. Wszyscy wszędzie straszą transakcjyjnością springa, kiedy@Transactional zadziała kiedy nie, tym że save to nie zawsze zapisuje.

Prawdopodobnie po prostu nie wiem o jakiejś małej i nic nieznaczącej rzeczy, prawdopodobnie przez to, że to nie idzie przez requesta tylko jest odpalane z wnętrza. Tylko trochę nie mam czasu teraz w to wszystko wnikać (sesja :<), a i tak już przepisywałem wszystko na JOOQ.

@jarekr000000 czy jest jakiś łatwy sposób mapowania obiektów na JOOQ czy trzeba ręcznie?

#java #spring

danek

@jarekr000000: samo mapowanie raczej nie jest problemem, bardziej nużące jest pisanie insertów, selectów itp, bo trzeba wszystkie pola ręcznie, wszystkie kolumny itp

danek
2019-04-23 13:30

Krótki suplement do poprzedniego wpisu. Jak mapuje błędy na odpowiedzi http. Trochę mniej treści, a więcej kodu.

Mam jeden interface na wszystkie błędy:

public interface ResponseError {
    String getMessage();
    int getHttpCode();
}

Przykładowe enum:

public enum UserError implements ResponseError {
    //normalnie jest ich oczywiście więcej
    EMPTY_USERNAME_OR_PASSWORD("Empty username or password", 400),
    DUPLICATED_USERNAME("Duplicated username", 400);

    private int httpCode;
    private String message;

    UserError(String message, int httpCode) {
        this.httpCode = httpCode;
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    @Override
    public int getHttpCode() {
        return httpCode;
    }
}

Narzuciłem sobie, aby wszystkie fasady zwracały:
Either<? extends ResponseError, ?>
Dzięki temu mam jeden generyczny mapper:

public final class ResponseResolver {
    private ResponseResolver() {}

    static ResponseEntity resolve(Either<? extends ResponseError, ?> input) {
        return input
                .map(ResponseEntity::ok)
                .getOrElseGet(ResponseResolver::createErrorResponse);
    }

    private static ResponseEntity createErrorResponse(ResponseError error) {
        ErrorResponse response = new ErrorResponse(error.getMessage());
        int httpCode = error.getHttpCode();
        return new ResponseEntity<>(response, HttpStatus.valueOf(httpCode));
    }
    //Bonusowo na tej samej zasadzie działa z Option (Optionalem)
    public static <T> ResponseEntity<T> resolve(Option<T> input) {
        return input
                .map(x -> new ResponseEntity<>(x, HttpStatus.OK))
                .getOrElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
}

(Gdzie klasa ErrorResponse jest zwykłym DTO z jednym polem, żeby wynik był jsonem)

No i teraz w kontrolerze (na przykładzie springa):

    @PostMapping("login")
    public ResponseEntity generateToken(@RequestBody LoginUserInfo loginUserInfo) {
        Either<UserError, UserToken> userDetails = userFacade.login(loginUserInfo);
        return ResponseResolver.resolve(userDetails);
    }

No i właściwie to tyle ;)

Powyższe rozwiązanie ma właściwie pewną wadę: miesza warstwy. Czy jest to problem? Zazwyczaj nie, bo i tak pisze się soft dedykowany pod pracę na serwerach i nikt go w inny sposób nie odpala. Dodatkowo ta nadmiarowa informacja w postaci kodu http i wiadomości nie przeszkadza w żaden sposób w odpaleniu kodu np. z konsoli. Rozwiązaniem tego mógłby być osobny mapper w warstwie http, ale to już wchodzi trochę w sztukę dla sztuki, więc wydaje mi się, że taki kompromis pomiędzy pragmatycznością, a łamaniem abstrakcji między warstwami jest jeszcze akceptowalny.

@Desu @CountZero

#java

marlukk

danek Fajne rozwiązanie, ale mam pytanko. Co jeśli w moich treściach błędów chciałbym mieć komunikaty parametryzowane np. Nie znaleziono gracza o id=? i w miejsce ? wartość ma być nadawana dynamicznie.

danek

@marlukk: zamiast enum używaj obiektów

Grzegorz Kotfis
2019-03-20 12:55

I wrzucam pełny odcinek z Tomkiem Nurkiewiczem. Mam nadzieję, że będzie się dobrze słuchało. https://devsession.pl/japrogramista-7
Tutaj jest wątek z zapowiedzią.

#podcast #programowanie #java

szarotka

Posłuchałabym wywiadu z Jarkiem Ratajskim, bo to poza wiedzą, to niecodzienna osobowość, ale Jarek za granicą jest na co dzień, więc go łatwo nie złapiesz :(

nie100sowny

Ja bym chciał z pozostałymi Java Championami z Polski. Jackiem Laskowskim, Konradem Malawskim i Andrzejem Grzesikiem. Dawaj też znać, kiedy będziesz planował kolejne wywiady. Postaram się zaproponować pytania.

Grzegorz Kotfis
2019-03-18 12:37

Uwaga! Tomek Nurkiewicz podaje niezawodny sposób na sprawdzenie czy liczba jest ujemna ;)
Krótka zapowiedź tego co nagraliśmy w zeszły piątek podczas #SegFault w Gdańsku.
#podcast #programowanie #java

Hispano-Suiza

@szarotka: Dlaczego nazywasz takich ludzi programistami? To podludzie :-)

vpiotr

miejsca gdzie rekurencja jest tylko smutnym żartem od matematyków dla programistów.