First8 Java Consultancy https://technology.first8.nl First8 is gespecialiseerd in het pragmatisch ontwikkelen van bedrijfskritische Java toepassingen. Tue, 15 May 2018 22:42:02 +0000 nl hourly 1 https://wordpress.org/?v=4.8.6 Creative Ways of Finding a Birthday: When Are We 250 Years? https://technology.first8.nl/creative-ways-of-finding-a-birthday-when-are-we-250-years/ Tue, 15 May 2018 22:42:02 +0000 https://technology.first8.nl/?p=6165 Today is my birthday. Yes, it is actually my birthday: May the 15th. So, I thought it would be fun to write about a little algorithmic puzzle I’ve been pondering about. You see, each year we grow older; as a person, but also collectively as an organisation, a group, a community. That’s a lot of combined knowledge I reckon. 🙂 … Lees verder Creative Ways of Finding a Birthday: When Are We 250 Years?

Het bericht Creative Ways of Finding a Birthday: When Are We 250 Years? verscheen eerst op First8 Java Consultancy.

]]>
Today is my birthday.

Yes, it is actually my birthday: May the 15th. So, I thought it would be fun to write about a little algorithmic puzzle I’ve been pondering about. You see, each year we grow older; as a person, but also collectively as an organisation, a group, a community. That’s a lot of combined knowledge I reckon. 🙂

Take, for instance, my immediate family. My parents Christiaan and Marijke, my little sister Petra and dear girlfriend Jolien. All together, we have a combined age of 234 years! Wow, isn’t that something?

I wondered: at who’s birthday have we reached a grand total of 250 years combined knowledge?

At first I actually just hoped to get a date and a person for conversation making purposes, but pretty soon it became a bit of a personal challenge. I mean: I’m a developer and that shouldn’t be hard to program right?

But: algorithms have never been my strong suit, and I knew that any 1st solution — which would produce an answer — had to be followed by at least a 2nd algorithm taking a different approach, for it actually to be a challenge. There’s never just one way of tackling a puzzle and by pushing myself to always come up with at least 2 alternatives to any problem, I get better at what I do as a software developer.

(Also publishing it on a blog like this and getting feedback is really enlightening!)

So before continuing to read on: try to solve the question for yourself first.

Given the known birthdays of e.g. 5 members of your family, at whose birthday (when and who) for the first time the entire family becomes e.g. 250 years old.

(The number 250 doesn’t really mean anything. ’t Was just a nice, round number we still had lying in front of us, nothing special.)

I have to admit: at first I tried to do this in Microsoft Excel. Unfortunately, after trying to be smart with formulas using other formulas I clearly went insane pretty soon, since I couldn’t actually code my way out of it.

To the code it is….!

Meet the Family’s helper classes & methods

So the 5 members of my family can be modelled in Java with a name, a String and their birthday, using a LocalDate, like this:

Family family = new Family(Arrays.asList(
  new Person("Jolien",
    LocalDate.of(1984, Month.OCTOBER, 15)),
  new Person("Petra",
    LocalDate.of(1983, Month.DECEMBER, 7)),
  new Person("Ted",
    LocalDate.of(1981, Month.MAY, 15)),
  new Person("Christiaan",
    LocalDate.of(1953, Month.JUNE, 10)),
  new Person("Marijke",
    LocalDate.of(1951, Month.JULY, 24))
));

The OO (Object Orientation)-part of my brain always lights up pretty fast, and devising a Person and a Family gave me some room to put some helper-methods in there which I expected I would need pretty soon…;-)

class Family {
  private List<Person> persons;

  Family(List<Person> persons) {
    this.persons = persons;
  }

  List<Person> getPersons() {
    return persons;
  }

  void displayBirthDate(LocalDate date) {
    persons
      .stream()
      .filter(p  -> p.isBirthDay(date))
      .findFirst()
      .ifPresent(p -> System.out.printf(
        "Reaching %s when %s turns %s at %s\n",
        calcTotalAge(date),
        p.name,
        p.calcAge(date),
        date)
      );
  }
}

You see I also created a displayBirthDate which I could feed a possibly found birth date, which is the actual challenge, and find and print the one who’s birthday it is on that day.

And for completeness, here’s the Person class.

class Person {
  String name;
  LocalDate birthDate;

  Person(String name, LocalDate birthDate) {
    this.name = name;
    this.birthDate = birthDate;
  }

  boolean isBirthDay(LocalDate date) {
    return MonthDay.from(date).equals(MonthDay.of(
      birthDate.getMonth(), birthDate.getDayOfMonth()));
  }

  @Override
  public String toString() {
    return String.format(
      "Person(name: %s, birthDate: %s)", name, birthDate
    );
  }
}

1st algorithm

My very, very first instinct, after having posed the question to myself — “at what birthday the entire family becomes 250 years of age?” — said: brute force.

I thought I needed to be able to calculate the total age of the family at any given time. This requires also being able to calculate the age of a person at any given time.

I introduced 2 helper methods for this: Family#calcTotalAge which needs a new Person#calcAge.

class Family {
  private List<Person> persons;

  Family(List<Person> persons) {
    this.persons = persons;
  }

  List<Person> getPersons() {
    return persons;
  }

  int calcTotalAge(LocalDate date) {
    return persons
      .stream()
      .mapToInt(p -> p.calcAge(date))
      .sum();
  }

  void displayBirthDate(LocalDate date) {
    persons
      .stream()
      .filter(p  -> p.isBirthDay(date))
      .findFirst()
      .ifPresent(p -> System.out.printf(
        "Reaching %s when %s turns %s at %s\n",
        calcTotalAge(date),
        p.name,
        p.calcAge(date),
        date)
      );
  }
}

class Person {
  String name;
  LocalDate birthDate;

  public Person(String name, LocalDate birthDate) {
    this.name = name;
    this.birthDate = birthDate;
  }

  int calcAge(LocalDate date) {
    return Period.between(this.birthDate, date).getYears();
  }

  boolean isBirthDay(LocalDate date) {
    return MonthDay.from(date).equals(MonthDay.of(
      birthDate.getMonth(), birthDate.getDayOfMonth()));
  }

  @Override
  public String toString() {
    return String.format(
      "Person(name: %s, birthDate: %s)", name, birthDate
    );
  }
}

And finally the code which does the work of finding me a birth date:

void doBruteForce() {

  LocalDate foundLuckyDate;
  LocalDate futureDate = now;
  while (true) {
    if (family.calcTotalAge(futureDate) >= 250) {
      foundLuckyDate = futureDate;
      break;
    }
    futureDate = futureDate.plusDays(1);
  }

  family.displayBirthDate(foundLuckyDate);
}

The brute force approach by Just. Looping. Days.

Start “now”, increase by one day into the future and calculate the total age of the family every time. Repeat this until we’re 250 years old, break from the loop: we’ve found our lucky birthday.

Yep, this assumes we’re not 250 years yet. If we are, the “>=” (greater than or equal) will save us from an infinite loop 🙂

The application with our main() method we’re about to run is:

public class WhenAreWe250Years {

  private final Family family;
  private final LocalDate now;

  public WhenAreWe250Years(Family family) {
    this.family = family;
    this.now = LocalDate.now();
    family.getPersons().stream().forEach(System.out::println);
    System.out.println(
      String.format(
        "Total age now at %s is %s",
        now, family.calcTotalAge(now))
    );
  }

  public static void main(String... args) {

    Family family = new Family(Arrays.asList(
      new Person("Jolien",
        LocalDate.of(1984, Month.OCTOBER, 15)),
      new Person("Petra",
        LocalDate.of(1983, Month.DECEMBER, 7)),
      new Person("Ted",
        LocalDate.of(1981, Month.MAY, 15)),
      new Person("Christiaan",
        LocalDate.of(1953, Month.JUNE, 10)),
      new Person("Marijke",
        LocalDate.of(1951, Month.JULY, 24))
    ));

    WhenAreWe250Years app = new WhenAreWe250Years(family);
    System.out.println("Brute:");
    app.doBruteForce();
  }

  void doBruteForce() {

    LocalDate foundLuckyDate;
    LocalDate futureDate = now;
    while (true) {
      if (family.calcTotalAge(futureDate) >= 250) {
        foundLuckyDate = futureDate;
        break;
      }
      futureDate = futureDate.plusDays(1);
    }

    family.displayBirthDate(foundLuckyDate);
  }

  // Person, Family, etc
}

After running it, the output to the console looks like:

Person(name: Jolien, birthDate: 1984-10-15)
Person(name: Petra, birthDate: 1983-12-07)
Person(name: Ted, birthDate: 1981-05-15)
Person(name: Christiaan, birthDate: 1953-06-10)
Person(name: Marijke, birthDate: 1951-07-24)
Total age now at 2018-05-15 is 234
Brute:
Reaching 250 when Christiaan turns 68 at 2021-06-10

Woohoo, above code found 2021-06-10.

It doesn’t know which person, but that’s ok: another piece of the code looked that up.

The result is found pretty fast (which is no surprise with this minimalistic amount of iterations) but we had to test 1123 days — the period between now and found date — before it met our condition. It’s not a benchmarking exercise, but having this amount of inefficiency left me with a bitter aftertaste.

I could not just leave it at this, and as I promised myself already, I forced myself to think about a 2nd solution.

Another attempt additionally has to have only one constraint (else I can’t sleep tonight): it has to be smarter.

Version 1b

I came up with refactored version using Streams…

Stream.iterate(now, l -> l.plusDays(1))
  .filter(futureDate -> {
    return family.calcTotalAge(futureDate) >= 250;
  })
  .findFirst()
  .orElseThrow(RuntimeException::new);

…but that could hardly qualify as a significant other approach. Even IntelliJ can suggest replacing a while loop using Stream API — and vice versa 🙂

So before continuing to read on: answer another question for yourself first.

Did you also thought up initially something along the lines of brute force checking things until you found the answer? If so, what would be another, possibly smarter, approach?



The 2nd attempt took me hours.

I know a bit of the awesome Java 8 Date Time API nowadays and fiddling around with classes such as Period and stuff made me believe the answer would be somewhere in those date/time classes.

Well, I just couldn’t find it.

At breaking-point I thought:

  • “Isn’t the whole calculation not as simple as finding x in a simple math question e.g. Given: 12/x = 4. What is x?. Boom, just a few expressions using known periods between something and a date x somewhere in the future?”

Then I thought:

  • “We have some birth days ahead of us. The lucky birth date is a certain amount of years from now, which is the nth birth day that year.”

The I started something which has this as the end result:

void doSmarter() {

  // We have some birth days ahead of us :-)
  LocalDate firstDayOfYear = now.with(TemporalAdjusters.firstDayOfYear());
  int yearsToCover = 250 - family.calcTotalAge(firstDayOfYear);
  int yearlyAmountOfBirthDays = family.getPersons().size();

  // The lucky birth date...
  // ...is a certain amount of years from now
  int nthYearFromNow = yearsToCover / yearlyAmountOfBirthDays;
  // ...which is the nth birth day that year
  int nthBirthDayThatYear = yearsToCover % yearlyAmountOfBirthDays;

  // That's it! Family members already ordered by day of birth
  LocalDate luckyDate = family.getPersons()
    // ...so take nth person from the (zero-based) list
    .get(nthBirthDayThatYear - 1)
    // and calculate his/her birth date in that year
    .calcNextBirthDate(now, nthYearFromNow);

  family.displayBirthDate(luckyDate);
}

Running it after the initial version, the 2nd version yields the same results:

Brute:
Reaching 250 when Christiaan turns 68 at 2021-06-10
Smarter:
Reaching 250 when Christiaan turns 68 at 2021-06-10

Woohoo!

I had to go a few times back and forth through the code to get it right — so don’t think this happened in the first pass. It’s again about trying to find a date in the future, but now by trying to reason about what I want to achieve. See the comments in the source code.

First I had the impression that my 2nd version should have made clever use of whatever the Date/Time API of Java had to offer me, but it seemed I was just not creative enough…and came up with some old-school math operations. Man!

Check the variables, as if they were logged at the end of the method, may be it makes more sense to follow what happens, just for background:

now = 2018-05-15
firstDayOfYear = 2018-01-01
yearsToCover = 17
yearlyAmountOfBirthDays = 5
nthYearFromNow = 3
nthBirthDayThatYear = 2
luckyDate = 2021-06-10

The rationale: still 3 years (with all 5 birth days each) had to happen and then only 2 more to “span” the 17 years of difference between total age now (234) and our target age of 250 years.

To find the 2nd birth day in a year, I choose to alter the Family constructor and ordering set family members then and there by their day of birth throughout the year.

The adjusted constructor which makes earlier logic work:

Family(List<Person> persons) {
  this.persons = persons.stream()
    .sorted(Comparator.comparing(p -> p.birthDate.getDayOfYear()))
    .collect(Collectors.toList());
}

Getting creative!

You can forget the specifics of both solutions pretty fast since those are not important. You might even argue about the aesthetics of the code or not having proper error handling. Yes, the code might fail when ran in, oh say, 2021.

The takeaway for myself is mainly the following: there’s not one solution to a problem and the hard part is, after the initial stab at it, getting creative and finding a 2nd or 3rd alternative. Yes, it will take hours to come up with new alternatives, but what’s the harm in asking a colleague to do the same and cross-referencing your work?

By first doing this for yourself a few times, you’ll notice some juices start to flow and you’ll end up sometimes in a completely different place than where you hoped to end up 🙂

I at least got confirmation that I definitely need to do more algorithmic puzzles every now and then, so even those “math parts” of my brain stay in shape.

Now, who of the readers can come up with a 3rd alternative?

  • Excel is accepted too 🙂

Het bericht Creative Ways of Finding a Birthday: When Are We 250 Years? verscheen eerst op First8 Java Consultancy.

]]>
Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 2) https://technology.first8.nl/wachtwoorden-3-mythes-4-fouten-en-5-tips-voor-ontwikkelaars-deel-2/ Fri, 04 May 2018 12:35:45 +0000 https://technology.first8.nl/?p=6107 In de vorige blogs gaf ik hier al tips voor gebruikers. De mythes en fouten voor ontwikkelaars kun je hier vinden. In dat deel heb ik overigens stiekem al enkele tips gegeven. Aan te raden is een goede combinatie van encoding, encryptie, hashing met salt & pepper en het gebruik van cpu en memory hardened algoritmes, zoals bcrypt of scrypt. Daarnaast … Lees verder Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 2)

