25. února 2013

Jak dělají Java pohovor jinde

Nedávno jsem psal o tom, jak dělám Java pohovor já. Bylo to napsáno z pohledu toho, kdo zná kontext, ví, jak by měl vhodný kandidát vypadat a také mmj. určuje pravidla, jak bude pohovor probíhat.

Aktuálně mám několik čerstvých zkušeností z opačné strany interview, tak bych se chtěl podělit o své dojmy. Na (Java) pohovoru jsem nebyl již několik let, v podstatě od "krize", kdy jsem si testoval stav trhu :-) a musím říct, že to byla zajímavá profesní zkušenost.

Budu diskrétní, takže nebudu prozrazovat konkrétní zadání a ani nebudu jmenovat jednotlivé firmy. Pro lepší představu pouze uvedu, že ve všech případech šlo o nadnárodní korporace, kde je běžným komunikačním jazykem angličtina. Také se budu věnovat pouze technickým kolům pohovorů, tzn. že různé HR a psychologické srandičky si odpustím.

No, a protože moje paměť je děravá a výběrová, zaměřím se pouze na signifikantní rysy daného pohovoru. Taky vynechám takové ty běžné věci, jako je probírání projektů nad CV.

Co bych předeslal, že měly všechny pohovory společné:
  • nikde po mně nechtěli vidět můj kód,
  • nikde po mně dopředu nechtěli nějakou specifickou přípravu
  • a nikde po mně (naštěstí) nechtěli psaní testů.

Algoritmy na white boardu

Tohle byla taková algoritmová klasika - měl jsem (za předpokladu, že neexistují Java Collections) naimplementovat spojitý seznam. S povděkem jsem si vzpomněl na školní předmět Algoritmy a datové struktury a i po těch cca šesti letech vydoloval celkem slušnou implementaci.

Implementace probíhala na whiteboardu, doplňovaná diskuzí. Debata byla uvolněná a nebazírovalo se na termínech. Výhodou whiteboardu je, že kromě kódu se dají kreslit různé pomocné schématka apod., nad kterými se dá dále diskutovat. A je to takové agilní :-)

Závěr: tohle je celkem příjemná metoda pohovoru, která ale staví na více méně fixních a teoretických znalostech. Navíc tam není moc prostoru pro invenci. Schválně, kolikrát už jste (v Javě) implementovali nějaký základní algoritmus a kdy jste naposledy vymysleli nějakou novou metodu sortování? Nicméně, pokud člověk nepřijde nabiflovaný algoritmy, dá se touto metodou sledovat, jak uvažuje a dobírá se řešení.

Checklist technologií

"Jak dlouho máte zkušenost s J2EE?"
"8 let."
Jak dlouho máte zkušenost s JSF?"
"Rok a půl."
"Musíme to zaokrouhlit na celý roky."
"OK, tak rok."

Na začátku tohohle interview byl seznam asi patnácti technologií, kdy jsem měl říct, jak dlouhou s nima mám zkušenost. Zkušenost musela být vyjádřená v celých rocích. Pak jsme jednotlivé technologie procházeli pomocí kontrolních otázek.

Např. u Java Core to byl vztah metod equals a hashCode. U JPA tři způsoby dotazování (JPQL, Criteria API a native SQL) apod. Platné byly pouze zkušenosti z projektů. Např. to, že mám Flex certifikaci a navrhoval jsem architekturu, kde byl Flex jako frontend, nic neznamenalo (člověk by řekl, že aspoň jednooký mezi slepými králem).

Závěr: pro mne jednoznačné nejhorší zkušenost - člověk je jenom souhrnem aktuálních znalostí, vůbec se nepočítá s nějakým potenciálem, schopností řešit problémy, vymýšlet řešení apod. Navíc ten checklist mi přijde hrozně zavádějící: když jsem Spring Security použil na dvou projektech v délce cca 3 let, ale čisté práce na něm bylo maximálně 3 týdny (konfigurace plus nějakej ten custom handler) - jak dlouhou zkušenost mám s touto technologií?

Algoritmy a rozhraní

Na tomto pohovoru jsem dostal dva příklady. První se týkal "jistého" vyhledávacího algoritmu, implementovaného pomocí dvou zanořených cyklů (mmch. jediný kód, byť na papíře, který jsem na pohovorech viděl). Měl jsem určit, jestli algoritmus pracuje vždy správně, jaká je jeho složitost, jak by se dal optimalizovat, jaká bude jeho složitost po optimalizaci atd.

