Etikettarkiv: kodkvalité

Security through domain modeling

Detta inlägg finns även att läsa på HRM Softwares teknikblogg!

At the time of writing this I am sitting on the train home after attending the jDays 2016, a two-day conference packed with talks about Java and related technologies. Me and two of my fellow colleagues had a really nice time there and right now I feel quite stuffed with information that will need some time to sink in. One of the keynote speakers actually pointed out that sleeping and resting are important ingredients for accommodating what you are trying to learn, and fortunately those ingredients are perfectly in line with what my mind is signaling right now.

But prior to resting there is one thing that I need to put down in words right away. Being a fan of Domain-Driven Design (DDD) for quite some years now I am glad that I attended a talk about the concept of Domain-Driven Security (DDS) with the irresistible name ”Arm yourself with Domain Driven Security. It’s time to slay some security trolls…” by Daniel Deogun and Dan Bergh Johnsson. In the next couple of paragraphs I will attempt to pass on my understanding of the concept. If the notion of DDD is new to you then I warmly recommend you to read up on it. For me I found DDD to be an eye opener to say the least.

Now, the overall idea behind DDS is that we can use DDD as a way tackle various security challenges that we all have to deal with in some way or another, for example input validation, cross-site scripting or SQL injections. And the really nice part of this is that there is no technical wizardry or mysterious frameworks here – it all comes down to modeling the domain properly. Let me describe this with an injection attack example inspired from the talk I refereed to earlier. Here we go.

In a simple on-line registration page for a cat owner community there is an input field where you are asked to fill in the name of your favorite cat. Everything works fine and the community site is coming along nicely with an ever-growing user base, but then one day a terrible thing happened. Someone had injected JavaScript code in the cat name input field which made the browser redirect to a dog owner community page whenever the cat name was supposed to be displayed on the screen. Under the hood, the value in the cat name input field had been persisted as is, and when retrieved from the database to be displayed the JavaScript code executed, redirecting the browser.

The cat owner community was not pleased.

If the cat owner community instead had designed the application according to DDS they would most probably not have ended up in this situation. A cat name is a domain concept in its own that clearly differ from a string in that it cannot contain weird characters such as ”<” or ”>”. And if you think about it, does the concept of a ”string” really have any meaning in the domain of cat owners? Probably not. Moreover, numbers are probably not be something that the should allow in a cat name. With such business rules in place, we can define a class – for instance CatName – within the domain model that enforces all of these rules in its constructor.

We now repeat the injection attack described above with our new domain model construct CatName in place. The attacker enters the terrible script into the input field and submits the form. The string containing the JavaScript code, including the ”<” and ”>” characters, are passed on down towards the domain model, eventually to be mapped to the domain model concept CatName. Depending on how the cat naming rule is enforced, an exception could be thrown or any characters that aren’t letters are filtered away from the string. In any case, we can be sure that a CatName instance will never, ever contain malicious JavaScript code.

What I just tried to explain is just one example of security challenges that DDS aims to tackle. And the great thing is that much of DDS really comes for free if you just do DDD properly. Just think about the example above – the injection attack was avoided as a consequence of thorough domain modeling work a la DDD. The restrictions and rules enforced by the domain model saved the day for many cat owners.

For me, the talk about DDS was yet another piece of evidence that DDD is worth the extra modeling work up front. Through exploiting the ideas in DDD we can take a proactive stance to fight security challenges by simply doing our domain modeling work properly.

If you want to have a look at this particular talk it will be available on the jDays 2016 site in a couple of weeks. I strongly recommend watching it!

Preconditions in Google Guava

Detta inlägg finns även att läsa på HRM Softwares teknikblogg!

While the Guava project from Google comes packed with goodies for Java developers there is one thing in particular that I tend to use over, over and over again. Actually there used to be two of those, but since Java 8 comes with their own implementation of Optional I have shifted over towards that implementation instead. Anyway, the topic of this short text is Preconditions in Google Guava.