Het bericht Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 2) verscheen eerst op First8 Java Consultancy.

]]>
In de vorige blogs gaf ik hier al tips voor gebruikers. De mythes en fouten voor ontwikkelaars kun je hier vinden. In dat deel heb ik overigens stiekem al enkele tips gegeven. Aan te raden is een goede combinatie van encoding, encryptie, hashing met salt & pepper en het gebruik van cpu en memory hardened algoritmes, zoals bcrypt of scrypt. Daarnaast hintte ik al op het gebruik van bewezen frameworks zoals Spring Security.

Als Senior Java Developer bij First8 houd ik me steeds meer bezig met security en privacy. Deze blog-serie is ontstaan uit de vraag naar praktische tips voor gebruikers en ontwikkelaars om eigen en andermans accounts veiliger te maken. Door deze kennis bij mezelf en mijn vakgenoten te vergroten, hoop ik de wereld veiliger te maken.

 

Zoekmachine

Inmiddels is er sinds het vorige artikel heel wat gebeurd. Zo kwam Facebook uitgebreid in het nieuws door het Cambridge Analytica schandaal. Verder kwamen er verschillende zoekmachines voor wachtwoorden online. De ethische variant Gotcha.pw van Hacker d0gberry laat alleen een gedeelte van het mail-adres en uitsluitend de eerste tekens van het wachtwoord zien. Genoeg in ieder geval om te verifiëren of je in actie moet komen. En veel te weinig om er misbruik van te maken. Alle nieuwsmedia stonden op hun achterste benen: we moesten voordat deze zoekmachine online kwam onze wachtwoorden resetten. Niets is minder waar: de gegevens die d0gberry doorzoekbaar zou maken, waren zijn al jaren op internet ongecensureerd beschikbaar. Je loopt dus al een tijdje gevaar, mochten je gegevens erin staan. De hele hype rondom deze site zorgt er wel weer voor dat mensen met hun neus op de feiten worden gedrukt: het wachtwoord-probleem is serieus en gebruikers, maar zeker ook ontwikkelaars hebben een verantwoordelijkheid om er goed mee om te gaan.

In deze blog geef ik dan ook een aantal tips of best-practices voor account management en omgaan met wachtwoorden in het bijzonder, gericht op jou als ontwikkelaar. Daarbij is het belangrijkste om je gebruiker te helpen verstandige keuzes te maken. Beperkingen of verplichtingen bij de keuze van een wachtwoord zoals complexiteits-regels en periodiek veranderen, leiden vaak tot frustratie. Een wachtwoord-sterkte meter, zoals je die vaak ziet helpt wel enigszins. Deze hebben echter vaak een beperking, waardoor de bekende P@ssw0rd! als vrij sterk uit de bus komt. Hoe dat te verhelpen is, zal ik verderop in dit artikel vertellen. 

Tips

Wachtwoord reset

De meeste mensen kennen de website HaveIBeenPwned inmiddels. Eigenaar Troy Hunt houdt je met deze site op de hoogte van data-lekken en dan met name login-credentials. Daarnaast houdt hij regelmatig interessante talks over security en de lekken die hij via zijn site inzichtelijk maakt. Daarin vertelt hij ook, dat hij vaak verzoekjes krijgt van ongeruste vrouwen die willen weten of hun partner een account heeft op bepaalde dubieuze sites. Dit kunnen ze in veel gevallen echter zelf achterhalen, zonder enige technische kennis. Een uitgelekte lijst met accounts is vaak niet eens nodig. De wachtwoord-reset functie is vaak genoeg om met het mail-adres van je partner te controleren of hij of zij er een account heeft. Het antwoord van die functie kan namelijk verschillen voor een bestaand account ten opzichte van een niet-bestaand account. Bekijk het onderstaande resultaat maar eens. NB: alhoewel dit probleem al lang geleden bij onderstaande site is aangekaart, bestaat het nog steeds.

Melding Ongeldig mailadres  
 De melding met een ongeldig mail-adres is heel anders…  … dan de melding met een bekend (geregistreerd) mail-adres

 

Een wachtwoord-reset functie is echter onmisbaar bij websites met account-registratie. Het goed implementeren ervan is nog een flinke uitdaging. Zorg er voor, dat het antwoord op eenwachtwoord-reset gelijk is, ongeacht of het mail-adres bij een account hoort of niet. Bijvoorbeeld Slack heeft dit goed voor elkaar:

 Melding met een ongeldig mail-adres is identiek…   … dan de melding met een bekend (geregistreerd) mail-adres

 

Let op: voer dit ook bij het registreren van accounts door. Geef dus bij registratie geen melding dat er al een account bestaat bij een bepaald e-mail adres. In plaats daarvan kun je het betreffende mail-adres een waarschuwing sturen, dat iemand (met vermelding van IP-adres, datum en tijd, browser-gegevens en dergelijke) een nieuw account probeerde te registreren. Verder zou je kunnen letten op de response-tijden voor beide scenario’s. Zorg ervoor dat deze ook identiek zijn, ongeacht of een account bestaat of niet. Zo zorg je ervoor dat ook daarmee niet achterhaald kan worden of een mail-adres geregistreerd is of niet.

All characters are equal

Heb je de blog voor gebruikers gelezen? Dan herken je dit wachtwoord ook nog wel. Dit is de songtext van “Let it go” uit de film Frozen, uitgeschreven als wachtwoord met Emoji’s. Ja als wachtwoord, en dit zijn allemaal geldige Unicode karakters. Zorg ervoor dat je deze netjes kunt inlezen bij wachtwoord invoer, wachtwoord reset en natuurlijk het inlog-scherm. Maar denk ook aan encoden en decoden als het wachtwoord over de lijn gaat. Zo voorkom je dat je gebruikers het wel kunnen instellen als wachtwoord, maar er niet daadwerkelijk mee kunnen inloggen. Controleer of er geen systemen crashen door het gebruik van speciale tekens. Het is gerechtvaardigd om control– en format– karakters uit te sluiten in een wachtwoord. De rest zou je gewoon kunnen verwerken.

The ❄️ 🌟 🔦 ⚪ on the mountain 🌙 🌠. 🙅🏻 a👣 to 🐝 👀. A 🏰 of 😢, and it 👀 like☝️ the 👑. The 💨 is 🐺 like this 🌀 ❄️ ☔️ 🏠. 🙅🏻 keep it in, ☁️ 💡 ☝️ tried.

Common passwords

In een lijst resultaten komt de hash voor "P@ssw0rd" meer dan 47000 keer voor

Met de eedergenoemde zoekmachine voor wachtwoorden (gedeeltelijk) is eindelijk heel Nederland wakkergeschud: meer dan een miljard e-mail en wachtwoord combinaties zijn eenvoudig en snel doorzoekbaar. Ze lagen echter al jaren op straat. Daarom heeft Troy HaveIbeenpwned Hunt er een extra service bij gebouwd. Deze kan gebruikt worden om ge-Pwnde wachtwoorden te controleren. Je kunt er bovendien ook SHA-1 hashed wachtwoorden in testen. En sinds V2 van PwnedPasswords kun je zelfs volstaan met alleen de eerste 5 tekens van de SHA-1 hash. De service geeft dan een lijst van alle hashes die beginnen met deze 5 tekens. Je vraagt dus niet meer het bestaan van een hash van een compleet wachtwoord, maar een deel van de hash. Hiermee kun je in de kleine resultaat-set zoeken of de complete hash voorkomt en zo ja, hoe vaak deze in gelekte credentials voorkomen. De samenwerking van Troy Hunt met wachtwoord-manager 1Password geeft gebruikers nu al de mogelijkheid om in de wachtwoord-manager op een veilige manier te controleren welke wachtwoorden aan vervanging toe zijn. En jij kunt dit ook voor jouw gebruikers doen met deze eenvoudige stappen:

  1. Hash een ingevoerd wachtwoord van je gebruiker met SHA-1. Dit kun je doen bij het aanmaken van het account, het veranderen of resetten van het wachtwoord, maar ook als de gebruiker inlogt.
  2. Doe een GET-request op de Pwned Passwords API met de eerste 5 karakters van de hash: https://api.pwnedpasswords.com/range/<first5chars>
  3. Vergelijk de rest van de hash (zonder de eerste 5 karakters) met de lijst in de API response
  4. Komt de hash voor, dan is het wachtwoord ge-Pwned. Geef dit aan bij de gebruiker en adviseer deze om een ander wachtwoord te kiezen.

E-mail adres

Vraag je bij het registratie proces naar een mail-adres? Sta dan het +-teken toe. Hieronder leg ik uit waarom. 

Ken je de Gmail + hack? Stuur eens een mail naar je bestaande Gmail account, met direct voor het @-teken een +-teken gevolgd door een willekeurige string. Je zult de mail netjes ontvangen. Je ziet echter in het mail-adres ook de extra toevoeging. Gebruik dit bij het aanmaken van een account, bijvoorbeeld bij Ebay. Je gebruikt hiervoor de toevoeging <mijn-gmail-account>+ebay@gmail.com. Nu krijg je alle mailings van Ebay op dat herkenbare adres. Waarom is dit nuttig?

  • Je kunt nu eenvoudig filters aanmaken die alle mail naar <mijn-gmail-account>+ebay@gmail.com labelen met een Ebay-label. Ja, dit kan ook met mail van *@ebay.com, maar je zult zien dat er ook andere mail-extensies gebruikt worden. Bovendien:
  • Mocht je ooit spam krijgen op adres <mijn-gmail-account>+ebay@gmail.com dan weet je dat er iets mis is gegaan. Ebay heeft dan een hack en/of datalek, of ze sturen zelf spam.
  • Zou je ooit in een Password-list komen met specifiek dit mail-adres, dan gaat automatische login-checks met die combinatie (geldig account van Ebay) niet ergens anders werken, mocht je het wachtwoord van Ebay hergebruikt hebben (wat je natuurlijk nooit doet 😉 ). Je account bij LinkedIn is namelijk <mijn-gmail-account>+linkedin@gmail.com

Natuurlijk is dit laatste punt niet echt secure. Een beetje cybercrimineel kan deze patronen wel herkennen en de +-toevoeging er afhalen, dan wel aanpassen naar gelang de service waarop hij de gelekte credentials wil testen. Dit kost echter flink veel extra werk en vooralsnog zal dit niet snel geautomatiseerd worden. De beste beveiliging is natuurlijk nog altijd unieke wachtwoorden. En de +-truc werkt helaas niet overal. Daar komt onze verantwoordelijkheid als ontwikkelaars kijken. Zorg ervoor dat ook het +-teken ingevoerd kan worden in e-mailadressen bij registratie en wachtwoord reset.

Account lockout

Als een gebruiker inlogt, lukt dit meestal in één tot drie pogingen. Als het niet lukt, kun je de gebruiker doorverwijzen naar de wachtwoord-reset. Maar wat doe je in de tussentijd met de login-functie? Blokkeer je deze meteen na drie pogingen? Dat is meteen een vrij forse maar doeltreffende maatregel. Je kunt echter een gebruiksvriendelijke en toch praktisch even doeltreffende maatregel toepassen. Zorg ervoor dat een gebruiker na een aantal pogingen even moet wachten, voordat hij weer opnieuw kan proberen. Bijvoorbeeld eerst 5 seconden wachten, daarna 10 seconden en telkens iets langer. Dit zorgt ervoor dat een brute-force aanval onhandig veel tijd gaat kosten en daarmee praktisch onuitvoerbaar is.

Effectief schakel je de account slechts tijdelijk uit. In eerste instantie voor enkele seconden tot misschien minuten. Uiteindelijk kun je ervoor kiezen de account voor bijvoorbeeld een dag uit te schakelen. Zorg er daarbij voor dat de gebruiker via het geregistreerde e-mail adres op de hoogte wordt gesteld van de mislukte inlog-pogingen. Dit kan namelijk wijzen op misbruik of hack-pogingen. Vermeld daarbij ook weer IP-adres, datum, tijd en andere gegevens die kunnen helpen bij het opsporen van de dader.

HTTPS everywhere

Uiteraard laadt je het login-formulier en de login-submit alleen over https. Maar doe je dat ook met alle andere resources op je site? Stel, je laadt de login-pagina over https, maar enkele andere resources (wat plaatjes, een stukje javascript) over http. In browser-termen is dit “mixed-mode”. In dat geval kan de gebruiker er niet op vertrouwen dat die javascript ook echt van jou afkomt en tussentijds niet is gemanipuleerd. Bij een man-in-the-middle aanval zou de javascript uitgebreid kunnen worden met code die de gebruiker’s cookies doorstuurt, login-credentials steelt of geld-transacties doorsluist naar een bankrekening in Rusland. Hier zie je een voorbeeld van een Social Security Administration site, waar deze fout kan worden misbruikt met uitleg hoe een hacker deze aanval kan opzetten.

Specifiek om deze reden gaan browsers steeds strenger om met mixed content. Vanaf Chrome 68 en Firefox 51 worden http websites bovendien als “Not secure” gelabeld. Voordelen van https zijn niet alleen security, maar ook snelheid, privacy en zelfs hogere score in Google resultaten. Of het moeilijk is of kost het geld om https te ondersteunen? Nee, het is eenvoudig te automatiseren en hoeft bovendien niks te kosten. Vele redenen dus om https te ondersteunen en geen enkele reden om het te laten.

Stay safe

Voor zover de blog-serie over wachtwoorden. Hopelijk heb ik je met de tips in deze serie op weg kunnen helpen naar een veiliger internet-gebruik voor jezelf en de gebruikers van je applicaties. De ontwikkelingen op security gebied gaan de laatste maanden razendsnel. Data-lekken zijn aan de orde van de dag. Met de nieuwe GDPR / AVG regels die over een maand ingaan, is de noodzaak voor veilige systemen groter dan ooit. En dat merken wij bij First8 ook. Zowel bestaande klanten als OpenHealthHub als contacten in het onderwijs en concullega’s schakelen ons in om hen te helpen bij security en privacy vraagstukken. Voor vragen kun je contact opnemen via onze vestiging in Nijmegen of stel je vraag aan mij direct via Twitter of LinkedIn.

Het bericht Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 2) verscheen eerst op First8 Java Consultancy.

]]>
Kubernetes & Logging https://technology.first8.nl/kubernetes-logging/ Wed, 04 Apr 2018 19:56:23 +0000 https://technology.first8.nl/?p=6131 Kubernetes & Logging When you are running services in a Kubernetes cluster they are probably writing log statements that contain all sorts of useful information you need to have look at now and then. Being the good developer you behaved and made sure all logging statements are written to the console. This gives you the possibility to use kubectl logs … Lees verder Kubernetes & Logging

Het bericht Kubernetes & Logging verscheen eerst op First8 Java Consultancy.

]]>
Kubernetes & Logging