Druhý příklad se týkal návrhu rozhraní a ev. jeho implementace. Zadání bylo (schválně) velmi volné a strohé, aby podnítilo přemýšlení a diskuzi. Požadavek byl pro mne lehce cizokrajný a příslušná (zevrubná) diskuze mne celkem obohatila (i když výsledné řešení bylo celkem konformní).

Závěr: tohle interview se mi profesně líbilo nejvíc - šlo nejvíc do hloubky, testovalo jak znalost algoritmů, tak přemýšlení nad nejednoznačným problémem. Čili otestovalo jak základní znalosti, tak myšlenkový potenciál.

Moje otázky

Na všech pohovorech jsem se hodně ptal a strávili jsme mýma otázkama poměrně dost času. Měl jsem vždycky připravenou stejnou sadu otázek:
  • Jaká je struktura společnosti?
  • Jak velké je oddělení, kde bych pracoval?
  • Jaký je budoucí kolekiv?
  • Kdo bude můj šéf a uvidím ho na některém kole pohovoru?
  • Jak vypadá moje budoucí pracoviště?
  • Jakým způsobem jsou vedeny projekty?
  • Jaké se používají metodiky?
  • (obligátní) Jaké se používají technologie?
  • Jaké podpůrné technologie se používají (Continuous Integration, Issue Tracking, Version Control)?
  • Funguje nějaký osobní rozvoj (školení atd.)?
  • Jak budou vypadat další kola pohovoru?

Mmch. před časem psal o otázkách při pohovoru Banter.

Závěr

Moje dojmy z pohovorů jsou samozřejmě subjektivní a zpětná vazba je většinou minimální - člověk se většinou dozví, jestli byl celkově úspěšný nebo ne, ale nedozví se podrobnosti. Proto se můžu ve svém náhledu mýlit. Protože nastavení pohovoru a jeho vyhodnocení je v rukou tazatele.

Související články

13. února 2013

Vytvoření JDBC datasource na WebLogicu pomocí WLST

Dneska to bude jen taková variace na minulé téma (vytvoření JMS zdrojů pomocí WLST), aneb jak na WebLogicu vytvořit JDBC datasource pomocí skriptovacího nástroje WLST (WebLogic Scripting Tool).

Podstatné věci o WLST jsem zmínil v uvedeném postu, takže je tady už nebudu opakovat a eventuálně vás pro doplňující informace odkazuji tam.

#
# properties
#
user = 'weblogic'
password = '<password>'
server = 't3://<host>:7001'
dsName = '<datasource>'
dsPath = '/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName
clusterName = 'soa_cluster'

# connection
connect(user, password, server)

# edit mode
edit()
startEdit()

#
# delete an old JDBC resource
#
if cmo.lookupJDBCSystemResource(dsName):
    delete(dsName, 'JDBCSystemResource')

#
# create JDBC resource
#
cmo.createJDBCSystemResource(dsName)
# set datasource name
cd(dsPath)
cmo.setName(dsName)
# set JNDI name
cd(dsPath + '/JDBCDataSourceParams/' + dsName)
cmo.setJNDINames(['jdbc/' + dsName])
# set driver
cd(dsPath + '/JDBCDriverParams/' + dsName)
cmo.setDriverName('oracle.jdbc.xa.client.OracleXADataSource')
cmo.setPassword('<password>')
cmo.setUrl('jdbc:oracle:thin:@<host>:1521:<SID>')
# set username
cd(dsPath + '/JDBCDriverParams/' + dsName + '/Properties/' + dsName)
cmo.createProperty('user')
cd(dsPath + '/JDBCDriverParams/' + dsName + '/Properties/' + dsName + '/Properties/user')
cmo.setValue('<user>')
# set targets
cd('/JDBCSystemResources/' + dsName)
cmo.setTargets([getMBean('/Clusters/' + clusterName)])

# save and finish
save()
activate()
disconnect()
exit()

Související články

7. února 2013

Vytvoření WebLogic Distributed Queue pomocí WLST

Pokud nějaká aplikace používá JMS zdroje, bývají  tyto zpravidla externí. (Výjimkou je JMS broker embeddovaný uvnitř aplikace.) Tyto externí zdroje bývají často vytvořeny na aplikačním serveru, ve kterém je většinou JMS server už obsažen. Pokud naše aplikace používá např. JMS fronty, musí je "někdo" na daném JMS serveru vytvořit. Ten někdo je na vývojovém a někdy i testovacím prostředí vývojář, na dalších prostředích už to bývá administrátor.

