Java - pytania rekrutacyjne mid/senior

Java - pytania rekrutacyjne mid/senior

Wątek przeniesiony 2022-01-19 11:11 z Kariera przez cerrato.

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:16 dni
  • Postów:3277
2

@PanamaJoe: Przykład praktycznego wykorzystania:
Piszesz aplikację, która ma wyświetlać listę ticketów w Jira.
Robisz "jakiś" mechanizm, który dba o to, żebyte tickety znalazły się w liście, były dociągane nowe, zamknięte usuwane itd.
Dorabiasz widok gdzie jakaś kontrolka ma wyświetlać aktualną zawartość listy. Widok rejestruje listenera w tej liście, i jest powiadamiany jeżeli zaistnieje konieczność odświeżenia tego co wyświetla.
Za chwilę pojawia się wymaganie biznesowe, że jak pojawi się coś nowego, to masz wyświetlić jakieś powiadomienie, a oprócz widoku listy masz też zrobić drugi panel, który wyświetli te dane ale w postaci kafelków - zmiana jest banalna.
Okazuje się, że aplikacja zaczyna lagować, bo wszystko zrobiłeś na pojedynczym wątku, a pobranie nowych ticketów stało się czasochłonne - podział na wątki również jest banalny.
Firma przepina się z Jira na RedMine ;) , zmieniasz jedynie mechanizm zasilający, cała reszta pozostaje bez zmian.
Trafiasz na ten jeden przypadek na milion, kiedy faktycznie ma znaczenie czy użyłeś ArrayListy, czy LinkedList zmieniasz jedną linijkę w kodzie.

W praktyce takie nasłuchiwanie zmian jest potrzebne dość często, przykład z listą jest akurat dlatego, że jest prosty do zrozumienia.

--edit
Dam też przykład jak można rozwiązać problem:

Kopiuj

public class ObservableList<T> implements List<T>{
private final List<T> underlying;
private final List<ListListener> observers = new ArrayList<>();
//tu następuje implementacja wszystkich metod List:
public int length(){
  return underlying.length();
  }
........
//dla metod które coś zmieniają:
public void clear() {
  underlying.clear();
  observers.forEach(ListListener::onClear);
  }
}
//do tego dodanie możliwości rejestrowania listenerów
public void addListener(ListListener listener){
  observers.add(listener);
}

Pewnie warto byłoby trzymać te listenery dodatkowo zapakowane w WeakReference (bo o dodaniu to pamięta każdy, o wyrejestrowaniu już nie zawsze), można by to proxy rozdzielić na DefaultProxy z implementacjami 1:1 i dopiero dziedzicząc po nim nadpisywać konkretne metody.

edytowany 1x, ostatnio: piotrpo
PanamaJoe
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 3 lata
  • Postów:310
0
piotrpo napisał(a):

@PanamaJoe: Przykład praktycznego wykorzystania:

Piszesz aplikację, która ma wyświetlać listę ticketów w Jira.
Robisz "jakiś" mechanizm, który dba o to, żebyte tickety znalazły się w liście, były dociągane nowe, zamknięte usuwane itd.
Dorabiasz widok gdzie jakaś kontrolka ma wyświetlać aktualną zawartość listy. Widok rejestruje listenera w tej liście, i jest powiadamiany jeżeli zaistnieje konieczność odświeżenia tego co wyświetla.
Za chwilę pojawia się wymaganie biznesowe, że jak pojawi się coś nowego, to masz wyświetlić jakieś powiadomienie, a oprócz widoku listy masz też zrobić drugi panel, który wyświetli te dane ale w postaci kafelków - zmiana jest banalna.

Sorry z góry, mogę głupoty pisać, ale czy nie było by prościej zamiast nasłuchiwać zmian to, co jakiś czas przejechać po liście i sprawdzić stan przełączników (wartości listy) i aktualizować stany tych kontrolek? A jeżeli to jest jakiś krytyczny system dla pocisków manewrujących (choć podejrzewam, że nie byłby w Javie pisany wtedy) to np. zrobić swoje rozszerzenie tej kolekcji, gdzie nadpisałoby się metody zmieniające jej elementy tak, że dodanie/update/usunięcie wyzwalałoby automatycznie jakąś reakcję?


A poza tym sądzę, że bootcampy należy zniszczyć.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:16 dni
  • Postów:3277
2