When you are running services in a Kubernetes cluster they are probably writing log statements that contain all sorts of useful information you need to have look at now and then. Being the good developer you behaved and made sure all logging statements are written to the console. This gives you the possibility to use kubectl logs -f <pod-name> -c <container> to tail the logs of a specific pod and container. More that enough when you are developing the services. Not so useful once you get to production. A more robust logging solution is needed.

Elasticserach, Fluentd, Kibana

The combination of these three open source projects keeps popping up more and more when it comes to centralized log collection and analysis. Elasticsearch is an open source search engine known for its ease of use. Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. Kibana is an open source Web UI that makes Elasticsearch user friendly for marketers, engineers and data scientists alike. By combining these three tools EFK (Elasticsearch + Fluentd + Kibana) we get a scalable, flexible, easy to use log collection and analytics pipeline.

Collecting Logs

When gathering the logs of a Kubernetes cluster there are two types of logs you want to collect. On one side we have the system logs of the cluster itself and on the other side we have the container logs. Before Fluentd will start collecting the logs we need to tell it where to find the logs by updating the fluent.conf file.

System Logs

Kubernetes components not running in a container write log information to files on the host system. They can mostly be found in the /var/log directory. To mark a host system log file for collection you simply add a <source> section to the configuration file for each file you want to collect. The <source> section for kubelet would look something like this.

<source>
  @id kubelet.log
  @type tail
  format multiline
  multiline_flush_interval 5s
  format_firstline /^\w\d{4}/
  format1 /^(?<severity>\w)(?<time>\d{4} [^\s]*)\s+(?<pid>\d+)\s+(?<source>[^ \]]+)\] (?<message>.*)/
  time_format %m%d %H:%M:%S.%N
  path /var/log/kubelet.log
  pos_file /var/log/es-kubelet.log.pos
  tag kubelet
</source>

Container Logs

Containers by default log there stdout en stderr to a file on the host file system. This is taken care of by the docker daemon. The files are located in /var/lib/docker/containers/. Each container has its own directory, where the directory name is the container id and the logs file looks like <container-id>=json.log. For example:

/var/lib/docker/containers/82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f/82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f.log-json.log

To have Fluentd collect the container logs we can add a <source> section like this:

<source>
  @id fluentd-containers.log
  @type tail
  path /var/lib/docker/containers/*/*.log
  pos_file /var/log/fluentd-containers.log.pos
  time_format %Y-%m-%dT%H:%M:%S.%NZ
  tag docker.*
  format json
  read_from_head true
</source>

This is pretty neat and gives us all containers, but since we are running Kubernetes we can do better. The Kubernetes kubelet makes a symbolic link to this file on the host machine in the /var/log/containers directory which includes the pod name and the Kubernetes container name:

sample-service-6b6f59f5cf-4v47j_default_sample-service-82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f.log -> /var/lib/docker/containers/82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f/82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f.log-json.log

The filename has meta data we can use in combination with the Fluentd Kubernetes Metadata plugin to add meta data to our log events. To achieve this we have to change the container <source> section to:

<source>
  @id fluentd-containers.log
  @type tail
  path /var/log/containers/*.log
  pos_file /var/log/fluentd-containers.log.pos
  time_format %Y-%m-%dT%H:%M:%S.%NZ
  tag kubernetes.*
  format json
  read_from_head true
</source>

This source will product log event tagged:

var.log.containers.sample-service-6b6f59f5cf-4v47j_default_sample-service-82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f.log

If we then apply the Fluentd Kubernetes Metadata filter by adding the following to the Fluentd config:

<filter kubernetes.**>
    @type kubernetes_metadata
</filter>

We get a log event with Kubernetes metadata embedded:

{
    "log":"2018-04-04 13:21:33.135  INFO [sample-service,5809caff2c4c218c,1da1ed2208d93495,false] 11 --- [ctor-http-nio-2] n.f.demo.sampleservice.SampleController  : Calling sample service.",
    "stream":"stdout",
    "time":"2018-04-04T13:21:33.137746827Z",
    "docker": {
        "container_id": "82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f"
    },
    "kubernetes": {
        "namespace_name": "default",
        "namespace_id: "724fc802-d4d6-4276-9aca-6f733c85a387",
        "pod_name": "sample-service-6b6f59f5cf-4v47j",
        "pod_id": "498a6ed4-3964-4579-b65d-52d0d9c82772",
        "container_name": "sample-service"
        "namespace_annotations": {
            "sample-service/release": "spring-2018"
        },
        "namespace_labels": {
            "product_version": "0.0.1"
        },
        "labels": {
           "fluentd-log-format": "spring-boot",
            "service": "sample-service"
        }
    }    
}

So far so good. The Kubernetes meta data plugin added meta data for our container. The only thing missing is proper parsing of the log attribute of the event. The sample service is a Spring Boot application using Spring Cloud Sleuth for tracing and it outputs log information using a very specific format.

<timestamp> <level> [<service>,<trace-id>,<span-id>,<exportable>] <pid> --- [<thread>] <source>: <message>

Before we write our log event to Elasticsearch we would like to parse this line to extract the different fields. As we are reading a lot of log files not every event originates from a Spring Boot application. We only want to parse the log attribute when the event is generated by a Spring Boot application. We can achieve this by using the rewrite tag filter plugin to mark events as spring-boot parsable.

<match kubernetes.**>
  @type rewrite_tag_filter
  <rule>
    key $.kubernetes.labels.fluentd-log-format
    pattern ^(.+)$
    tag $1.${tag}
  </rule>
  <rule>
    key log
    pattern ^(.*)$
    tag no-parse.${tag}
  </rule>
</match>

This will effectively prefix the tag of the event with the value of the fluentd-log-format label if you specified it in the labels section of the container metadata in the Kubernetes descriptor for the pod. The second rule is to make sure we match all other events too, or else they disappear.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace: services
  name: sample-service
spec:
  replicas: 1
  revisionHistoryLimit: 2
  minReadySeconds: 20
  template:
    metadata:
      labels:
        fluentd-log-format: "spring-boot"
        service: sample-service
    spec:
      containers:
      - name: sample-service
        image: sample-service:snapshot
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

Now we can use a filter, which triggers on the spring-boot tag prefix, to parse the log attribute and extract all the different fields.

<filter spring-boot.**>
  @type parser
  key_name log
  reserve_data true
  <parse>
    @type multiline
    format_firstline /\d{4}-\d{2}-\d{2}/
    format1 /^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(?<level>[^\s]+)\s+(\[(?<service>[^,]*),(?<trace>[^,]*),(?<span>[^,]*),(?<exportable>[^\]]*)\]\s+)?(?<pid>\d+)\s+---\s+\[(?<thread>[^\]]+)\]\s+(?<source>[^\s]+)\s*:\s+(?<message>.*)/
    time_format %Y-%m-%d %H:%M:%S.%N
  </parse>
</filter>

When the events go through the filter we end up with:

{
    "log":"2018-04-04 13:21:33.135  INFO [sample-service,5809caff2c4c218c,1da1ed2208d93495,false] 11 --- [ctor-http-nio-2] n.f.demo.sampleservice.SampleController  : Calling sample service.",
    "stream":"stdout",
    "time":"2018-04-04T13:21:33.135",
    "docker": {
        "container_id": "82cf69ea77a3dafa8dac3a6efd587664b7e9aadcc6f7db98859566d213d4371f"
    },
    "kubernetes": {
        "namespace_name": "default",
        "namespace_id: "724fc802-d4d6-4276-9aca-6f733c85a387",
        "pod_name": "sample-service-6b6f59f5cf-4v47j",
        "pod_id": "498a6ed4-3964-4579-b65d-52d0d9c82772",
        "container_name": "sample-service"
        "namespace_annotations": {
            "sample-service/release": "spring-2018"
        },
        "namespace_labels": {
            "product_version": "0.0.1"
        },
        "labels": {
           "fluentd-log-format": "spring-boot",
            "service": "sample-service"
        }
    },
    "level": "INFO",
    "service": "sample-service",
    "trace": "5809caff2c4c218c",
    "span": "1da1ed2208d93495",
    "exportable": "false",
    "pid": "11",
    "thread": "ctor-http-nio-2",
    "source": "n.f.demo.sampleservice.SampleController",
    "message": "Calling sample service."   
}

When we send this to Elasticsearch we have a lot of indexed fields we can use for creating awesome dashboards in Kibana.

This is a cross-post from my personal blog. Follow me on @acuriouscoder if you like what you’re reading or subscribe to my blog on https://acuriouscoder.net.

Het bericht Kubernetes & Logging verscheen eerst op First8 Java Consultancy.

]]>
Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 1) https://technology.first8.nl/wachtwoorden-3-mythes-4-fouten-en-5-tips-voor-ontwikkelaars-deel-1/ Wed, 21 Feb 2018 21:39:16 +0000 https://technology.first8.nl/?p=6069 Als ontwikkelaars hebben we tegenwoordig een grote verantwoordelijkheid. We moeten ervoor zorgen dat onze gebruikers zich zo veilig en betrouwbaar mogelijk kunnen identificeren. In deel één van deze blog vertelde ik over de mythes, fouten en tips voor gebruikers. In dit deel zal ik toelichten waar wij als ontwikkelaars vaak de fout in gaan. In deel 3 zal ik de … Lees verder Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 1)

Het bericht Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 1) verscheen eerst op First8 Java Consultancy.

]]>
Als ontwikkelaars hebben we tegenwoordig een grote verantwoordelijkheid. We moeten ervoor zorgen dat onze gebruikers zich zo veilig en betrouwbaar mogelijk kunnen identificeren. In deel één van deze blog vertelde ik over de mythes, fouten en tips voor gebruikers. In dit deel zal ik toelichten waar wij als ontwikkelaars vaak de fout in gaan. In deel 3 zal ik de tips gericht op ontwikkelaars beschrijven.

Als Senior Java Developer bij First8 houd ik me tijdens en buiten werktijden bezig met security en privacy. Door kennis hierover voor mezelf en mijn vakgenoten te vergroten, hoop ik de wereld veiliger te maken.

Ook in dit deel zal ik een aantal mythes ontkrachten. Daarna licht ik een aantal fouten toe die we als ontwikkelaar nog steeds maken.

Mythes

Periodiek veranderen

Laten we meteen beginnen met de meest hardnekkige mythe. Periodiek veranderen van wachtwoorden helpt niet. Als je je gebruikers gaat dwingen om periodiek een nieuw wachtwoord te kiezen, dan gaan ze simpelweg een reeks gebruiken. Het is dus veel beter om goed te monitoren op potentiële wachtwoord-lekken en evt. ongeautoriseerde toegang. In die gevallen is er tenminste een goede reden voor een wachtwoord-reset.

MyComplexPW1!
MyComplexPW2!
MyComplexPW3!

Complexiteit

Je kent de standaard regeltjes wel: minimaal één hoofdletter, één kleine letter, één cijfer en één leesteken. Maar dan niet die, die en die. Met de meest recente Unicode karakter-set kunnen gebruikers helemaal los gaan met emoji’s, Aziatische, Arabische en andere non-Latin karaktersets en allerhande rare figuurtjes. Zoals hier (4:40) al wordt uitgelegd, een XSS attack-string is een vrij goed wachtwoord, maar wordt vaak niet toegestaan. De bedoeling van al die regels is nobel: we willen onze gebruikers zoveel mogelijk stimuleren om een goed en veilig wachtwoord te gebruiken. Maar wat bereiken we ermee?

Kijk eens naar onderstaande lijst. Dit zijn allerhande varianten van het woord ‘password’ en het aantal keren dat deze werd uitgeprobeerd in een brute-force hack. In totaal werden 49 verschillende varianten geprobeerd.

     17 p455w0rd
     18 p4ssword
     19 p@55w0rd
     27 P@ssw0rd
     29 p@ssword
     32 p4ssw0rd
     88 pa55w0rd
    115 passw0rd
    125 p@ssw0rd
    294 password
Total: 1070

We weten dat gebruikers al snel terugvallen op varianten (l33tsp34k) van bestaande woorden. Uit ervaring weten we ook, dat crackers deze varianten kennen en dit eenvoudig in hun aanvallen en password-dictionaries opnemen. Moeilijke regels wekken dus schijnveiligheid. Daarnaast zorgt de complexiteit ook voor een uitdaging bij gebruikers. Zij worden beperkt in de keuze van hun wachtwoord. Zijn bepaalde speciale tekens wel of niet toegestaan? Zijn er nog hoofdletter / kleine letter eisen? Additionele eisen? Bij de Nederlandse Belastingdienst voor MKB is de eisenlijst al behoorlijk lang en onnodig complex. Bovendien leggen ze beperkingen op, die een gebruiker dwingen om minder sterke wachtwoorden te kiezen. Er is slechts een kleine subset aan speciale karakters mogelijk. De overige eisen zijn eveneens complex en beperkend. Op de eerste regel die je in het plaatje ziet, kom ik later nog terug.

Copy-paste

Sommige websites blokkeren copy-paste acties in het wachtwoord-veld: Stop Password Pasting of SPP. Er zijn een aantal overtuigend klinkende redenen die dit rechtvaardigen. Er is geen enkele reden die dit rechtvaardigt.

Brute-force attacks

Password Pasting zou het mogelijk maken om een geautomatiseerd programma brute-force aanvallen te laten uitvoeren. Door SPP zou deze vorm worden geblokt. De realiteit is, dat brute-force ook zonder het html-form kunnen worden uitgevoerd. Tools als Burp Suite kunnen requests eenvoudig herhalen met andere parameters. SPP stopt dit niet. Bovendien zijn er veel betere manieren om brute-force aanvallen te blokkeren. Denk hierbij aan korte vertragingen na elke inlog-poging en (tijdelijke) lock-outs na een aantal foutieve pogingen.

Slecht onthouden

Door SPP zou een gebruiker vaker het wachtwoord zelf invoeren en daarmee sneller het wachtwoord kunnen onthouden. Bij veelgebruikte websites, waar gebruikers dagelijks op inloggen zou dit misschien nog werken. De meest gevoelige sites, zoals belastingdienst, pensioen, hypotheek, verzekeringswebsites en mogelijk internetbankieren worden echter sporadisch bezocht. Daarnaast wil je de gebruiker zoveel mogelijk complexe, lange en unieke wachtwoorden laten kiezen. Het is onrealistisch om van gebruikers te verlangen dat ze deze unieke wachtwoorden allemaal gaan onthouden. Als strategie is dit dus niet haalbaar.

Clipboard

Wachtwoorden zouden onveilig lang op het clipboard van de gebruiker blijven staan. Als een gebruiker zelf een wachtwoord uit een document copy-paste, dan blijft deze inderdaad op het clipboard staan, totdat het wordt overschreven. De meeste wachtwoord-managers verwijderen echter het wachtwoord, zodra deze is ge-paste. Hiermee wordt de tijd en het risico verkort. Sommige password-managers gebruiken bovendien virtuele keyboards om het copy-paste risico te ontwijken. Bovendien is de machine van een gebruiker met een clipboard-capturing virus of malware al per definitie onbetrouwbaar. Clipboard capturing is dan één van de vele aanvallen die het virus kan proberen en zeker niet het grootst mogelijke probleem.

SPP maakt onveilig

Het blokken van copy-paste helpt dus niet of nauwelijks om systemen veiliger te maken. Het maakt  wachtwoorden juist onveiliger. Password-pasting geeft de gebruiker namelijk belangrijke mogelijkheden. De gebruiker kan eenvoudiger unieke wachtwoorden gebruiken met behulp van een wachtwoord-manager. Deze hebben meestal copy-paste mogelijkheden nodig om te kunnen werken. Copy-paste verlaagt daarnaast de tijd die een gebruiker nodig heeft om in te loggen en voorkomt type-fouten bij complexe en lange wachtwoorden.

Fouten

Tot zover deze mythen die onbewust en vaak onbedoeld tot fouten leiden. De volgende punten zijn echter bekende en nog steeds niet goed gehanteerde regels.

Maximale lengte

We zagen dit al in het voorbeeld van de belastingdienst. Hierbij werd het wachtwoord beperkt tot maximaal 25 karakters. Een goedwillende gebruiker die een extra lang wachtwoord wil instellen, wordt hiermee beperkt. Een langer wachtwoord is niet eens onredelijk, alhoewel slechts zeer weinig gebruikers boven 100 a 200 karakters gebruiken. Mocht je dan ook een maximum willen instellen, neem dan een veel ruimer getal. NIST adviseert minimaal 64 karakters toe te staan. Kosten van opslag zijn dusdanig laag, dat dit geen limiterende factor meer is. We zullen later zien dat beperkingen in lengte niet of nauwelijks nodig zijn, zelfs als je de marginale kosten voor opslag zou mee rekenen.

Mailen van wachtwoord

Bij het aanmaken van een account of de wachtwoord-vergeten functie wordt soms nog het wachtwoord in plain-text naar de gebruiker gemaild. Dit is om meerdere redenen een slecht idee. Ten eerste is e-mail per definitie onveilig, tenzij je PGP gebruikt. Ten tweede geef je met een plain-text wachtwoord in de mail via de wachtwoord-vergeten functie een cruciale fout toe: je kunt het wachtwoord leesbaar herproduceren. Dit kan duiden op het gebruik van een slecht algoritme, bijvoorbeeld door gebruik van encoding (bv. base64) of encryptie terwijl goede hashing gebruikt zou moeten worden. Het kan echter nog slechter:

Plain-text

Geloof het of niet: er worden nog steeds wachtwoorden opgeslagen in plain-text. Dat plain-text storage fout is, mag duidelijk zijn. Het is echter lastig en complex om de opslag van wachtwoorden echt goed te doen. Encoding, encryptie, hashing, als je deze termen niet vlekkeloos en in detail kunt toelichten, dan zul je er gegarandeerd fouten mee maken.

Encoding

Bijna net zo makkelijk leesbaar als plain-text is encoding. Er zijn meerdere gevallen bekend waarbij de wachtwoorden in Base64 encoding zijn opgeslagen. Deze en andere encoding kan eenvoudig worden omgekeerd. Een eigen programma maken om dit offline uit te voeren kost weinig moeite. Encoding werkt twee richtingen op, het is omkeerbaar. En dat is bij wachtwoorden niet nodig.

Encryptie

Ook encryptie alleen is niet voldoende om wachtwoorden veilig op te slaan. Net als encoding is encryptie omkeerbaar, hoewel je soms het encryptie-mechanisme en mogelijk de sleutel moet weten om dit uit te kunnen voeren. Bij zwakkere encryptie kunnen met decryptie de originele wachtwoorden worden achterhaald.

Hashing

De enige manier om wachtwoorden te bewerken zodat ze niet tot het originele wachtwoord te herleiden zijn, is hashing en wel met een sterk hashing-mechanisme. Je kunt onmogelijk een hash terugrekenen naar het originele wachtwoord. Wat een aanvaller wel zou kunnen doen, is een lange lijst maken met bekende wachtwoorden en van elk de hash zelf uit rekenen. Door deze zelfgemaakte lijst te vergelijken met de hashes uit een gestolen database, kan een aanvaller eenvoudig de oorspronkelijke wachtwoorden opzoeken. Soortgelijke lijsten circuleren al op internet en worden ook wel rainbow-tables genoemd.

Salt

Een verdediging tegen rainbow-tables is het gebruik van salt. Een salt combineert het wachtwoord met een deel van de andere gegevens van de gebruiker om een complexere string te maken. Bij een inlog-poging kan de invoer weer worden gecombineerd met dezelfde gegevens (bv. de achternaam van de gebruiker) en vergeleken met de database-waarde. Als de aanvaller echter beschikking over de database heeft, dan heeft hij ook de beschikking over de gegevens die gebruikt worden voor het salten. Hij hoeft enkel te achterhalen welke gegevens als salt worden gebruikt.

Pepper

Ook hier is weer een verdediging voor te bedenken. Een unieke en lange geheime sleutel wordt gebruikt om het wachtwoord opnieuw te hashen. Deze sleutel wordt vaak pepper of HMAC genoemd. De methode die hierbij gebruikt wordt is lastig uit te leggen en valt meer onder cryptografie. Een vereenvoudigde uitleg van pepper is als een salt die voor iedere gebruiker hetzelfde is, maar die wel buiten de database liefst in een veilige omgeving (vault) wordt opgeslagen.

Hardening

Zelfs als je bovenstaande maatregelen correct implementeert kan een aanvaller nog altijd proberen om simpelweg alle mogelijke wachtwoorden te proberen: brute-force. Een verdediging tegen brute-forcing kan door ervoor te zorgen dat de encryptie bij een password check of “omzetting” memory en cpu intensief is. Hierdoor wordt de tijd en hardware die nodig is om de wachtwoorden te kraken flink verhoogd. 

Door eerst te hashen met SHA2-512 wordt het wachtwoord, ongeacht de lengte omgezet in een 512 bits hash. Hierdoor kan elk wachtwoord van arbitraire lengte worden opgeslagen in veld van 64 karakters. Hiermee hoeven we dus geen extra opslagruimte te reserveren voor extra lange wachtwoorden. Door het vervolgens te combineren met een salt van 8 karakters kunnen we deze encrypten met bcrypt. Een klein nadeel van bcrypt is namelijk de limiet van 72 karakters. Andere opties naast bcrypt zijn scrypt, PBKDF2 en argon2.

Wiel uitvinden

In veel organisaties wordt functionaliteit zelf ontwikkelt. Bestaande pakketten sluiten vaak niet precies aan op de behoefte van de organisatie. Ook voor identity management en authenticatie wordt dan al snel een eigen oplossing gebouwd. De complexiteit en gemis aan zeer specialistische kennis zorgt dan al snel voor fouten in de software. Dit artikel is nog beperkt tot enkel wachtwoorden. Er valt nog een hoop te schrijven over account initialisatie, privacy, rechtenbeheer, beveiliging etc. Er zijn ontzettend veel mogelijkheden om fouten te maken. En een enkele fout kan funest zijn. Gelukkig hoef je als ontwikkelaar niet alles zelf te doen. De meeste frameworks hebben uitgebreide mogelijkheden om account en identity management op te zetten. Koppeling met externe identity providers zoals Google of Facebook, zijn vaak ingebakken of als plugin beschikbaar. En er zijn vaak mogelijkheden om het account management naar wens aan te passen. Er zijn dus weinig tot geen redenen om zelf opnieuw het wiel uit te vinden.

Frameworks en moderne wachtwoord policy

De regels van vroeger zijn dus achterhaald. Beperkingen in de wachtwoord-policy werken averechts. Je kunt ze dus beter weglaten. Daarnaast is goede en veilige opslag van wachtwoorden een complex probleem. Er is diepgaande specialistische kennis voor nodig om dit goed te doen. Gelukkig zijn er voldoende standaard oplossingen die hier speciaal voor ontwikkeld zijn. Gebruik deze dan ook. Een framework als Spring Security helpt je als ontwikkelaar om goed en veilig identity management op te zetten.

Het bericht Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor ontwikkelaars (deel 1) verscheen eerst op First8 Java Consultancy.

]]>
Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor gebruikers https://technology.first8.nl/wachtwoorden-3-mythes-4-fouten-en-5-tips-voor-gebruikers/ Thu, 08 Feb 2018 11:27:14 +0000 https://technology.first8.nl/?p=6065 Wachtwoorden…. nog steeds het belangrijkste authenticatie mechanisme: het bewijs dat je bent wie je zegt dat je bent. We hebben er bovendien tientallen, zo niet honderden. Allemaal met andere eisen, andere geldigheidsduur. Ze beschermen (hopelijk) gegevens van vrij onbelangrijk tot zeer persoonlijk en gevoelig. We (denken te) weten wat de adviezen zijn voor wachtwoorden. Maar we volgen die nog steeds … Lees verder Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor gebruikers

Het bericht Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor gebruikers verscheen eerst op First8 Java Consultancy.

]]>
Wachtwoorden…. nog steeds het belangrijkste authenticatie mechanisme: het bewijs dat je bent wie je zegt dat je bent. We hebben er bovendien tientallen, zo niet honderden. Allemaal met andere eisen, andere geldigheidsduur. Ze beschermen (hopelijk) gegevens van vrij onbelangrijk tot zeer persoonlijk en gevoelig. We (denken te) weten wat de adviezen zijn voor wachtwoorden. Maar we volgen die nog steeds niet allemaal. Zijn die adviezen eigenlijk wel zo goed? Hoe kunnen we met al die adviezen toch op een normale manier onze gegevens veilig stellen?

Als Senior Java Developer bij First8 houd ik me tijdens en buiten werktijden bezig met security en privacy. Na te lang zelf gestoeid te hebben (en nog steeds) met de beperkingen van websites en applicaties op gebied van wachtwoorden, vond ik het tijd om een artikel te schrijven die voor eens en altijd afrekent met de mythes en valkuilen van wachtwoorden. Dat worden er uiteindelijk twee, gericht op gebruikers in dit artikel en ontwikkelaars in het volgende deel.

Zoals de titel al zegt, ga ik eerst een drie-tal mythes bespreken. Daarna stip ik vier fouten aan, die de meeste mensen nog steeds maken. Tenslotte geef ik vijf tips, die je zelf kunt toepassen om veel veiliger om te kunnen gaan met wachtwoorden en beveiligde accounts. Als er één advies is dat je in ieder geval wilt opvolgen, dan is dat het gebruik van een wachtwoord-manager. Hiermee volg je meteen een aantal zeer belangrijke tips op, die ik hieronder zal toelichten.

Drie mythes

Om te beginnen: bepaalde adviezen van oudsher zijn achterhaald. Ze zijn gewoonweg extreem gebruikers-onvriendelijk. Je weet wat er dan gebeurt; we vinden een work-around. De vindingrijkheid van mensen wordt nog steeds zwaar onderschat. Overijverige systeembeheerders bedenken nog steeds beveiligingsmaatregelen die in de praktijk juist averechts werken.

1: Periodiek veranderen

Verander je regelmatig je wachtwoord? Waarom? Omdat het moet hè? Elk jaar, elke drie maanden of misschien zelfs elke maand. Wat doe je dan? Je hoogt het nummertje in je wachtwoord op met 1. Dat is ontzettend handig als je vergeten bent wanneer je ook al weer in dienst kwam. Deel het getal door 4 en je hebt het aantal jaar dat je in dienst bent. 

MyComplexPW1!
MyComplexPW2!
MyComplexPW3!

Je snapt, op deze manier is het vrij makkelijk voor een hacker om je volgende wachtwoord te raden. Bovendien: ook al zou je als gebruiker een compleet ander wachtwoord instellen, als je wachtwoord is gehackt of geraden, dan nog heeft een hacker tot maximaal 1 a 12 maanden om in je account rond te neuzen. Een verplichte periodieke wachtwoord-aanpassing heeft dus simpelweg geen zin.

2: Complexe wachtwoorden

Je wachtwoord is complex en met reden. Die reden is meestal omdat het systeem dat van je verlangt. Maar hoe goedbedoeld die reden ook is, de gevolgen gaan volledig aan het doel voorbij. Want wat doe je als je een wachtwoord moet bedenken en je wordt bestookt met allerhande moeilijke eisen? Dan ga je letters vervangen voor cijfers, leestekens etc. Alsof een password-hacker niet kon bedenken dat de letter A ook in de @ zit, of lijkt op een 4. Bovendien vervangt zowat iedereen, niet alleen de jeugd, inmiddels de E voor een 3, de I voor een 1 of een !, de O voor de 0, etc. Het mag dan ook geen verrassing zijn, dat deze eisen helemaal geen toegevoegde waarde meer hebben. Als ik zeg “correct horse battery staple”, dan weten de meeste techies meteen waar ik op doel. Als je de comic hiernaast aanklikt, dan weet jij het vanaf nu ook. Overigens is ook deze theorie inmiddels achterhaald en dat heeft dan weer met dictionary attacks te maken. Het gaat iets te ver voor dit artikel, maar ik ga je hieronder helpen om je ook tegen deze aanval te beschermen.

3: Onthouden

Onthoud jij al je wachtwoorden? Nee hè? Dat dacht ik al. Dat is maar goed ook. Het is natuurlijk onbegonnen werk, met al die accounts die we tegenwoordig hebben. Privé-mail, werk-mail, DigiD, werk-computer, je eigen computer, verschillende accounts op Social media, de nodige webwinkels, natuurlijk je internet-bankieren en wat al niet meer. Langzaam maar zeker komt bij bedrijven het besef dat het anders moet. Social logins zoals login met je Facebook of Google account zijn een optie. Maar ook die brengen weer een risico. Als je Facebook account is gehackt, dan zijn alle accounts die je daaraan gekoppeld hebt in één keer mee gekaapt.

Vier Fouten

Het kan vrij lastig zijn om verkeerde adviezen af te leren. Hopelijk heb ik je hierboven kunnen overtuigen hoe achterhaald deze rare mythes zijn. Maar het is nog veel moeilijker om de adviezen die je kent, netjes en consistent te hanteren. De systemen van oudsher dwingen ons in onwerkbare patronen. Zoals gezegd: dan gaan we oplossingen bedenken die het enigszins werkbaar maken. De bekende post-it op de monitor is daar een voorbeeld van. Maar er zijn meer “oplossingen”, die je echt beter kunt mijden. Hieronder geef ik aan waarom ze zo ernstig zijn en ook wat de betere oplossingen zijn.

1: Hergebruiken

Met zoveel accounts is het bijhouden van al die wachtwoorden praktisch onbegonnen werk. Waarom is het hergebruik van die wachtwoorden dan zo’n probleem? En als er eentje op straat komt te liggen, dan kan ik ze toch gewoon weer veranderen? Wat boeit het nou, als iemand je account van Bol.com kan inzien? Als ze iets bestellen, dan betaal je het toch gewoon niet? Je hebt niets te verbergen, toch? Ik weet wel zeker dat je je vergist. Maar veel belangrijker, als je overal hetzelfde wachtwoord gebruikt, dan zijn je accounts zo zwak beveiligd als de zwakste schakel. Dus heeft die ene simpele katten-site het niet op orde en lekt je wachtwoord via die site uit, dan is de inlog op je bankrekening ook gekaapt. Maar beveiliging kan ook bij grote bedrijven niet goed genoeg op orde zijn. Zelfs sites als LinkedInYahoo, de ECB en andere banken en financiële instellingen worden nog steeds gehackt.  Dus doe jezelf een groot plezier en gebruik je wachtwoorden slechts 1x per site.

2: Opschrijven

Nu de uitdaging: hoe ga je die grote wachtwoorden-brei nu werkbaar maken? Het zijn zo gigantisch veel accounts, dat alleen de gebruikersnaam onthouden al een uitdaging is. Dus je gaat het opschrijven. Toegeven, als je moet kiezen tussen hergebruik of unieke en sterke wachtwoorden die je opschrijft, dan is dat laatste nog altijd de minst erge optie. Dus mocht je niet handig genoeg zijn met computers, gebruik dan een wachtwoord notitie-blok en bewaak die met je leven. Maar waarschijnlijk lees je dit blog, omdat je aardig wat computer-ervaring hebt. In dat geval zijn er veel betere opties dan opschrijven.

3: Onthouden

Heb je een fotografisch geheugen? Gefeliciteerd. Maar kun je ook 100 unieke wachtwoorden met elk 60 verschillende tekens (inclusief leestekens) onthouden? Nee, dat dacht ik al. Daarom is mijn advies, stop met onthouden van wachtwoorden. Het heeft geen zin, het is onbegonnen werk en nogmaals, er is een veel betere manier. 

4: Lengte

Hoe lang is je langste wachtwoord? Minder dan 20 tekens? Iedereen weet, hoe langer het wachtwoord, hoe moeilijker te kraken. Toch maken we onze wachtwoorden niet lang genoeg. Sterker nog, we kunnen het soms niet eens, al zouden we het willen. Hiernaast een screenshot van het wachtwoord scherm van de Belastingdienst. Kijk maar eens goed naar de draconische regels die je voor je kiezen krijgt. In het volgende deel voor developers zal ik hier uitgebreid op ingaan. Het belangrijkste punt voor nu is echter de lengte. De eerste hint geeft aan dat het wachtwoord minimaal 8 en maximaal 25 tekens mag bevatten. Waarom dat maximum? Er is geen enkele goede reden om de lengte van het wachtwoord te beperken tot 25 tekens. Een maximum van 100 a 200 tekens zou veel beter zijn. Dat geeft jou als gebruiker veel betere mogelijkheden om een sterk wachtwoord te kiezen.

Vijf tips

Voor nu even genoeg misvattingen en fouten om af moeten leren. Wat natuurlijk belangrijk is voor jou als gebruiker is hoe je jezelf wel goed kunt beschermen. Wat zijn nou de maatregelen die echt zin hebben? Hieronder staan vijf tips die je als gebruiker kunt toepassen om je accounts telkens een stuk veiliger te maken. Er is nog steeds geen 100% veiligheid, maar met deze maatregelen ben je als “normale” gebruiker vaak prima beschermd. Vergelijk het met de beveiliging van je huis. Als het heel veel moeite kost voor een inbreker om in te breken, dan zal hij al snel een ander huis kiezen. Tenzij die inbreker zeker weet dat er ook echt een grote buit te halen is. 

1: Lang

Gebruik lange wachtwoorden. Zoals je in de bovenstaande strip al kon lezen, hoe langer het wachtwoord, hoe meer tijd het kost om het te raden. Ga voor wachtwoorden van minimaal 30 tekens. Ik zelf probeer altijd een wachtwoord van 30 tekens (met onderstaande maatregelen erbij) en kort dit alleen in als het moet. Zoals bij de belastingdienst dus. 

2: Complex

Hoe complexer je wachtwoord, hoe beter. Dus gebruik alle mogelijke tekens die je kunt vinden. Wist je dat emoticons tegenwoordig ook officiële geldige tekens zijn? Yep, de Unicode karakter-set is nu uitgebreid met Emoji. De eerste Emoji-karakters zaten daar al in sinds 2015, maar sinds 2017 kun je met gemak het complete eerste couplet van Let it go (uit de film Frozen) als wachtwoord invoeren.

The ❄️ 🌟 🔦 ⚪ on the mountain 🌙 🌠. 🙅🏻 a👣 to 🐝 👀. A 🏰 of 😢, and it 👀 like☝️ the 👑. 
The 💨 is 🐺 like this 🌀 ❄️ ☔️ 🏠. 🙅🏻 keep it in, ☁️ 💡 ☝️ tried.

Overigens zou ik een ander liedje kiezen. Dit couplet is namelijk al eens als wachtwoord gebruikt. Het werd uitgebreid op internet besproken toen de gebruiker erachter kwam, dat hij niet meer in zijn Macbook kon inloggen. 

3: Uniek

Het kan niet vaak genoeg gezegd worden: gebruik altijd unieke wachtwoorden. Zo beveilig je jezelf als er één van de website waar jij gebruik van maakt, wordt gehackt. Het uitlekken van je wachtwoord heeft dan geen sneeuwbal-effect, want de schade stopt bij die ene website. Het maakt niet uit, dat je dan tientallen wachtwoorden hebt. Daar hebben we de volgende tip voor.

4: Wachtwoord-manager

Gebruik een wachtwoord-manager. Je zult er echt even wat moeite voor moeten doen. Maar het helpt je zo ongelooflijk veel. Je kunt hiermee met gemak hele lange, complexe wachtwoorden instellen en bovendien voor elk account een uniek wachtwoord. Het is vaak zelfs mogelijk om nieuwe (unieke, lange en complexe) wachtwoorden te laten genereren, afhankelijk van de opties die jij aangeeft. Er is één heel belangrijke voorwaarde waar je zelf voor moet zorgen: een hoofd-wachtwoord. De wachtwoorden in je wachtwoord-manager worden versleuteld met dat hoofd-wachtwoord. Zonder dat wachtwoord kun je er dus niet in. Dat is heel goed, want dan kan een hacker er namelijk ook niet in. Let wel: er is voor dat hoofd-wachtwoord geen backup-optie. Er is geen “Ik ben mijn wachtwoord vergeten”-service. Onthoud dat wachtwoord dus alsof je leven ervan afhangt. Kies daarbij absoluut een lang en moeilijk niet te raden wachtwoord.

Keuze te over

Er zijn trouwens vele wachtwoord-managers. Daarin zul je nog wat huiswerk moeten doen. Je zult een keuze moeten maken of je je wachtwoorden automatisch wilt synchroniseren via internet, de zogenaamde “Cloud-sync”. Daarmee kun je eenvoudig wachtwoorden die je op je thuis-computer hebt ingevoerd gebruiken op je werk-computer en je telefoon. Let wel: in dat geval is je hoofdwachtwoord natuurlijk super-belangrijk. Als je wachtwoorden-bestand wordt onderschept of gekopieerd van één van je apparaten, dan is dat hoofdwachtwoord je laatste verdediging voor al je accounts. Zelf gebruik ik deze functie bewust niet. Als ik de wachtwoorden wil synchroniseren, dan doe ik dat zelf en handmatig. Ik gebruik een USB-stick of kabeltje om het bestand over te hevelen. Hierdoor kan het ook niet via e-mail, wifi of LAN-netwerk onderschept worden.

Automatisch of niet

De tweede keuze die je moet maken is of je automatische invul-functies wilt inschakelen. Er zijn voor de meeste wachtwoord-managers ook browser-uitbreidingen die het wachtwoord op de juiste site automatisch voor je invullen. Ook hierbij kies ik zelf voor wat minder gebruiksgemak, maar wel een nog betere bescherming. In dat geval moet ik dus om in te loggen even schakelen tussen mijn wachtwoord-manager en de browser of applicatie waar ik wil inloggen. Het minimale risico van een lek of misbruik in de browser-plugin sluit ik daarmee uit. 

Er wordt door security-experts heel kritisch gekeken naar wachtwoord-managers en met reden. Als er een bug of lek ontstaat of op enig andere manier iets fout gaat bij het gebruik, dan liggen meteen al je accounts op straat. Er zijn dan ook nog heel wat punten waarop je je keuze voor een bepaalde wachtwoord-manager kunt baseren. Mocht je je willen verdiepen, dan is hier meer informatie over wachtwoord-managers. Er worden heel wat technische termen gebruikt. Maar als je je wilt verdiepen kun je jezelf nog beter beveiligen. Mocht dit te technisch worden, kies dan gerust voor een wachtwoord-manager als 1Password, LastPass of KeePass.

5: Twee factor authenticatie

Wil je na deze tips nog meer veiligheid? Dat kan. Stel één van je wachtwoorden lekt alsnog uit, is die account dan meteen verloren? Dat hangt ervan af. Je gebruikt waarschijnlijk bij internet-bankieren al zo’n raar apparaatje. Dat apparaatje is naast je wachtwoord de tweede factor die jouw identiteit bevestigt. Het gebruik van dit soort apparaatjes of apps wordt 2-factor authenticatie genoemd, kortweg 2FA.

Het voordeel hiervan is dat een hacker met alleen je gebruikers-naam en wachtwoord nog steeds (bijna) niets kan doen. Hij kan hooguit de gegevens op je rekening bekijken, maar geen geld overboekingen. Afhankelijk van hoe een website 2FA gebruikt, kan er dus weinig of niets misgaan. Helaas is 2FA nog lang niet overal beschikbaar. De grote websites als Google, Facebook, Twitter en natuurlijk banken gebruiken allemaal 2FA, optioneel of verplicht. Maak er dan ook gebruik van. Vaak kun je ook aanvinken dat je werkt op een vertrouwde computer, zodat je jezelf maar éénmalig of periodiek hoeft te identificeren met 2FA. 

Gebruik ook het liefst een apparaatje, zoals banken die voor je aanleveren. Andere opties zijn autorisatie-apps, zoals Authy of Google Authenticator, maar ook SMS-berichten worden nog gebruikt. Die laatste is de minst veilige optie, aangezien ook SMS onderschept kan worden. Het is echter nog altijd veiliger dan zonder 2FA.

Tools & 2FA dus

Er zijn dus heel wat maatregelen die je zelf kunt nemen om je accounts te beveiligen. Niet alle maatregelen zijn altijd toepasbaar, gezien de beperkingen van sommige websites of applicaties. Kies dus telkens de beste combinatie van maatregelen en probeer zoveel mogelijk opties uit. Als er iets is wat je minimaal zou moeten doen, dan is het een wachtwoord-manager gebruiken. Daarmee kun je meteen op een gemakkelijke manier complexe, lange en vooral unieke wachtwoorden gebruiken voor al je accounts. Als je waar mogelijk ook nog 2FA toepast, dan ben je eigenlijk al heel goed beschermd.

Volgende keer ga ik dieper in op de technische maatregelen die ontwikkelaars kunnen treffen om het jou als gebruiker makkelijk te maken en je kunnen sturen naar een veilig wachtwoord. Daarnaast zal ik ook een aantal belangrijke fouten toelichten, die zowel de veiligheid als de privacy van gebruikers in gevaar kunnen brengen.

Het bericht Wachtwoorden: 3 mythes, 4 fouten en 5 tips voor gebruikers verscheen eerst op First8 Java Consultancy.

]]>
Functional Java by Example | Part 3 – Don’t Use Exceptions to Control Flow https://technology.first8.nl/functional-java-by-example-part-3-dont-use-exceptions-to-control-flow/ Fri, 19 Jan 2018 10:25:59 +0000 https://technology.first8.nl/?p=6056 This is part 3 of the series called “Functional Java by Example” and is a cross-post from my personal blog. The example I’m evolving in each part of the series is some kind of “feed handler” which processes documents. In previous parts I started with some original code and applied some refactorings to describe “what” instead of “how”. In order … Lees verder Functional Java by Example | Part 3 – Don’t Use Exceptions to Control Flow

Het bericht Functional Java by Example | Part 3 – Don’t Use Exceptions to Control Flow verscheen eerst op First8 Java Consultancy.

]]>
This is part 3 of the series called “Functional Java by Example” and is a cross-post from my personal blog.

The example I’m evolving in each part of the series is some kind of “feed handler” which processes documents. In previous parts I started with some original code and applied some refactorings to describe “what” instead of “how”.

In order to help the code going forward, we need to get rid of the good ol’ java.lang.Exception. (disclaimer: we can’t actually get rid of it) That’s where this part comes in.

If you came here for the first time, it’s best to start reading from the beginning. It helps to understand where we started and how we moved forward throughout the series.

These are all the parts:

I will update the links as each article is published. If you are reading this article through content syndication please check the original articles on my blog.

Each time also the code is pushed to this GitHub project.

Getting up to speed about Exceptions

Our java.lang.Exception has been around since Java 1.0 – and has basically been our friend in good times and nemesis at other times.

There’s not much to talk about them, but if you want to read up on a few sources, here are my favorites:

You on Java 8 already? Life became so much better! I… Err…oh, wait.

Ok, seems that there’s no way you can actually do it right.

At least, after reading above list, we’re now completely up-to-speed on the topic 🙂

Luckily I don’t have to write a blog post any more about what’s been covered for 95% already in above articles, but I’ll focus here on the one Exception we actually have in the code 🙂

Side effects

Since you’re reading this post, you’re probably interested in why this all has to do with functional programming.

On the road to approaching your code in a more “functional way”, you may have encountered the term “side effect” and that it’s a “bad thing”.

Ted-Vinke-Functional-Programming-Side-Effects

In the real world, a side effect is something you did not intend to happen, and you might say it’s equivalent to an “exceptional” situation (you would indicate with an exception), but it has a more strict meaning in a Functional Programming context.

The Wikipedia-article about a Side effect says:

Side effect (computer science) In computer science, a function or expression is said to have a side effect if it modifies some state outside its scope or has an observable interaction with its calling functions or the outside world besides returning a value. … In functional programming, side effects are rarely used.

So let’s see how our FeedHandler code currently looks like after the first two articles in this series:

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    changes
      .findAll { doc -> isImportant(doc) }
      .each { doc ->

      try {
        def resource = createResource(doc)
        updateToProcessed(doc, resource)
      } catch (e) {
        updateToFailed(doc, e)
      }
    }
  }

  private Resource createResource(doc) {
    webservice.create(doc)
  }

  private boolean isImportant(doc) {
    doc.type == 'important'
  }

  private void updateToProcessed(doc, resource) {
    doc.apiId = resource.id
    doc.status = 'processed'
    documentDb.update(doc)
  }

  private void updateToFailed(doc, e) {
    doc.status = 'failed'
    doc.error = e.message
    documentDb.update(doc)
  }

}

There’s one place where we try-catch exceptions, and that’s where we loop through the important documents and try to create a “resource” (whatever that is) for it.

try {
  def resource = createResource(doc)
  updateToProcessed(doc, resource)
} catch (e) {
  updateToFailed(doc, e)
}

In code above catch (e) is Groovy shorthand for catch (Exception e).

Yes, that’s the generic java.lang.Exception which we’re catching. Could be any exception, including NPE.

If there’s no exception thrown from the createResource method, we update the document (“doc”) to ‘processed’, else we update it to ‘failed’. BTW, even updateToProcessed can throw an exception too, but for the current discussion I’m actually only interested in a successful resource creation.

So, above code works (I’ve got the unit tests to prove it :-)) but I’m not happy with the try-catch statement as it is now. I’m only interested in successful resource creation, and, silly me, I could only come up with createResource either returning a successful resource or throwing an exception.

Throwing an exception to signal something went wrong, get the hell out of dodge, have caller catch the exception in order to handle it, is why exceptions were invented right? And it’s better than returning null right?

It happens all the time. Take some of our favorite frameworks, such as EntityManager#find from the JPA spec:

Ted-Vinke-FP-Exceptions-JPA-find

Arg! Returns null.

Returns:
the found entity instance or null if the entity does not exist

Wrong example.

Functional Programming encourages side-effect free methods (or: functions), to make the code more understandable and easier to reason about. If a method just accepts certain input and returns the same output every time – which makes it a pure function – all kinds of optimizations can happen under the hood e.g. by the compiler, or caching, parallelisation etc.

We can replace pure functions again by their (calculated) value, which is called referential transparancy.

In previous article, we’ll already extracted some logic into methods of their own, such as isImportant below. Given the same document (with the same type property) as input, we’ll get the same (boolean) output every time.

boolean isImportant(doc) {
  doc.type == 'important'
}

Here there’s no observable side effect, no global variables are mutated, no log file is updated – it’s just stuff in, stuff out.

Ted-Vinke-Functional-Data-In-Data-Out

Thus, I would say that functions which interact with the outside world through our traditional exceptions are rarely used in functional programming.

I want to do better than that. Be better. 🙂

Optional to the rescue

As Benji Weber expresses it:

There are different viewpoints on how to use exceptions effectively in Java. Some people like checked exceptions, some argue they are a failed experiment and prefer exclusive use of unchecked exceptions. Others eschew exceptions entirely in favour of passing and returning types like Optional or Maybe.

Ok, let’s try Java 8’s Optional so signal whether a resource can or can not be created.

Let’s change the our webservice interface and createResource method to wrap and return our resource in an Optional:

//private Resource createResource(doc) {
private Optional<Resource> createResource(doc) {
  webservice.create(doc)
}

Let’s change the original try-catch:

try {
  def resource = createResource(doc)
  updateToProcessed(doc, resource)
} catch (e) {
  updateToFailed(doc, e)
}

to map (processing resource) and orElseGet (processing empty optional):

createResource(doc)
  .map { resource ->
    updateToProcessed(doc, resource)
  }
  .orElseGet { /* e -> */
    updateToFailed(doc, e)
  }