Podle daného aplikačního serveru se JMS zdroje dají buď naklikat v nějaké administrátorské konzoli, nebo je potřeba poeditovat/vytvořit nějaké konfigurační soubory. Třetí možností je tyto  zdroje nějakým nástrojem naskriptovat. V případě aplikačního serveru WebLogic je takovým nástrojem WebLogic Scripting Tool (WLST).

Jak už jsem psal v minlém zápisku o mazání dat z MDS, WLST je v Jythonu napsaný nástroj pro správu WebLogic serveru, který funguje ve dvou režimech - offline a online. V online režimu se WLST připojuje k běžícímu WebLogicu a operuje nad stromem jeho MBeans. Pro správu JMS zdrojů je potřeba používat WLST online.

Distributed Queue

Věc, kterou jsem potřeboval vyřešit, bylo vytvoření distribuované fronty ve WebLogicovém clusteru. Cluster byl velmi jednoduchý - admin server a dva nody (managed servery). Vzhledem ke clusteru bylo potřeba vytvořit logickou frontu, která by měla stejný JNDI (jako na vývojovém prostředí s jedním nodem) a zastřešovala by fronty na jednotlivých nodech. Na WebLogicu je toto řešeno distribuovanými destinacemi (queue/topic). Pokud si to neumíte představit, distribuovaná fronta funguje v podstatě jako klasický load balancer.

Distribuovaná fronta (WebLogic Administration Console)

Členové distribuované destinace (WebLogic Administration Console)

WLST a JMS

Použití WLST je po krátké praxi poměrně intuitivní a jednoduché. Zpočátku může dělat problém se orientovat ve struktuře (stromech) MBean. V tomto může napomoci celkem slušná dokumentace: navigace MBeans, Javadoc a MBean reference. Pak už stačí jenom lehké základy Pythonu.

V následujícím skriptu je několik věcí, které můžou trochu ztížit čtení/pochopení skriptu, takže ještě kratičká legenda:
  • Target. Cílové umístění zdroje, nebo aplikace, např. server, cluster, JMS server ad. V případě deploymentu (aplikace) tím říkám, na které nody/clustery chci aplikaci nasadit.
  • SubDeployment. Mechanismus pro seskupení a umístění JMS zdrojů. V rámci subdeploymentu říkám, na které cíle (targets) chci dané zdroje nasadit. Může to být libovolná kombinace, nebo podmnožina.
  • cmo. Proměnná, která reprezentuje "aktuálně spravovaný objekt" (current management object). Je to vlastně MBeana, která má momentálně "focus". Tak, jak se prochází stromem MBean, tak se tato proměnná automaticky mění.

# properties
user = 'weblogic'
password = '<password>'
server = 't3://<host>:7001'
subDeploymentName = 'EVMJMSServers'
queuePath = 'JMSResource/SOAJMSModule/UniformDistributedQueues/'
queueName = 'EVM_DLQ'
jndiPrefix = 'jms/b2b/'
loadBalancing = 'Round-Robin'

# connection
connect(user, password, server)

# edit mode
edit()
startEdit()

# get targets
s1 = getMBean('/JMSServers/SOAJMSServer_auto_1')
s2 = getMBean('/JMSServers/SOAJMSServer_auto_2')

#
# create a SubDeployment
#
cd('/JMSSystemResources/SOAJMSModule')
# delete an old SubDeployment
if cmo.lookupSubDeployment(subDeploymentName):
    delete(subDeploymentName, 'SubDeployment')
# create a new SubDeployment
cmo.createSubDeployment(subDeploymentName)
subDeployment = cmo.lookupSubDeployment(subDeploymentName)
subDeployment.setTargets([s1, s2])

#
# create a ldistributed queue
#
resource = cmo.getJMSResource()
# delete an old queue
ref = getMBean(queuePath + queueName)
if ref != None:
    cd('JMSResource/SOAJMSModule')
    delete(queueName, 'UniformDistributedQueue')
# create a new queue
resource.createUniformDistributedQueue(queueName)
distributedQueue = resource.lookupUniformDistributedQueue(queueName)
distributedQueue.setJNDIName(jndiPrefix + queueName)
distributedQueue.setLoadBalancingPolicy(loadBalancing)
distributedQueue.setSubDeploymentName(subDeploymentName)

# save and finish
save()
activate()
disconnect()
exit()

Související články