@PanamaJoe: Zależy, jak pisałem przykład jest (jak właściwie każdy przykład na interview) trochę z d. Pytanie też co oznacza dla ciebie prościej. Jeżeli chodzi o szybkość pisania, to pewnie najszybciej byłoby mieć jakiś kawałek kodu typu:

Kopiuj
tickets = jiraConnector.getTickets();
ui.update(tickets);

Ale ma to trochę wad:
Klasa w której to tworzysz (kontroler), ma spore szanse na rozwinięcie się w czasie do GodObject, bo będzie odpowiadać za kontrolowanie pozyskiwania danych i za co najmniej wyzwalanie zmian na UI.
Załóżmy, że na tym UI, użytkownik będzie mógł coś zrobić i powinien być responsywny. Jeżeli zrobisz tak jak wyżej, to znowu najprościej będzie robić to tak jak wyżej, co oznacza, że wszystko (UI, kontroler, komunikacja z Jira) będzie chodzić na jednym wątku. Przyjmuje się, że responsywność UI nie powinna przekraczać 100ms, czyli jeżeli najedziesz myszką na jakiś przycisk, on zmienia kolor i ta zmiana powinna zostać wykonana natychmiast, żeby użytkownik nie czuł lagowania aplikacji. Jeżeli w tym czasie akurat jesteś w trakcie pobierania ticketów z zewnętrznego źródła to nic innego nie zostanie zrobione. Jeżeli piszesz aplikację na Androida, to nawet ci się nie skompiluje, bo tam nie wolno robić komunikacji na głównym wątku.
To co opisałem to też nie jest jakaś wielka, samodzielnie wymyślona magia, poczytaj sobie o różnicach pomiędzy MVC i MVVM.

Odpytywanie co ileś tam sekund też ma sporo wad. Będzie to kod wykonywany nadmiarowo w większości przypadków, czyli albo zużyje jedynie trochę czasu CPU (desktop), albo dodatkowo baterię. W dodatku nawet w realnych zastosowaniach może ci zależeć na czasie (aplikacja do czatowania) i te 5s będzie wprowadzać dodatkowe opóźnienie w dostarczeniu wiadomości z jednego UI do drugiego.

Wreszcie, są moje prywatne oczekiwania w stosunku do osoby, która chcę mieć w zespole (mowa o seniorze) i tego co osobiście uważam za istotne przy tworzeniu oprogramowania. Rzeczywistość jest taka, że pracujemy ze zmieniającymi się w krótkim czasie wymaganiami klienta/rynku. Agile, to nie są sprinty, retrospektywy, daily i temu podobne bzdety, tylko zdolność do reagowania na dynamikę otoczenia. Jak spojrzysz sobie na te wszystkie SOLID, clean code/architecture, DDD, TDD, BDD, Design Pattern, CI, CD, to ich głównym, a przynajmniej celem jest zapewnienie, że kod, który tworzy zespół będzie utrzymywalny, co w delikatnym uproszczeniu oznacza podatność na zmiany. Na poziomie junior mogę zatrudnić kogoś z przyzwoitą znajomością Java, bo to wystarczy do tego żeby napisać kod, na poziomie senior chcę, żeby taka osoba wiedziała po co to robi i była w stanie w praktyce zastosować część tych wynalazków, co nie oznacza, że z radością wezmę do zespołu fanatyka któregoś podejścia.

PanamaJoe
No tak, tylko pytanie brzmi jakbyś właśnie oczekiwał jakiegoś kreatywnego rozwiązania. Może lepiej pytać wprost o znajomość wzorców projektowych, jeżeli zależy Ci na zatrudnieniu wymiennego bloczka.
piotrpo
Mi nie chodzi o to, żeby ktoś "znał wzorce". Jeżeli nie zna nazwy - luz, jeżeli znajdzie dobre rozwiązanie takiego problemu i będzie potrafił je uzasadnić, to tym lepiej.90% kandydatów "zna wzorce", może 10% potrafi je zastosować. Myślałeś kiedyś o jakimś problemie w sposób "o tu wstawimy dekorator, to owiniemy proxy, a tutaj najlepsza będzie builder? Ja nigdy, a każdy z tych wzorców stosowałem wiele razy. Dlatego wolę zapytać o niby-realny problem, zamiast zapytać o proxy i observer.
LU
  • Rejestracja:ponad 11 lat
  • Ostatnio:6 dni
  • Lokalizacja:Gdańsk
7