Great createResource method: either correct result comes back, or an empty result.

Wait a minute! The exception e we need to pass into updateToFailed is gone: we have an empty Optional instead. We can’t store the reason why it failed — which we do need.

May be an Optional just signals “absence” and is a wrong tool for our purpose here.

Exceptional completion

Without the try-catch and with the map-orElseGet instead, I do like the way the code started to reflect the “flow” of operations more. Unfortunately, using Optional was more appropriate for “getting something” or “getting nothing” (which names like map and orElseGet also suggested) and didn’t give us the opportunity to record a reason for failing.

What’s another way to either get the successful result or get the reason for failing, still approaching our nice way of reading?

A Future. Better yet: a CompletableFuture.

A CompletableFuture (CF) knows how to return a value , in this way it’s similar to an Optional. Usually a CF is used for getting a value set in the future, but that’s not what we want to use it for…

From the Javadoc:

A Future that …, supporting … actions that trigger upon its completion.

Jip, it can signal “exceptional” completion — giving me the opportunity to act upon it.

Let’s change the map and orElseGet:

createResource(doc)
  .map { resource ->
    updateToProcessed(doc, resource)
  }
  .orElseGet { /* e -> */
    updateToFailed(doc, e)
  }

to thenAccept (processing success) and exceptionally (processing failure):

