2019. április 20., szombat

software serviceability checklist

Az utóbbi néhány évben többnyire úgy hivatkoztak rám, hogy "on site" engineer. Ez annyit jelent, hogy legalább ugyanabban az országban lakok, ahol a felhasználók többsége. Érdekes dolgokat tanultam, de nagyon ne irígyeljetek, mert néha fájt, meg nem ritkán hétvégémbe is került.


Logging

Korábban ennyire nem érdekelt, hogy mit logol a szoftver. Miután elég sok esetben kell túrkálnom az éles rendszerek logját és bosszús, türelmetlen emberek kérdéseire válaszolnom, kicsit kevésbé vagyok már liberális a logolással kapcsolatban.
  1. Például ha a felhasználók / kliens alkalmazások hülyeséget csinálnak, legyen ott a logban, hogy milyen bemenő adatokat küldött a felhasználó és hogy feküdt el a feldolgozás
  2. Nem rossz például minden a klienseknek adott hibához egy egyedi azonosítót (talán a legkézenfekvőbb egy UUID) rendelni, és azt a logba is megadni, így nem kell annyit keresgetni
  3. Nagyon szép és kedves dolog a fejlesztőktől megkönnyíteni a logok gépi feldolgozását, pl CSV formátumban elmondani a mondandónkat
  4. Azt a hülyét, aki hangosan üvölti, hogy log aggregálóra semmi szükség nincs, gyorsan kivégezni, a hullát eltüntetni.
  5. Még egy technikai apróság, ilyet sokan csinálnak:
    if(LOGGER.isEnabled(LogLevel.INFO)) {
       LOGGER.info("akármi: " + valami.getName().getFirstName())
    }

    Csodálatos, hogy megpróbálod elkerülni, hogy fölöslegesen összeállítson a gép egy stringet. Biztosan valaki észre fogja venni hogy mit megtakarított a cég az áramon. Most viszont a szoftvered a logolás szintjétől függően működik vagy nem. Elég bosszantó, ha hibakeresésnél megváltoztatod a log szintet és ettől bedől a rendszer.

Health-check (alias 'ping')

Ez egy gyakori feature a legtöbb szoftverben, általában egy egyszerű text, html vagy JSON oldal, ami felsorolja
  1. a szoftver verziószámát
  2. minden backend (adatbázis, rest service, EJB gányolmány, CORBA dinoszaurusz) elérhetőségét - illetve a hiba jellegét ha nem sikerült elérni.
  3. vagy ha ilyesmi szükséges: helyi disk space (például a lognak) vagy a szabad memória információk
Ezt sikerült idáig mindenkinek összehoznia, de mit lehet benne elszúrni:
  1. ha a ping túlságosan nehéz műveletet akar végrehajtani az adatbázison - nem csak egy select sysdate from dual hanem konkrétan táblák méretét lekérdezni: select count(*) from all_i_have_ever_done;
    Ilyen esetben ahogy nő az adatbázis, az ember többé már nem meri használni a health-check oldalt, mert esetleg az dönti be a rendszert.
  2. ha egy backend hibája miatt a ping nem képes továbbhaladni - vagy beblokkol (lásd előző pont) vagy hiba esetén a többi kapcsolatot már nem ellenőrzi. Ez félmunka.
Publikus rendszerek esetében érdemes levédeni a health-check oldalt, különben fantasztikusan hasznos információkat tud adni az illetéktelen érdeklődőknek.

Reverse Onboarding

Általában üzleti rendszereknél van egy bürokratikus procedúra, amikor egy új szoftvernek engedélyt adnak egy másik rendszer vagy infrastruktúra használatára. Ezt hívják onboarding-nak. Ilyenkor az új szoftver fejlesztőinek kell mindenfélét bemutatnia, például a tesztek eredményeit, a várható terhelést, a kapcsolattartó emailcímet, satöbbi.

Van aki furcsán néz rám, amikor megfordítom a dolgot. Ugyanezeket a dolgokat kérjük szépen mi is, feljegyezzük és bármilyen probléma esetén használni fogjuk. Volt aki azt mondta erre hogy "De hát mi vagyunk a világ legnagyobb XYZ rendszere". Klassz. Akkor ezeket már biztosan sokan kérdezték :-)

Ezek az infók nagyon hasznosak lesznek probléma esetén, ezt sajnos szó szerint érdemes a párna alatt tartani.

  1. Tervezett Outage esetén hol kapsz értesítést, mennyi idővel előre
  2. Nem tervezett kiesés esetén hol kérhetsz segítséget - és ez ne egy személy legyen lehetőleg, mert mindig az lesz az eredmény, hogy pont egy pár hónapja lepattant az ember
  3. Ha sikerül ilyesmit kicsikarni az emberekből: átlagos és maximális válaszidők, elérhetőség, satöbbi (SLA technikai részletei)