Na większość z tych pytań odpowiedziałem https://lsdev.pl/posts/java-interview-pytania-rekrutacyjne/
może będzie pomocne dla kogoś. Jeżeli popelniłem jakiś błąd merytoryczny zachęcam do dyskusji ;)


PI
  • Rejestracja:ponad 9 lat
  • Ostatnio:4 miesiące
  • Postów:2787
0
lookacode1 napisał(a):

Na większość z tych pytań odpowiedziałem https://lsdev.pl/posts/java-interview-pytania-rekrutacyjne/

może będzie pomocne dla kogoś. Jeżeli popelniłem jakiś błąd merytoryczny zachęcam do dyskusji ;)

Mała sugestia - w pytaniu nr 19, o model pamięci w javie, warto dodać, że w off-heapie są też trzymane pola static

jarekr000000
Generalnie nie. Ktoś Ci sprzedał błędne informacje.
PI
@jarekr000000: Chodzi Ci o to, że po Javie 8, jak PErmGen zamieniło się w MEtaspace, to statici już są w heapie przechowywane?
vpiotr
Z jednej strony Metaspace jest określany jako off-heap, z drugiej ma jakies tam sprzątanie.
jarekr000000
@Pinek - statici (te normalne ) nie są przechowywane też w Metaspace.
Patryk Mieleszko
  • Rejestracja:około 4 lata
  • Ostatnio:około 3 lata
  • Postów:69
1
lookacode1 napisał(a):

Na większość z tych pytań odpowiedziałem https://lsdev.pl/posts/java-interview-pytania-rekrutacyjne/

może będzie pomocne dla kogoś. Jeżeli popelniłem jakiś błąd merytoryczny zachęcam do dyskusji ;)

To zabawne ale znając te odpowiedzi wciąż możesz
a) być kiepskim programistą
b) nie umieć pisać aplikacji
c) oba powyższe

edytowany 1x, ostatnio: Patryk Mieleszko
Zobacz pozostałe 5 komentarzy
PerlMonk
@p_agon: Toż M$ zrobił J#. Oczywiście nie wyszło :]
p_agon
A co wyszlo M$? Certyfikaty chmurowe? #pdk
S9
Age of Empires 2.
PerlMonk
Xbox... chociaż pad do Xboksa najbardziej.
jarekr000000
BASIC na 8080 i 6502 microsoft zrobił całkiem dobrze.
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Mała sugestia - w pytaniu nr 19, o model pamięci w javie, warto dodać, że w off-heapie są też trzymane pola static

Panie Pinku nieeeeeeee.
https://stackoverflow.com/questions/8387989/where-are-static-methods-and-static-variables-stored-in-java/8388068


PI
Czyli moja wiedza jest sprzed javy 8 xd
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
3

@lookacode1:

Jeżeli popelniłem jakiś błąd merytoryczny zachęcam do dyskusji

pytanie 3

Nie ma to nic wspólnego ze Springiem i na dobrą sprawę Spring raczej incydentalnie wspiera tą adnotacje bo implementuje CDI, ale zaręczam ci że można tego używać nie mając żadnego Springa w projekcie.

pytanie 7

o_O chcesz listę ID przekazywać w URLu jako path variable? To raczej strasznie słaby pomysł, bo URL ma bardzo ograniczoną długość.

pytanie 9

Przy zmianie wymagań kod...

Ja bym jednak sugerował że przy nowych wymaganiach open-close ma sens. Jeśli wymagania uległy zmianie (funkcja ma zwracać 1 a wcześniej miała zwracać 2) to ja bym jednak kod zmienił i wyrzucił ten błędny.

pytanie 12

aby każdy kolejny odczyt zwracał ten sam wynik możemy zwiększyć poziom izolacji na REPEATABLE_READ.

phantom read chyba jednak sprawia że wynik niekoniecznie nie będzie taki sam ;)

pytanie 16

Sól pełni rolę mitygacji przed atakami słownikowymi

Nie, sól jest związana z rainbow tables a nie z atakiem słownikowym. Threat model zakłada że atakujacy zna wszystkie sole.

pytanie 17

dzięki parallelStream() możemy w prosty sposób zrównoleglić operacje na danych

No nie wiem, akurat takie użycie na pałe parallelStream to moze ci deadlockować aplikacje bardzo łatwo, albo zrobić bottleneck w miejscu w którym się tego nie spodziewasz ;)