createResource(doc)
  .thenAccept { resource ->
    updateToProcessed(doc, resource)
  }
  .exceptionally { e ->
    updateToFailed(doc, e)
  }

The CompletableFuture#exceptionally method accepts a function with our exception e with the actual reason for failure.

You might think: tomayto, tomahto. First we had try-catch and now we have thenAccept-exceptionally, so what’s the big difference?

Well, we can obviously not get rid of the exceptional situations, but we’re now thinking like a resident of Functionalville would: our methods start to become functions, telling us something goes in and something goes out.

Consider it a small refactoring we need towards part 4, limiting the amount of side effects in our code even more, and part 5.

This is it for now 🙂

For reference, here’s the full version of the refactored code.

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    changes
      .findAll { doc -> isImportant(doc) }
      .each { doc ->
        createResource(doc)
        .thenAccept { resource ->
          updateToProcessed(doc, resource)
        }
        .exceptionally { e ->
          updateToFailed(doc, e)
        }
      }
  }

  private CompletableFuture<Resource> createResource(doc) {
    webservice.create(doc)
  }

  private boolean isImportant(doc) {
    doc.type == 'important'
  }

  private void updateToProcessed(doc, resource) {
    doc.apiId = resource.id
    doc.status = 'processed'
    documentDb.update(doc)
  }

  private void updateToFailed(doc, e) {
    doc.status = 'failed'
    doc.error = e.message
    documentDb.update(doc)
  }

}

This is a cross-post from my personal blog. Follow me on @tvinke if you like what you’re reading or subscribe to my blog on https://tedvinke.wordpress.com.

Het bericht Functional Java by Example | Part 3 – Don’t Use Exceptions to Control Flow verscheen eerst op First8 Java Consultancy.

]]>
5 overeenkomsten tussen Lego en First8 https://technology.first8.nl/5-overeenkomsten-lego-first8/ Fri, 05 Jan 2018 07:00:31 +0000 https://technology.first8.nl/?p=5991 Uitdaging Afgelopen december hebben we met onderstaande groep bij First8 een zaterdag besteed aan een mooie uitdaging. We bouwden het grootste, meest complexe en uitdagende Lego model dat verkrijgbaar is: de nieuwe Millennium Falcon, model 75192 uit de Star Wars Ultimate Collector Series. Een monster-model van 7541 steentjes en een gewicht van meer dan 13 kg!  De Falcon bouw je … Lees verder 5 overeenkomsten tussen Lego en First8

Het bericht 5 overeenkomsten tussen Lego en First8 verscheen eerst op First8 Java Consultancy.

]]>
Uitdaging

Afgelopen december hebben we met onderstaande groep bij First8 een zaterdag besteed aan een mooie uitdaging. We bouwden het grootste, meest complexe en uitdagende Lego model dat verkrijgbaar is: de nieuwe Millennium Falcon, model 75192 uit de Star Wars Ultimate Collector Series. Een monster-model van 7541 steentjes en een gewicht van meer dan 13 kg! 

Lego UCS Millennium Falcon in doos met Arjan en Bram

De Falcon bouw je niet even tussendoor. Dit model is het meest uitdagende model ooit door Lego uitgebracht: de instructies tellen meer dan 450 pagina’s! Met goed teamwork, de juiste expertise, doorzettingsvermogen en een goede voorbereiding hebben we dit model in een recordtijd van 8 uur opgebouwd.
Bij First8 zijn we vlot teamwork gewend. Wij zoeken projecten met uitdaging en passie. We houden van opdrachten die ons verder brengen. Opdrachten die onze kennis en ervaring op de proef stellen en aansprekende resultaten opleveren. En dit bouw-project is nagenoeg gelijk aan de bedrijfscultuur van First8, onze medewerkers en de uitdagingen die we in ons dagelijkse werk aangaan. In deze blog vertellen we graag wat over de overeenkomsten met het Lego bouwproces.

 

Reden 1: Goede voorbereiding

Opstelling van tafel als werkblad met camera op statiefVoor dit bouwproject hebben we goede voorbereidingen getroffen. We verwachtten een bouwtijd van minstens 10 uur. Dit zou zowel van de bouwers als de camera-apparatuur een flink uithoudingsvermogen vergen. Daarnaast zijn we in alle vroegte begonnen, zodat we het daglicht konden gebruiken bij de opnamen. Voor de bouwers hebben we genoeg drinken en lunch geregeld, met de mogelijkheid om ook avondeten te regelen indien nodig. We hebben de grootst mogelijke tafel als werkruimte gekozen die we beschikbaar hebben. En als laatste hebben we een digitale bouwbeschrijving gebruikt op laptops om ruimte te besparen en om parallel te kunnen bouwen.

Bij First8 gaan we goed beslagen te werk. We laten niets aan het toeval over. Een project begint al ruim voordat we de eerste regel code hebben gezet. We verdiepen ons in onze projectpartner, zodat we helder hebben wat zijn motivatie is. We bijten ons vast in het vraagstuk en willen het onderste uit de kan weten. Dit helpt ons het probleem beter te doorgronden en dwingt onze partner om goed, beter, best na te denken en alles helder te verwoorden.

 

Reden 2: Duurzame basis

Gedeeltelijk gebouwde Millennium Falcon, waarvan het  raamwerk wel al afgebouwd isDe Millennium Falcon weegt ongeveer 13 kg en dat moet geen probleem zijn. Lego steentjes kunnen namelijk heel wat gewicht aan. Maar liefst 432 kg is nodig om een standaard 2×2 blok te vervormen. Voor bouwwerken van 13 kg is echter ook stabiliteit nodig. Bij dit model is daar goed over nagedacht. Het raamwerk van Lego Technic blokken vormt de basis. Onze ervaren bouwers hebben deze basis gebouwd, zodat we daarop konden voortbouwen met mensen van allerlei niveau’s.

Onze projecten gaan ook zo. We beginnen direct goed, zodat we niet voor verrassingen komen te staan. Voor de fundering zetten we dan ook ervaren mensen in, die verstand van zaken hebben. Alleen dan kunnen we zeker zijn van een duurzaam en betrouwbaar eindresultaat.

 

 

Reden 3: Gemengde teams

Kinderen werken met Lego Mindstorms programmeerset
Devoxx4kids oktober 2017
Nadat we de basis goed hadden neergezet, hebben we ons bouwteam opgeschaald met mensen van allerhande ervaringsniveaus. Daarin heeft iedereen zijn of haar eigen kracht. Laura heeft bijvoorbeeld veel ervaring met verschillende bouwtechnieken. Ze is gewend om te improviseren en bouwt altijd met grote hoeveelheden Lego. Bram heeft veel ervaring met Star Wars Ultimate Collector Series modellen. Hij heeft bovendien de eerste Millennium Falcon (model 10179) al enkele malen gebouwd. Arjan is dan weer een ervaren Lego bouwer in Star Wars USC modellen en complexe Lego Technic modellen. Naast deze ervaring kregen we hulp van Linda met haar dochters. Ook Bas met zijn zoon en Koen met zijn blinde enthousiasme hielpen mee. Vooral de toevoeging van de kids (4 tot 8 jaar) creëerde een win-win-win situatie. Het hield ons scherp om precies te werken en duidelijk uit te leggen. Het hielp hiermee onze mentor-skills te verbeteren. De kids kregen daarbij veel en gedegen ervaring in de bouw van een model dat veel complexer is dan voor hun leeftijd bestemd is.
De evenementen die First8 elk jaar organiseert bieden diezelfde win-win situaties. Devoxx4kids is twee keer per jaar ons moment om ons mentorschap flink op de proef te stellen. We geven dan verschillende workshops programmeren aan kinderen van 9 tot 14 jaar. Daarbij beproeven zij ons om eenvoudig en duidelijk de aspecten van programmeren uit te leggen. En wij kunnen vanuit ons vakgebied de passie voor techniek overbrengen.
In onze projecten kiezen we ook voor een mix van ervaren mensen en leergierige juniors. Hierdoor kunnen we onze klanten bedienen met kwaliteit en lage kosten. En ook hierbij krijgt iedereen in zijn rol de voordelen. Kennis en ervaring in techniek voor de juniors, scherp blijven, duidelijk uitleggen en ervaring in goed mentorschap voor de ervaren mensen. Ook bij First8 zoeken we high potentials die zich vast willen bijten in stevige uitdagingen om te groeien, natuurlijk begeleid door Seniors. En we bieden dan ook een stevige uitdaging, zonder dat je bang hoeft te zijn voor falen. Bovendien stimuleren we opleidingen met een stevig opleidingsbudget. En we willen dat iedereen daar ook gebruik van maakt. 

 

 

Reden 4: Open standaarden

Pagina van het patent genaamd "Lego Toy building block" met dwarsdoorsnede van Lego bricks en het "Tube"-design

Sinds 1989 is het patent op het Lego bouwsysteem vervallen. Lego is dus al decennia lang een open standaard. Concurrerende systemen kunnen hun eigen, goedkopere versie van de alom bekende blokjes maken. Die kunnen dan gecombineerd worden met de originele Lego blokjes. Toch is de enige echte Lego nog steeds zeer populair en sinds 2016 zelfs de grootste speelgoedfabrikant ter wereld. Maar hoe kan dit succes verklaard worden? En waarom zien we dan maar weinig Lego concurrenten op de markt?
Bij First8 werken we ook met open standaarden. Dat doen we om makkelijk systemen op elkaar aan te kunnen sluiten. Het geeft onze klanten bovendien de mogelijkheid om probleemloos met andere partijen in zee te gaan. Wij houden niet van vendor lock-in, dus we doen daar zelf ook niet aan mee. We vertrouwen op de kennis en kwaliteit van onze mensen. En we zien dat ook terug in de tevredenheid van onze klanten. Vertrouwen geven en kwaliteit leveren is dan ook veel beter en duurzamer om een relatie op te bouwen en te behouden met onze klanten.
Voor Lego geldt hetzelfde. Het systeem is compatibel met andere bouwblokjes. Als Lego-bouwers weten we dat we niet vastzitten aan het Lego merk. Bovenal zijn we zeker van de perfecte kwaliteit van de originele Lego-blokjes en kiezen we telkens opnieuw voor kwaliteit boven een lagere prijs.

 