Dashboards

Nagyon hasznos, ha van valamilyen dashboard / info radiator ahol összegyüjtheti az ember akár a health-check oldalak eredményeit, vagy a log aggregáló riportjait a hibákról, teljesítmény adatokat. Reggelente ez a legizgalmasabb oldal.

JAVA: Exception handling

Ezt sajnos gyakran kell magyaráznom a kollégáknak, de nem az a baj, ha hibát adunk vissza a felhasználónak. Néha a hiba a helyes válasz. Az a baj ha egy infrastruktúra hibát figyelmen kívül hagyunk és például null-t adunk vissza helyette.
Sajnos a checked exceptions egy tragikusan rossz ötlet volt. Eggyel több ok kotlinra váltani.


Ennyi pillanatnyilag. Egy profi supportos biztosan tudna hozzábökni pár dolgot, de én még mindig főleg hegesztésből élek.

2019. január 22., kedd

Kotlin null-biztonság

A kotlin mellett még mindig a szuper-barátságos null-safety a legjobb érvem. Aki esetleg nem ismerné a kotlin nyelvet, Annak röviden:
A kotlin fordítási időben ellenőrzi a változók és értékek típusát.
Azaz mindent úgy kell deklarálnod (a kotlin erősen típusos nyelv) hogy lehet-e null vagy sem.

Például:

var neverNull : String = "bla bla bla"
var maybeNull : String? = null // hoppá alapból pont null

Lehet próbálni a széllel szembe pisilni:

var amISmarterThanTheCompiler : String = null // compiler error

A compiler pedig kikényszeríti a null értékek tiszteletét, azaz mindig kell valami null-ellenőrzést beiktatni. Lehet old-school if(blah!=null) a kotlin elvis-operátorával, vagy a null-safe navigációval, pl

person.taxId?.startsWith("1234") ?: false

A legeslegesleg szeretetre-méltóbb dolog az, hogy ezt adatreprezentációban, a kotlin data osztályokban.

data class Person (
  val firstName : String,
  val lastName: String, 
  val taxId : String?
)

Millió órányi NullPointerException-kergetés után könnyes szemekkel hüppögve kérdezhetjük:

Akkor most meg vagyunk mentve?

És a korrekt válasz: lófaszt. Illetve már majdnem, csak még nem.

Persze azzal kezdtem, hogy fordítási időben ellenőrzi a null-biztonságot. Ebből következően bármi ami nem kotlinból jön, hanem java, groovy, akármi, az megsértheti ezt a szabályt és egy ideig ez ki sem derül.


1. számú gyanúsított: Serialization

A legnyilvánvalóbb tréfát serializationnel lehet elkövetni.

data class Person (
  val firstName : String,
  val lastName: String, 
  @Transient val name = "$firstName $lastname"
)

Tessék kérem serializálni, deserializálni, majd

person.name.startsWith("Meglepi") // bang

2. számú gyanúsított: Jackson 

A jackson egyébként az evidens esetekben kedvesen szól, hogy nem lehet null valami...

data class Person (
  val firstName : String,
  val lastName: String
)

objectMapper.readValue(""" 
 {
   "firstName":"Kakukk",
   "lastName": null
 }
""", Person::class.java)

És itt a jackson felháborodik, amitől mindenki megnyugszik, hogy tessék, biztonságban vagyunk. Igen, majdnem...

data class Person (
  val firstName : String,
  val lastName: String,
  val titles : List
)

val person = objectMapper.readValue(""" 
 {
   "firstName":"Eugene",
   "lastName": "Cuckoo",
   "titles" : ["dr",null,"sir"]
 }
""", Person::class.java)         // nahát, működött...
person.titles.forEach(::println) // bang

Erre többször nyitottak bugot a jackson-kotlin modul bugtrackerében, összegyűlt tekintélyes mennyiségű szavazat. Minden alkalommal a fejlesztő pár hónap után lezárta ugyanazzal a kommenttel: wont fix. A jackson egy java komponens, nem érdekli a kotlin nullsafety.

Egyébként egyre népszerűbbek az egyéb JSON libraryk, mint a moshi... meglátjuk, van időm. Inkáb egy jól ismert lókötő, mint egy civilizált idegen, nem?

3. számú gyanúsított: mindenki

De legyen elég mára ennyi a paranoiából, mert végülis csak annyit akartam mondani, hogy
  1. Semmi baj, túl lehet élni, csak figyelni kell rá.
  2. Mindent addig kell kínozni, amig a kívánt vallomást meg nem teszi.
  3. Oké elég, takarodó