You can think of preconditions in Guava (as the word suggests) as a way to express and enforce preconditions that must be true in order for the execution to continue. A natural fit for these would be at the beginning of a method or a constructor, acting as guard statements of sorts that throw exceptions when violated.

To make things a bit more concrete we turn to code. First off we take a look at the ”normal” way to achieve precondition-like functionality without relying on Guava:

public class SomeClass {  
   private final String aString;  
   private final String anotherString;  
   private final int anInteger;  

   public SomeClass(String aString, String anotherString, int anInteger) {  
     if (aString == null) {  
       throw new NullPointerException("aString was null");  
     if (anotherString == null) {  
       throw new NullPointerException("anotherString was null");  
     if (anInteger <= 0) {  
       throw new IllegalArgumentException(  
           String.format("Expected anInteger to be > 0, got %s", anInteger));  
     this.aString = aString;  
     this.anotherString = anotherString;  
     this.anInteger = anInteger;  
   // more code here..  

In the SomeClass constructor we want to a) enforce that the strings passed as arguments are not null and that the integer argument is greater than zero and b) assign the arguments to their respective class member variable. Throughout the 16 lines of code in the constructor body we spend 12 lines of code just enforcing the correctness of the supplied arguments. One word that comes to my mind is verbose.

Another thing to note is that in each of the if-statements we check if the argument has a value that we do not accept. In plain english we can say ”if aString is null, then throw an exception” or ”if anInteger is equal to or lower than zero, throw an exception”.

We now turn to preconditions in Guava. An implementation of the constructor with the same functionality would then look as follows:

import static;
import static;

public class SomeClass {  
   private final String aString;  
   private final String anotherString;  
   private final int anInteger;  

   public SomeClass(String aString, String anotherString, int anInteger) {  
     checkArgument(anInteger > 0, "Expected anInteger to be > 0, got %s", anInteger);  
     this.anInteger = anInteger;  
     this.aString = checkNotNull(aString);  
     this.anotherString = checkNotNull(anotherString);  
   // more code here..  

In this version of the class constructor we make use of two static methods in the Preconditions class, namely checkArgument and checkNotNull. In order to make the code more readable these two methods have been statically imported, as seen above the class definition. Let’s walk through the lines in the constructor one by one.

The first line calls the checkArgument precondition to check that anInteger is greater than zero, otherwise an IllegalArgumentException will be thrown. A second and third argument can be supplied to the method – this is optional as the method is overloaded – that provides the exact same functionality as the String.format method used in the former version of the constructor. The most important thing to note on this line is that we check if the argument has a value that we accept. This is the complete opposite to what we did in the former version of the constructor, where we checked if the argument had a value we did not accept. In plain english we can now say ”anInteger must be greater than 0 or an exception will be thrown”.

The second line in the constructor is just an assignment, nothing more to say about that. The fourth and the fifth lines are however much more interesting. Here we use a precondition on each line to check that the string is not null, otherwise a NullPointerException will be thrown. If the precondition is enforced successfully, the argument supplied to the checkNotNull method is assigned to its member variable. In plain english we can now say ”aString cannot be null or an exception will be thrown”. Again, the way we express this is completely inverted from the former version of the constructor, where we say ”if aString is null, then throw an exception”.

Aside from making the code more compact – we have now effectively reduced the code from 16 lines down to 5 – it is also in my strong opinion that the latter version of our constructor is easier to understand. With preconditions in Guava we have the ability to state how things must be rather than how things must not be in order to proceed with the execution. This might seem like a trivial improvement to code readability, but with each small improvement to readability we add to our code base we also make it more maintainable.

After all, code is a form of communication, and code that communicates well is easier to understand and maintain.

P.S. An alternative to the Preconditions.checkNotNull method is the Objects.requireNonNull method available in Java 7.

Safety net tests?

För ett par dagar sedan höll jag en liten informell presentation på jobbet om en metod jag brukar luta mig mot när jag refaktorerar kod. Metoden beskrivs i boken Working Effectively With Legacy Code av Michael Feathers och kallas för The Legacy Code Change Algorithm. Den består av dessa fem enkla steg:

1. Identify change points.
2. Find test points.
3. Break dependencies.
4. Write tests.
5. Make changes and refactor.

Egentligen är väl tanken att algoritmen ska användas för att angripa legacykod utan att riskera land och rike, men om man för en stund bortser från ”make changes” i punkt 5 återstår ju faktiskt ”refactor”.

Nu vore det kanske på sin plats att definiera ”legacy code”. Menar man en stor hög med spagettikod från antiken? Eller betyder det helt enkelt att koden är dammig och bortglömd? Det finns säkert många definitioner där ute, men egentligen behöver vi bara bry oss om hur Feathers definierar begreppet för att förstå hans algoritm. Hans definition är som följer:

”Legacy code is simply code without tests.”

Plain, simple och kanske lite brutalt. Oavsett vad man tycker innebär definitionen alltså att koden kan ha författats igår – utan tester klassar Feathers den som legacy.

Tillbaka till min presentation (och poängen med detta inlägg). I en av mina slides hade jag ställt upp algoritmen för Test-Driven Development (TDD) jämte The Legacy Code Change Algorithm för att på så sätt kunna resonera om hur vi kan förhålla oss till tester som skrivs i respektive algoritm. Här tycker jag att det finns en intressant skillnad som hänger ihop med testernas syften.

I TDD ingår författandet av tester som en del i utvecklingen. Syftet med tester som skrivs här är att öka kvalitén på koden som skrivs och att via tester skapa en slags dokumentation över hur koden används. Om vi sedan tittar på The Legacy Code Change Algorithm syftar testerna istället till att skapa förutsättningar för att genomföra förändringar utan att ta sönder saker. Det betyder också att testerna i sig inte nödvändigtvis behöver vara en naturlig del av koden (som i fallet med TDD).

För mig blir det med ovanstående resonemang mycket enklare att motivera användandet av mocking frameworks såsom Mockito eller PowerMock när jag refaktorerar legacykod. Med sådana frameworks tillämpar man en slags White-box testing där testerna till stor del lutar sig mot hur implementationen ser ut. Helt vanligt refaktoreringsarbete kan då ta sönder sådana tester – trots att kodens beteende fortfarande mycket väl kan vara alldeles riktigt och rätt – eftersom implementationens utformning förändras.

Jobbigt, jobbigt.

Men i en galet komplex kodmassa kan ramverk som Mockito göra hela skillnaden för att få en ärlig chans att refaktorera på ett säkert sätt. Om testerna blir väldigt svårförvaltade kan jag tycka att de på sätt och vis har spelat ut sin roll och kan tas bort. Koden som refaktorerades när testerna skrevs bör i vilket fall vara i ett bättre tillstånd än tidigare, vilket också var det vi ville uppnå.

Kanske vore det läge för en ny benämning för tester som skrivs i detta syfte? Vad sägs om Safety net tests? 😉

Lite material om enhetstester

Ett tag innan jul höll jag i en kort presentation för min arbetsgrupp om enhetstester i Java för att få igång en diskussion över hur vi ska förhålla oss till sådana. Jag minns att jag sprang på ett par intressanta fynd när jag samlade ihop material till presentationen och ja, det är väl sånt man lägger upp på sin blogg I guess?

Det största fyndet var helt klart Michael Feathers bloggpost – författaren till den eminienta boken Working Efficiently with Legacy Code – som bjuder på en fin definition av vad ett enhetstest är. Men vänta lite nu, om jag kokar ihop ett exekverbart JUnit test, har jag då inte författat ett enhetstest? Svaret (enligt Feathers definition) är nej om:

  • testet arbetar mot databasen
  • testet kommunicerar över nätverket
  • testet arbetar mot filsystemet
  • testet inte kan köras parallellt med andra tester
  • man måste göra speciella saker med miljön (till exempel redigera konfigurationsfiler) för att köra testet

Okej, så även om jag skriver mina tester med hjälp av ramverk såsom JUnit är de inte alltid enhetstester. Men att skriva tester för kod som arbetar mot någon form av databas kan väl ändå vara värdefullt? Absolut, men då gäller det att vara medveten om att man testar kodens integration med den mjukvaran/biblioteket/whatever och inte kodens beteende. Att testa hur kod lirar tillsammans med andra moduler och komponenter kallas passande nog för integrationstester.

Karaktäristiskt för integrationstester är att de är tidskrävande, vilket också är en viktig poäng med att skilja enhetstester och integrationstester åt. Enhetstester är något man kör varje gång man bygger projektet medan integrationstester är något som körs mer sällan, t ex som ett schemalagt jobb.

Slutligen vill jag dela med mig av en kul anekdot i ämnet test coverage. Varsågoda!

Dagens begrepp: Characterization tests

För ett par dagar sedan satt jag och läste lite i boken Working Effectively With Legacy Code och då hittade någonting som jag tyckte om. Inte för att boken har varit dålig hittills – det mesta jag läst såhär långt har varit vettigt och matnyttigt. Men just det här tycker jag förtjänar att lobbas för. Det jag tänkte skriva om här kallas för characterization tests, och för att kunna förklara det fina med sådana behövs lite bakgrund.

Boken jag läser handlar om hur man ska förhålla sig till och arbeta med legacy code (orkar inte leta efter en vettig svensk översättning så engelska får duga). Även för en inbiten programmerare är definitionen av begreppet i boken lite intressant och kanske aningen kontroversiellt. Översatt från engelska anser författaren att legacy code helt enkelt är kod som saknar tester, oavsett om de är ett ”arv” eller ej. Med andra ord: inte bra.

Att man som ansvarsfull systemutvecklare ska skriva enhetstester för den kod man producerar är ingen nyhet. Det står i stort sett i varenda bok som behandlar ämnet programmering. Om detta är så pass vedertaget borde väl ändå de som arbetar med programmering/systemutveckling gladeligen ägna sig åt testknackande dagarna i ända? Well, som vanligt går inte teori och praktik hand i hand. I vissa fall (läs: många) finns det inga tester överhuvud taget, i andra har intentionen funnits men man har inte nått ända fram. Vad kan man då göra för att försöka förändra situationen till det bättre?

Enligt definitionen av legacy code behöver otestad kod kompletteras med tester för att inte längre klassas som legacy code. Det låter enkelt, men om testerna ska verifiera programmets beteende gäller det också att vi vet hur programmet ska fungera. Här stämmer bokens budskap och min erfarenhet väl överens: det finns sällan något enkelt sätt att ta reda på vad korrekt beteende är. Och vad är korrekt? Det beteende som finns att läsa i en gammal spec begraven i versionshanteringssystemet? Eller systemet som det fungerar idag?

När det gäller characterization tests är inte korrekt beteende det primära, utan här utgår man helt enkelt från systemets nuvarande funktionalitet. Till skillnad från ”vanliga” enhetstester, som syftar till att verifiera programmets beteende, syftar characterization test till att beskriva programmets beteende. Returnerar funktionen X i dagsläget värdet Y? Då ska testet förvänta sig värdet Y när X anropas. Är detta korrekt beteende? Vet inte, men det spelar ingen roll just nu. Det är det nuvarande beteendet vi vill åt. När vi har satt en struktur av tester som ”ramar in” funktionaliteten har vi skapat ett trevligt skyddsnät för framtida ändringar. Vi kan då börja fundera på vad som är korrekt. Samtidigt kan testerna ses som en dokumentation över hur systemet fungerar. Att sätta sig in i vad kod gör upptar en stor del av en programmerares dag och här kan sådana tester vara till god hjälp.

Har jag provat på detta? På sätt och vis har jag det; utan att jag vetat om det har jag skrivit tester utefter befintligt beteende för att ha något att utgå ifrån. Men det fina med denna lärdom är att jag nu har ett begrepp att förhålla mig till. Och när jag kommer tillbaka från föräldraledigheten blir det till att börja praktisera det nya begreppet på allvar.

Så nästa gång du blir ombedd att förändra funktionalitet i ett system och berörd kod saknar tester vet du vad du ska göra! 😉 Happy coding!