Reden 5: Vier je succes

Arjan en Bram houden trots de afgebouwde Millennium Falcon vast

Hard werken moet beloond worden. Daar doe je het voor. Na oplevering hebben we getoost op het succes. En het bouwwerk staat voorlopig als trofee op ons kantoor. Bovendien kunnen we nagenieten van de timelapse die we tijdens de bouw hebben gemaakt. Zo ook in ons normale werk. We hebben elke zomer een uitje, met kerst een diner en in de herfst en lente een borrel. 

Plezier

Alles gaat beter als je er plezier in hebt, zeker als het om complexe uitdagingen gaat. Dit project was ook een behoorlijke uitdaging. Natuurlijk is Lego bouwen al plezier op zich. Ook de nieuwe techniek die wij toepassen in onze projecten zorgt op dezelfde manier voor plezier. We zorgen ervoor dat we leuk, afwisselend en uitdagend werk hebben. Saai en monotoon werk, daar hebben we niks mee. Ook buiten ons werk zorgen we voor plezier. Naast onze uitjes en borrels hebben we elke 2 maanden een bordspellen-avond op ons kantoor. De medewerkers zorgen voor de spellen, onze werkgever zorgt voor de ruimte en hapjes en drankjes.

 

Conclusie

Lego Millennium Falcon ter display op kantoorZoek je goede ICT-ers om een uitdagende klus te klaren? Of ben je zelf Java, Open Source freak en op zoek naar een nieuw uitdaging? In beide gevallen is First8 de beste keus. Wij gaan voor duurzame relaties met onze partners en medewerkers. We zoeken de mooiste uitdagingen. En we gaan voor de beste oplossingen met Open Source techniek en open standaarden. Dat zorgt ervoor dat wij al bijna twee decennia lang een gezonde IT-club runnen. Dat doen we met mensen die hart voor de zaak, voor techniek en voor collega’s hebben. Maar vooral met mensen die ook plezier hebben. En dat zorgt ervoor dat we keer op keer genoeg reden hebben om er een feest van te maken.

Je kunt de Millennium Falcon komen bewonderen bij First8 in Nijmegen met een kop koffie en ons vertellen over jouw passie. Bel Daniëlle Graat of Linda Elbersen (024-3483570 of 06-51784368) voor een afspraak.

 

Bekijk de video:

Bouw-team

Arjan Lamers   Bram Patelski
Bouwt veel Lego Technic. Arjan heeft ruime ervaring met complexe en uitdagende technische modellen, zoals de 42055 Bucket Wheel Excavator. Voor modellen met pneumatische en gemotoriseerde onderdelen draait Arjan zijn hand niet om. Arjan is architect en samen met Bas zijn zij oprichters van First8.
 
  Bouwt voornamelijk Star Wars UCS modellen. Bram heeft bijna alle Star Wars UCS modellen minstens één keer gebouwd en de uitdagende modellen vaker. Door de overeenkomsten met de 10179 UCS Millennium Falcon kon hij zijn ervaring met dat model goed gebruiken bij de bouw van de nieuwe 75192. Bram heeft net een uitdagend Grails project afgerond en heeft ruime ervaring met GitFlow. Hij heeft bovendien brede kennis op privacy en security gebied.
     
Bas Passon (en zoon)   Koen Aben
Bouwt voornamelijk Lego met zijn zoontje, zij het wat eenvoudigere modellen. Bas heeft samen met Arjan in 1999 ons bedrijf opgericht en werkt nog steeds met passie bij First8. Die passie komt met name naar voren als hij Arjan bestookt met kritische vragen over diens keuzes en op die manier zijn partner in crime dwingt om de allerbeste oplossing te kiezen, maar dat ook nog eens moet kunnen uitleggen aan EN overtuigen van zijn luis in de pels.   Bouwt met Lego om Scrum beter uit te leggen. Naast Scrum ook een echte Open Source fanaat. Koen wil graag weten hoe iets werkt en zoekt dat uit tot op het diepste niveau. Hij is oprichter van MADSpace, de hackerspace van Eindhoven, en organiseert graag meetups op gebied van privacy en security.
     
Laura Nij Bijvank   Linda Elbersen (en dochters)
Bouwt veel modular gebouwen, naar eigen inzicht en met haar eigen Lego-collectie. Ze koopt liever losse Lego partijen als complete modellen in doos. Daardoor heeft ze veel ervaring met allerhande bouw-technieken en weet ze goed te improviseren. Ze weet bovendien hoe je overzichtelijk kunt werken met grote hoeveelheden steentjes. Laura is een ervaren Java developer en werkt momenteel aan REST-API’s die JSON data leveren aan meerdere Java en Grails front-end applicaties.   Bouwt met haar dochters kleine en middelgrote Lego modellen. Ze weet haar dochters goed aan te sturen en te stimuleren om uitdaging aan te gaan, ook als het enthousiasme wegvalt. Linda is marketing-guru bij First8. Samen met First8 developers bedenkt ze de meest waanzinnige marketing-stunts en maakt ze dan ook werkelijkheid. Samen met Bram heeft ze dit project uitgedacht en gefaciliteerd, zodat jij nu kunt genieten van een gave timelapse video.
     

Het bericht 5 overeenkomsten tussen Lego en First8 verscheen eerst op First8 Java Consultancy.

]]>
Functional Java by Example | Part 2 – Tell a Story https://technology.first8.nl/functional-java-by-example-part-2-tell-a-story/ Fri, 24 Nov 2017 14:16:54 +0000 https://technology.first8.nl/?p=5984 This is part 2 of the series called “Functional Java by Example”. The example I’m evolving in each part of the series is some kind of “feed handler” which processes documents. In previous part I started with some original code and applied some refactorings to describe “what” instead of “how”. In order to help the code going forward, we need … Lees verder Functional Java by Example | Part 2 – Tell a Story

Het bericht Functional Java by Example | Part 2 – Tell a Story verscheen eerst op First8 Java Consultancy.

]]>
This is part 2 of the series called “Functional Java by Example”.

The example I’m evolving in each part of the series is some kind of “feed handler” which processes documents. In previous part I started with some original code and applied some refactorings to describe “what” instead of “how”.

In order to help the code going forward, we need to tell a story first. That’s where this part comes in.

If you came here for the first time, it’s best to start reading from the beginning. It helps to understand where we started and how we moved forward throughout the series.

These are all the parts:

I will update the links as each article is published. If you are reading this article through content syndication please check the original articles on my blog.

Each time also the code is pushed to this GitHub project.

As a reference, we now have the following code as a starting point:

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    changes
      .findAll { doc -> doc.type == 'important' }
      .each { doc ->

      try {
        def resource = webservice.create(doc)
        doc.apiId = resource.id
        doc.status = 'processed'
      } catch (e) {
        doc.status = 'failed'
        doc.error = e.message
      }
      documentDb.update(doc)
    }
  }
}

Read out aloud

When I first started using Spock as a testing framework, since it came by default with Grails many years ago, I was impressed (and still am) by its many features and ease of use.

SpockFramework

You know what Mocks, Stubs and Spies are, right? Mockito has them, Powermock has them and basically every other serious (unit) testing framework. The concept of a Mock isn’t hard to grasp (you can read all about it here), but Spock has a special way of describing the (expected) interactions with its mocks.

There a great chapter about “Interaction Based Testing” which explains how to write down these interactions with a code sample.

The “Mocking” sub-chapter starts with:

Mocking is the act of describing (mandatory) interactions between the object under specification and its collaborators. Here is an example:

def "should send messages to all subscribers"() {
  when:
  publisher.send("hello")

  then:
  1 * subscriber.receive("hello")
  1 * subscriber2.receive("hello")
}

If you’re not familiar with Spock, with Groovy, or merely with above style of writing, don’t worry!

The author(s) of above Spock documentation too recognized not everyone immediately would understand what’s happening here.

They help with some advice and continue the documentation:

Read out aloud: “When the publisher sends a ‘hello’ message, then both subscribers should receive that message exactly once.”

The emphasis on “Read out aloud” is mine, because I think it’s pretty important. Not going into more Spock details here, but the advice itself I try to take to heart in my day-to-day coding.

  • When I write a piece of code, can I read it out aloud?
  • When someone else reads my code, can he/she read it out aloud?

“Aloud” here has nothing to do with volume 🙂 but with the fact that you can describe “what’s happening here” in a concise and understandable way. This makes it easy to reason about code.

High-level vs low-level

Consider the following scenario:

After driving for hours around in an unknown city to find the Theatre, after your car navigation has broken down, you finally decided to stop and ask for directions.

You stop near a pedestrian.

green-map-pin-flag-icon-655

You:

Sir, would you happen to know how to get to the Theater from here?

Pedestrian:

  1. Sure, that’s pretty easy. Here we go:
  2. Check your windows to make sure you have good visibility. Check mirrors to be sure they are aligned properly, giving you a proper view of the road.
  3. Adjust the seat so that your feet comfortably reach both pedals.
  4. Close the window.
  5. Reset the turn signal.
  6. Disengage your parking brake before you start driving.
  7. Ah, I see that you have an automatic. Please put the gear stick in “Drive”.
  8. Slowly, take your foot of the brake and monitor your dashboard gauges.
  9. Straight on, increase speed, monitoring your speedometer, keeping the RPM around 2000
  10. After around 120 yards, indicate with your blinkers for at least two seconds before beginning to switch to the left lane.
  11. Slowly move the car into the other lane. Turn your hands on the steering wheel ever so slightly in order to change lanes. It only takes a very slight movement of the wheel; as most modern cars are fitted with power steering. It should take anywhere from one to three seconds for you to change lanes. Any less and you’re doing it too quickly; any more and you’re doing it too slowly.
  12. Another X steps…
  13. Good luck!

Or, consider an alternative universe where the conversation would go like this:

You:

Sir, would you happen to know how to get to the Theater from here?

Pedestrian:

  1. Sure, that’s pretty easy. Here we go:
  2. Take a left turn and cross the bridge. It’s on your right.
  3. Good luck!

The last scenario is a breeze: clear directions what to do & where to go!

The first scenario, however, is ridden by details — with low-level specifics about driving the car itself — and even while we would not hope to get directions like that in real-life we still write software like that.

Tell me something on the right level. If I need specifics I’ll ask for it.

(BTW wikihow.com: How to Drive a Car kindly donated some of above instructions. If you actually need to learn to drive, it has a ton o’ resources!)

Telling something on the right level, means not only using properly named classes and methods, but also using the right kind of abstractions in them.

Let’s take a look again at our code:

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    changes
      .findAll { doc -> doc.type == 'important' }
      .each { doc ->

      try {
        def resource = webservice.create(doc)
        doc.apiId = resource.id
        doc.status = 'processed'
      } catch (e) {
        doc.status = 'failed'
        doc.error = e.message
      }
      documentDb.update(doc)
    }
  }
}

The story

How can we combine “read out aloud” and “high-level vs low-level” in our code?

Ted-Vinke-Tell-a-Story

What does our single handle method currently read like?

  1. Find all documents where the type-property equals the string "important".
  2. Call create on webservice with the document, which returns a resource.
  3. If we have a resource, assign the resource’s id to the documents apiId property.
  4. Set the status property of the document to the string "processed".
  5. If an exception occurred, set the status property of the document to the string "failed". Set the status property of the document to the message from the exception.
  6. Finally, call update on documentDb with the document.

Basically this is just repeating the code statements!

What story I’d like to tell instead, is the following:

  1. Process “important” documents by “creating a resource” through a webservice.
  2. Every time when this succeeds, associate both together and “mark the document as processed”, else mark it as “failed”.

Reads pretty well, don’t you think?

We can actually make this happen by using several “Extract method” refactorings in our IDE and choosing some good names for the extracted methods.

The double-quoted phrases in above story are the important bits I want to see at the high-level.

“important”

Why do I care what attribute is used of a document to determine it’s importance? Now it’s the string "important" which indicates “hey, I’m important!” but what if conditionals become more complex?

Extract doc.type == 'important' to its own method, called isImportant.

changes
    .findAll { doc -> isImportant(doc) }
    // ...

  private boolean isImportant(doc) {
    doc.type == 'important'
  }

“creating a resource”

Why do I care here how to invoke what method in a webservice? I just want to create a resource.

Extract all dealings with the webservice to it’s own method, called createResource.

def resource = createResource(doc)
  // ...

  private Resource createResource(doc) {
    webservice.create(doc)
  }

“update to processed”

Extract the details of associating resource/document/setting a status to its own method, called updateToProcessed.

updateToProcessed(doc, resource)
  // ...

  private void updateToProcessed(doc, resource) {
    doc.apiId = resource.id
    doc.status = 'processed'
  }

“update to failed”

Don’t care about the details. Extract to updateToFailed.

updateToFailed(doc, e)
  // ...

  private void updateToFailed(doc, e) {
    doc.status = 'failed'
    doc.error = e.message
  }

Seems that we’re left with documentDb.update(doc) at the end.

This is part of the storing of a processed/failed document in the database and I already described that on the highest level.

I put it in each of the just created updateTo* methods – a lower level.

private void updateToProcessed(doc, resource) {
    doc.apiId = resource.id
    doc.status = 'processed'
    documentDb.update(doc)
  }

  private void updateToFailed(doc, e) {
    doc.status = 'failed'
    doc.error = e.message
    documentDb.update(doc)
  }

So, after extracting the details out, what’s changed?

void handle(List<Doc> changes) {

    changes
      .findAll { doc -> isImportant(doc) }
      .each { doc ->

      try {
        def resource = createResource(doc)
        updateToProcessed(doc, resource)
      } catch (e) {
        updateToFailed(doc, e)
      }
    }
  }

Any human — e.g. co-worker, your future self — who would read this one out “aloud”, would understand what’s going from 30,000 ft.

If you need the details of any of these steps, just drill down into the method.

Being able to write things declarative (previous part of this series) and telling a story on the right level (this part) will also help make future changes more easily in part 3 and beyond.

This is it for now 🙂