wyrażenia (lambda) w map/filter itd. nie mogą rzucać tzw. checked exceptions co może być problematyczne np. jak przetwarzamy I/O

Istnienie Optionala czy Eithera sprawia ze ten problem nie istnieje

pytanie 20

Atak SQLI polega na zmanipulowaniu wejścia (np. nazwy użytkownika lub frazy wyszukiwania) w taki sposób aby silnik bazodanowy podczas parsowania tego zapytania zinterpretował je inaczej niż twórca aplikacji założył

No nie, SQLi to nie jest atak na system bazodanowy :D To jest atak na aplikacje która przygotowuje zapytanie do bazy. Silnik niczego tu nie parsuje i nie interpretuje źle. To aplikacja generuje zmanipulowane query do bazy.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
Zobacz pozostałe 11 komentarzy
SI
@Shalom: to teraz jesli ja napisze ze myslalem o Postgresie a Ty ze o Oracle (albo ogolnie specyfikacji SQL) to wyjdzie ze obaj mieliśmy troche racji.
Shalom
To jak z tym stojącym zegakiem który dwa razy dziennie pokazuje dobrą godzinę ( ͡° ͜ʖ ͡°)
SI
@Shalom: No dobra, żaden z nas nie mial racji, bo żaden nie zaczął od pytania 'a dla jakiej k...a bazy'? Albo - jak każdy porządny konsultant/architekt by zaczął - 'to zależy' :P Ładnie to opisał Kleppman w "Designing Data-Intensive Applications" - jest absolutny burdel na rynku jeśli chodzi o poziomy izolacji i gwarancje szeroko pojętego 'consistency'. Co baza to inaczej.
Shalom
Nie do końca, bo chyba każda baza trzyma się zasady, że poziomy oferują przynajmniej bezpieczeństwo od znanych anomalii. Mogą oferować więcej (jak postgres i jego repeatable read) ale nie oferują mniej
SI
@Shalom: Wlasnie wyczytalem ze MySQL tez gwarantuje brak phantom reads na poziomie repeatable read, przynajmniej w InnoBD (https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html ). Jak na razie 2:1 dla mnie :P Jak to nie jest burdel, to ja nie wiem co jest :)
LU
  • Rejestracja:ponad 11 lat
  • Ostatnio:6 dni
  • Lokalizacja:Gdańsk
0

@Shalom:
Thx część poprawiłem.

Nie ma to nic wspólnego ze Springiem i na dobrą sprawę Spring raczej incydentalnie wspiera tą adnotacje bo implementuje CDI, ale zaręczam ci że można tego używać nie mając żadnego Springa w projekcie.

Tak wiem i tak napisałem, że ta adnotacja pochodzi z specyfikacji a Spring ją wspiera. Generalnie piszę raczej w kontekście Springa z uwagi, że jest najpopularniejszy.

Istnienie Optionala czy Eithera sprawia ze ten problem nie istnieje

Nie każdy tego używa dlatego uznałem to jako wadę poza tym często wkurza.
Czasem chcesz tylko raz złapać exception i go zmapować na either a nie wszystko wrapować w Either.

No nie wiem, akurat takie użycie na pałe parallelStream to moze ci deadlockować aplikacje bardzo łatwo

Uznałem to jako zaletę bo lepiej jak jest taki feature niż jak go nie ma a kiedy go zastosować to już inna sprawa
natomiast na pewno w prostych przypadkach się przydaje kilka razy zastosowałem ;)

o_O chcesz listę ID przekazywać w URLu jako path variable? To raczej strasznie słaby pomysł, bo URL ma bardzo ograniczoną długość.

Racja chociaż jak tak odpowiedziałem rekruterowi to powiedział, że dobrze :D


Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Tak wiem i tak napisałem, że ta adnotacja pochodzi z specyfikacji a Spring ją wspiera. Generalnie piszę raczej w kontekście Springa z uwagi, że jest najpopularniejszy.

Tylko że Spring to akurat bardzo słaby przykład implementacji CDI bo ma kupę swoich udogodnień ;) Np. wg specyfikacji konstruktor do którego wstrzykujesz musi mieć @Inject a Spring pozwala na brak takiej adnotacji. Generalnie nie używałbym Springa jako przykładu do ilustracji JEE

Uznałem to jako zaletę bo lepiej jak jest taki feature niż jak go nie ma a kiedy go zastosować to już inna sprawa natomiast na pewno w prostych przypadkach się przydaje kilka razy zastosowałem

Sęk w tym że to jest dość ryzykowny ficzer, szczególnie właśnie użyty tak na pałe. Wynika to z tego jak on działa "pod spodem" - domyślnie puszcza to na standardowym fork join poolu, tylko ze ten sam fork join pool jest używany także w innych celach (np. do asynchronicznego uruchomienia CompletableFuture). W efekcie ten parallelStream w jednym miejscu w kodzie, może zablokować ci wykonanie jakiegoś CompletableFuture w zupełnie innym miejscu i odwrotnie jakieś długo działające CompletableFuture może ci zablokować tego streama.
A może być jeszcze gorzej, bo możesz zrobić kompletny deadlock, jeśli operacja którą odpalasz przez parallelStream woła pod spodem CompletableFuture (np. wrapujesz tak jakiś REST call) :D Bo nagle cały pool będzie zajęty streamem i aplikacja zablokuje się czekając na wątek żeby odpalić CompletableFuture :)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
LU
  • Rejestracja:ponad 11 lat
  • Ostatnio:6 dni
  • Lokalizacja:Gdańsk
0

parallelStream w jednym miejscu w kodzie, może zablokować ci wykonanie jakiegoś CompletableFuture w zupełnie innym miejscu

A czy to jest coś dziwnego? Np. jak mamy pule połączeń do bazy to też kilka jakichś ciężkich zapytań może przyblokować inne itd. przez co pula się wyczerpie.
Z tego co wiem można podać dla parallelStream() customowy thread pool ale nigdy nie próbowałem.
Ja parallelStream wykorzystałem np. tutaj gdzie wiedziałem, że lista nie będzie jakaś duża
więc uznałem, że warto zrównoleglić.


vpiotr
Z tego co wiem po prostu nie należy stosować domyślnej puli i problem solved. https://www.baeldung.com/java-8-parallel-streams-custom-threadpool
Shalom
Tak, generalnie sugerowałbym używać tego tylko i wyłącznie z własną pulą.
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

A czy to jest coś dziwnego? Np. jak mamy pule połączeń do bazy to też kilka jakichś ciężkich zapytań może przyblokować inne itd. przez co pula się wyczerpie.

Problem jest w tym że jest to niewidzialne. Jesteś w stanie z głowy powiedzieć mi co w JVMie korzysta z tego samego forkjoinpoola i jest w stanie się tak deadlockować? :) W przypadku puli do bazy generalnie używasz jej gdzieś explicite, a tutaj nie ma to miejsca.

Ja parallelStream wykorzystałem np. tutaj gdzie wiedziałem, że lista nie będzie jakaś duża

To teraz wyobraź sobie że postanowiłeś to przetwarzać sobie teraz asynchronicznie i to RESTowe query które tam masz wrapujesz w jakieś CompletableFuture.suppyAsync() żeby wykonywało się w tle, bo nie potrzebujesz tych wyników od razu ;)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
LU
  • Rejestracja:ponad 11 lat
  • Ostatnio:6 dni
  • Lokalizacja:Gdańsk
0

@Shalom:
Ok czyli wniosek taki żeby nie używać ForkJoinPool tylko tworzyć customowe thread poole?


Zobacz pozostały 1 komentarz
Shalom
Nie używać domyślnego poola (czyli takiego parallelStream bez podania na czym ma działać)
wiciu
W większości współczesnych aplikacji i tak jest wykorzystana jakaś warstwa abstrakcji na thread poole poprzez jakiś framework i nie tworzysz ich ręcznie bezpośrednio w kodzie.
Charles_Ray
Nie znam niczego takiego np. w Springu, może chodziło Ci o serwery aplikacyjne. Jak używasz np Springa na Tomcacie czy Undertow, to normalnie tworzysz własna pule przez ExecutorService. Jeśli używasz np. Hystriksa to i tak należy te pule skonfigurować i monitorować.
wiciu
Np. WebFlux i Reactor ze Springa posiada tzw. Schedulery, które są abstrakcją na ThreadPoole. Podobnie rozwiązuje to biblioteka RxJava. Są też inne podobne rozwiązania. Oczywiście na samym dole są tworzone wątki najprawdopodobniej przez ExecutorService, ale nie zawsze trzeba wołać ten obiekt explicite.
Charles_Ray
No właśnie, to dalej jest jakaś pula wątków, którą musisz stworzyć - tyle, że opakowana w Scheduler :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.