For reference, here’s the full version of the refactored code.

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    changes
      .findAll { doc -> isImportant(doc) }
      .each { doc ->

      try {
        def resource = createResource(doc)
        updateToProcessed(doc, resource)
      } catch (e) {
        updateToFailed(doc, e)
      }
    }
  }

  private Resource createResource(doc) {
    webservice.create(doc)
  }

  private boolean isImportant(doc) {
    doc.type == 'important'
  }

  private void updateToProcessed(doc, resource) {
    doc.apiId = resource.id
    doc.status = 'processed'
    documentDb.update(doc)
  }

  private void updateToFailed(doc, e) {
    doc.status = 'failed'
    doc.error = e.message
    documentDb.update(doc)
  }

}

This is a cross-post from my personal blog. Follow me on @tvinke if you like what you’re reading or subscribe to my blog on https://tedvinke.wordpress.com.

Het bericht Functional Java by Example | Part 2 – Tell a Story verscheen eerst op First8 Java Consultancy.

]]>
Functional Java by Example | Part 1 – From Imperative to Declarative https://technology.first8.nl/functional-java-by-example-part-1-from-imperative-to-declarative/ Tue, 07 Nov 2017 00:17:55 +0000 https://technology.first8.nl/?p=5962 Functional Programming (FP) is about avoiding reassigning variables, avoiding mutable data structures, avoiding state and favoring functions all-the-way. What can we learn from FP if we would apply functional techniques to our everyday Java code? In this series called “Functional Java by Example” I will refactor in 8 installments an existing piece of code to see if I can reach … Lees verder Functional Java by Example | Part 1 – From Imperative to Declarative

Het bericht Functional Java by Example | Part 1 – From Imperative to Declarative verscheen eerst op First8 Java Consultancy.

]]>
Functional Programming (FP) is about avoiding reassigning variables, avoiding mutable data structures, avoiding state and favoring functions all-the-way. What can we learn from FP if we would apply functional techniques to our everyday Java code?

In this series called “Functional Java by Example” I will refactor in 8 installments an existing piece of code to see if I can reach Functional Nirvana in Java.

I don’t have much experience in a “real” functional language such as Haskell or F#, but I hope to demonstrate in each article by example what it means to apply some of these practices to your every day Java code.

Hopefully at the end you’ve gained some insight and know to pick some techniques which would benefit your own codebase.

These are all the parts:

I will update the links as each article is published. If you are reading this article through content syndication please check the original articles on my blog.

Each time also the code is pushed to this GitHub project.

Disclaimer: code is written in Apache Groovy, primarily for conciseness, so I don’t have to type stuff (you know: typing) where it doesn’t matter for the examples. Secondary, this language Just Makes Me Happy.

Why should you care about Functional Programming (FP)?

If you’re not doing Haskell, F# or Scala on a hip real-time, streaming data event processing framework you might as well pack your bags. Even the JavaScript guys are spinning functions around your methods these days — and that language has been around for some time already.

There are a lot of articles and video’s out there which make you believe that if you don’t hop on the Functional bandwagon these days, you’re left behind with your old OOP-contraptions and frankly, are obsolete within a couple of years.

Well, I’m here to tell you that’s not entirely true, but FP does have some premises, such as readability, testability and maintainability, values which we also strive to achieve in our (enterprise) Java code right?

As you’re reading this, for years you might already have the same outspoken opinion about FP being a step forwards or backwards or anno 2017-2018 you are just open for new ideas 🙂

You can level up your skills in every language by learning FP.

Determine for yourself what you can learn from it and how your own programming can benefit from it.

If you’re up to the task, let’s start this series with…

Some existing code

A word about example code: It’s pretty tricky to come up with contrived examples for blogs like these: it should be easy enough to appeal to a broad audience, simple enough to be understood without too much context, but still be interesting enough to result in desired learning effects.

Moving forward, each installment in this series will build on the previous one. Below is the code we’re going to take as a starting point.

So, put on your glasses and see if you’re familiar with coding-style below.

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    for (int i = 0; i < changes.size(); i++) {
      def doc = changes[i]
      if (doc.type == 'important') {

        try {
          def resource = webservice.create(doc)
          doc.apiId = resource.id
          doc.status = 'processed'
        } catch (e) {
          doc.status = 'failed'
          doc.error = e.message
        }
        documentDb.update(doc)
      }
    }
  }
}

  • It’s some sort of FeedHandler.
  • It has two properties, some Webservice class and a DocumentDb class.
  • There’s a handle method which does something with a list of Doc objects. Documents?

Try to figure out what’s going on here 🙂

..

..

..

Done?

Reading stuff like this can make you feel like a human parser sometimes.

Scanning the class name (FeedHandler?) and the one method (void handle) can give you, next to some eye sore, a “feel” for the purpose of everything.

However, figuring out what exactly gets “handled” inside the handle method is much harder.

  • There’s a for-loop there — but what’s exactly being iterated? How many times?
  • This variable webservice is called, returning something called resource.
  • If webservice returns successfully, the doc (a document?) being iterated over is updated with a status.
  • Seems webservice can also throw an Exception, which is caught and the document is updated with another status.
  • Ultimately, the document is “updated” by this documentDb instance. Looks like a database.
  • Oh wait, this happens only for the “important” docs — a doc.type is checked first before doing all above stuff.

Perhaps, you have heard of the phrase:

Code is read more than it is written.

Check out this piece of beauty:

for (int i = 0; i < changes.size(); i++) {

Above code is written in an imperative style, which means that the concrete statements — which manipulate state and behaviour — are written out explicitly.

  • Initialize an int i with zero
  • Loop while int i is less then the size of the changes list
  • Increment int i with 1 each iteration

In this style of imperative (procedural) coding (which most of the mainstream languages, including object-oriented programming (OOP) languages, such as Java, C++, C#, were designed to primarily support) a developer writes the exact statements a computer needs to perform to accomplish a certain task.

A few signals of very imperative (procedural) code:

  1. Focus on how to perform the task
  2. State changes and order of execution is important
  3. Many loops and conditionals

The code clearly focuses on the “How” — which makes the “What” hard to determine.

Focus on the What

Our first step, as the title of this article already have away, is to move away from the imperative style of coding and refactor to a more declarative style — of which FP is a form.

The loop is bugging me the most.

Here’s the new version of the code.

class FeedHandler {

  Webservice webservice
  DocumentDb documentDb

  void handle(List<Doc> changes) {

    // for (int i = 0; i < changes.size(); i++) {
    //    def doc = changes[i]
    changes
      .findAll { doc -> doc.type == 'important' }
      .each { doc ->

      try {
        def resource = webservice.create(doc)
        doc.apiId = resource.id
        doc.status = 'processed'
      } catch (e) {
        doc.status = 'failed'
        doc.error = e.message
      }
      documentDb.update(doc)
    }
  }
}

What’s changed?

  • The if (doc.type == 'important') part has been replaced with a findAll { doc -> doc.type == 'important' } again on the document collection itself — meaning “find all documents which are important and return a new collection with only those important documents”
  • The imperative for-loop (with the intermediate i variable) has been replaced by the declarative each method on the documents collection itself — meaning “execute the piece of code for each doc in the list and I don’t care how you do it” 🙂

Don’t worry about each and findAll: these methods are added by Groovy, which I use happily together with Java in the same code base, to any Collection, e.g. Set, List, Map. Vanilla Java 8 has equivalent mechanisms, such as forEach to iterate a collection more declaratively.

What leads to readable software is:

Describe “What” and not “How”.

I can easily see what’s going on if I write my code in a more functional style, which saves me time (because yes, I do read code 90% of the time instead of writing it) and writing it like this is less error-prone, because less lines gives less opportunity for bugs to hide.

This is it for now 🙂

In part 2, we will tell a story properly, paving the way for more functional programming, such as “Either” or “Try” even later in the series.

This is a cross-post from my personal blog. Follow me on @tvinke if you like what you’re reading or subscribe to my blog on https://tedvinke.wordpress.com.

Het bericht Functional Java by Example | Part 1 – From Imperative to Declarative verscheen eerst op First8 Java Consultancy.

]]>
Why is Spring’s Health Down, Down, Up, Up, Up and Down again? https://technology.first8.nl/why-is-springs-health-down-down-up-up-up-and-down-again/ Wed, 25 Oct 2017 07:45:39 +0000 https://technology.first8.nl/?p=5957 Why Our new JavaScript client application regularly calls the /health endpoint of our Grails backend to determine on- of offline state. Things started to become “funny” with it. This endpoint we get for free, since Grails is based on Spring Boot, which comes with a sub-project called Spring Boot Actuator. This gives us a a bunch of endpoints which allows … Lees verder Why is Spring’s Health Down, Down, Up, Up, Up and Down again?

Het bericht Why is Spring’s Health Down, Down, Up, Up, Up and Down again? verscheen eerst op First8 Java Consultancy.

]]>
Why

Our new JavaScript client application regularly calls the /health endpoint of our Grails backend to determine on- of offline state. Things started to become “funny” with it.

This endpoint we get for free, since Grails is based on Spring Boot, which comes with a sub-project called Spring Boot Actuator.

This gives us a a bunch of endpoints which allows us to monitor and interact with our application, including /health which returns health information.

So, our JS client checks whether or not it can reach this /health endpoint, executed every few seconds, to determine if the user is on- or offline. Nothing fancy, and we might switch later on to just using the Google homepage or something, but for now this works.

Failing health check

On localhost everything always seems fine, but as soon as I got our Jenkins pipeline finally to deploy the app to to our test servers after each build, and we started veryfying the app there, things became funny.

Usually we had a streak of perfectly good calls.

GET https://tst.example.com/health 200 ()
GET https://tst.example.com/health 200 ()
GET https://tst.example.com/health 200 ()
etc

Other times every few seconds we saw errors accumulating in the Chrome Inspector. Health checks would fail with with a HTTP status code of 503 Service unavailable for a long time.

GET https://tst.example.com/health 503 ()
GET https://tst.example.com/health 503 ()
GET https://tst.example.com/health 503 ()
etc

Then after a while we would get good calls again!

GET https://tst.example.com/health 200 ()
GET https://tst.example.com/health 200 ()
etc

The response of these failed requests just said

{"status":"DOWN"}

This is — by design — not very descriptive.

I certainly did not write any healh indicators myself so why would it be “down”?

Experienced Spring Booters know it will pick up any health indicator on the classpath and comes default with a few. Which ones are actually in use can be a mystery, because by default this endpoint is classified by Spring Boot as “sensitive” — and thus doesn’t expose too much information to the outside world.

I had to make the health check a bit more “chatty” by setting the following setting:

endpoints.health.sensitive: false

Now, calling the endpoint manually revealed the contenders!

{
  "status":"DOWN",
  "diskSpace":{
    "status":"DOWN",
    "total":8579448832,
    "free":20480,
    "threshold":10485760
  },
  "db":{
    "status":"UP",
    "database":"H2",
    "hello":1
  }
}

The general status of “down” is an aggregate result of (in this case: 2) auto-configured health indicators listed explicitly now.

What inmediately came to mind, when I saw this:

  • Why didn’t I remove H2 yet 🙂
  • Hey, disk space is running out on the test server already?!

The H2 database comes as a default dependency in any Grails application, but our app doesn’t use it — not in production and not for testing — so we will definately remove it from the dependencies. That’s a worry less.

With regard to disk space, it’s the good ol’ DiskSpaceHealthIndicator (indeed part of the auto-configured indicators) telling me things are unhealthy.

It has a default threshold of 10485760 bytes or 10 MB — the minimum disk space that should be available.

And…there’s only 20 kb free space? Of 8 gigs in total.

That’s a pretty low number 🙂

In the first 0.7 seconds I didn’t believe the healt indicator, can you imagine?

So I SSH’ed into the test server to check the available disk space with the df utility:

[Ted@server-01t ~]$ df -h
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/rhel-root  8.0G  8.0G   20K 100% /
...

Right, at least the health check speaks the truth there: there’s actually only a tiny bit of space left.

I relayed this to my IT collegue which provisioned this machine, to investigate. Seemed that there were already some Java heap dumps from earlier experiments taking up the space — which I was told will be removed ASAP.

Better check the other node too.

[Ted@server-02t ~]$ df -h
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/rhel-root  8.0G  5.3G  2.8G  66% /

Enough room there.

Wait a minute? “Other node?” Yes, we have 2 test servers, 01t and 02t.

At that point, I realized: the behaviour I was seeing was because of the loadbalancer forwarding a request to tst.example.com to either server-01t or the other `server-02t’. One of them was low on disk space, which explains that the health indicator of the Grails app on that server says “down” – resulting in a HTTP 503.

When observing these health calls (which requests are continuously made by our JS client) through the Chrome Inspector one small question was left: why do we have a streak of (sometimes 50x) “ups” (200) and then a bunch of “downs” (503) then in a seemingly random order?

The load balancer should keep us “fixed” on that node where a JS client for the first time makes its requests, as we configure our servers like that.

If the loadbalancer would send every request (to tst.example.com) round robin to server 1 or 2, I would expect a more (random) response of e.g. “up”, “down”, “down”, “up”, “down”, “up”, “up”, “down”, “up”.

Well, it seemed that during the window while I was observing this behaviour, the rest of the team was still developing features and…pushing to Git, which Jenkins picks up, which gets deployed to both servers. Because of a redeploy of the app to ech server serially, the loadbalancer “sees” the unavailibility of the application on the one server (with enough disk space: “up”, “up”, “up”, “up”, “up”) for the duration of the deployment and redirects traffic to the other server (with almost no disk space: “down”, “down”, “down”)…

…which gets updated with a new WAR pretty soon after, and requests end up on the other server again (with enough disk space: “up”, “up”, “up”, “up”, “up”).

🙂

Costs again 3 hours out of my life. Including some time noting down this stuff here (but I think that’s worth it) 🙂

Lesson learned

Know your process

Knowing that there’s a loadbalancer and multiple nodes (and how they work) helps. And that your CI server continuously deploys new versions to your environment which is under investigation does not help. But altogether knowing this did help to clarify the observed behaviour.

Learn the “sensible” defaults of your framework.

In case of Grails 3 and Spring Boot, know the stuff which gets “auto-configured” from the classpath, inspect it and make sure it’s going to be what you actually want.

We will get rid of H2 and review the health indicators we actually need, may be disabling the auto-configuration altogether. We cleaned up the Java heap dumps which caused the full disk. We’ve re-confirmed that the Unix team will monitor the OS, including disk space, so that we at least don’t need the DiskSpaceHealthIndicator anymore 🙂

This article has been crossposted from my personal blog.

Het bericht Why is Spring’s Health Down, Down, Up, Up, Up and Down again? verscheen eerst op First8 Java Consultancy.

]]>