Follow Mattias Holmqvist's new blog "Learning more about software development".
The first two posts focus on, yes, you guessed it, Clojure, as Mattias works through some examples from Structure and Interpretation of Computer Programs.
Kurser i Domain-Driven Design - Våren 2012
Tuesday, October 27, 2009
From Java to Clojure Followup
Interest in the From Java to Clojure article has been pretty big, rarely before have we seen a PNEHM!-article getting so much attention!
I have also gotten some great feedback, in particular Stuart Halloway suggests that we use Clojure-contrib's seq-utils/frequencies to improve the code. Since we use Apache Commons Collections in the Java version of the code, its only fair for us to dive into the goodness of Clojure-contrib to see what can be of use there.
Let us start by a quick review of what our final version of the Clojure code looked like:
As it turns out, clojure.contrib.seq-utils/frequencies does exactly what our function count-words does, as such we can use it as a drop-in replacement. A version which uses contrib now looks like this:
We have to make sure we
Now, for extra credits, let's look inside the frequencies function in Clojure-contrib, to see what i looks like:
The implementation is quite different from our own, it feels a bit more straight-forward and intuitive. Initially, an empty map is created. As the collection is reduced a copy of the map is created for each processed item and the item is added with an incremented count (if the item already is in the map) or added to the new map with a count of one (if it is the first time the item is processed). get, gets a value from the map given a key, if there is no match the default, '0', is returned. inc increments the value, and assoc associates the value to a key in the map.
Not only is this version simpler than our own (which is good), it's also much faster (also good). Using seq-utils/frequencies a sample run with our micro-benchmark now looks like this (sorting 100 characters with 10000 samples):
Java: 120 ms
Groovy: 538 ms
Time Clojure: 563 ms
Excellent!
So, Joshua Bloch's item 47 in Effective Java (2 ed) applies as always: Know and use the libraries. If you get the feeling that someone must have done what you are about to do before you, someone most probably have.
Many thanks to Stuart Halloway (who will be at Øredev next week, don't miss it!).
The sources at http://code.google.com/p/pnehm-java-to-cool-language-x/ have been updated with the alternative version.
I have also gotten some great feedback, in particular Stuart Halloway suggests that we use Clojure-contrib's seq-utils/frequencies to improve the code. Since we use Apache Commons Collections in the Java version of the code, its only fair for us to dive into the goodness of Clojure-contrib to see what can be of use there.
Let us start by a quick review of what our final version of the Clojure code looked like:
(ns step4.pnehm.clojure-orderer)
(defn count-words [coll]
(reduce #(merge-with + %1 {%2 1}) {} coll))
(defn cmpr [[val1 freq1] [val2 freq2]]
(let [freq (compare freq2 freq1)]
(if-not (zero? freq) freq (compare val1 val2))))
(defn order-by-freq [coll]
(keys (sort cmpr (count-words coll))))
As it turns out, clojure.contrib.seq-utils/frequencies does exactly what our function count-words does, as such we can use it as a drop-in replacement. A version which uses contrib now looks like this:
(ns withcontrib.pnehm.clojure-orderer
(:use clojure.contrib.seq-utils))
(defn cmpr [[val1 freq1] [val2 freq2]]
(let [freq (compare freq2 freq1)]
(if-not (zero? freq) freq (compare val1 val2))))
(defn order-by-freq [coll]
(keys (sort cmpr (frequencies coll))))
We have to make sure we
:use clojure.contrib.seq-utils
, and then we can replace our call to count-words, with a call to frequencies.Now, for extra credits, let's look inside the frequencies function in Clojure-contrib, to see what i looks like:
(defn frequencies
"Returns a map from distinct items in coll to the number of times
they appear."
[coll]
(reduce (fn [counts x]
(assoc counts x (inc (get counts x 0))))
{} coll))
The implementation is quite different from our own, it feels a bit more straight-forward and intuitive. Initially, an empty map is created. As the collection is reduced a copy of the map is created for each processed item and the item is added with an incremented count (if the item already is in the map) or added to the new map with a count of one (if it is the first time the item is processed). get, gets a value from the map given a key, if there is no match the default, '0', is returned. inc increments the value, and assoc associates the value to a key in the map.
Not only is this version simpler than our own (which is good), it's also much faster (also good). Using seq-utils/frequencies a sample run with our micro-benchmark now looks like this (sorting 100 characters with 10000 samples):
Java: 120 ms
Groovy: 538 ms
Time Clojure: 563 ms
Excellent!
So, Joshua Bloch's item 47 in Effective Java (2 ed) applies as always: Know and use the libraries. If you get the feeling that someone must have done what you are about to do before you, someone most probably have.
Many thanks to Stuart Halloway (who will be at Øredev next week, don't miss it!).
The sources at http://code.google.com/p/pnehm-java-to-cool-language-x/ have been updated with the alternative version.
Monday, October 19, 2009
From Java to Clojure
In this article, published in Citerus’ newsletter PNEHM!, I introduce Clojure to Java developers by converting a piece of Java code to Clojure. The article examines how to call Java code from Clojure and Clojure code from Java, complete with source code.
Citerus’ consultant Peter Backlund took the same journey some months ago with his article Från Java till Groovy (in Swedish).
Read From Java to Clojure.
Citerus’ consultant Peter Backlund took the same journey some months ago with his article Från Java till Groovy (in Swedish).
Read From Java to Clojure.
Thursday, October 08, 2009
DDDSample Presentation (free event)
On Thursday evening, October 22, Sweden Spring User Group is hosting an even in Stockholm where Peter Backlund (mostly) and I (less) will present the current state of the DDDSample application.
Sedan applikationen först introducerades för drygt ett år sedan har den kontinuerligt utvecklats, mycket tack vara den feedback som kommit från olika communities. Det är snart dags för en ny release och under denna träff kommer vi kika närmare på applikationens olika delar och se hur dessa mappar mot koncept inom Domain-Driven Design.
Vi kommer att visa hur Spring (och i viss mån andra ramverk) hjälper oss att programmera domändrivet genom att dels låta oss bygga en ren och rik modell i Java, och dels genom att ta hand om infrastrukturell kod och låta oss fokusera på affärsnytta (focus on the core domain).
The presentation will be in Swedish and the event is free to attend.
Sign up at http://www.eventbrite.com/event/445416252
Welcome!
Agenda
DDDSample är en Spring-applikation som utvecklats för att påvisa hur idéer och koncept från Domain-Driven Design kan implementeras i en modern utvecklingsstack. Applikationen utvecklas i samarbete med Eric Evans, författare till boken Domain-Driven Design, och syftar till att visa hur mönster från DDD konkret kan användas för att skapa en systemarkitektur för att lösa problem i en komplex domän, utan att skapa onödig teknisk komplexitet.Sedan applikationen först introducerades för drygt ett år sedan har den kontinuerligt utvecklats, mycket tack vara den feedback som kommit från olika communities. Det är snart dags för en ny release och under denna träff kommer vi kika närmare på applikationens olika delar och se hur dessa mappar mot koncept inom Domain-Driven Design.
Vi kommer att visa hur Spring (och i viss mån andra ramverk) hjälper oss att programmera domändrivet genom att dels låta oss bygga en ren och rik modell i Java, och dels genom att ta hand om infrastrukturell kod och låta oss fokusera på affärsnytta (focus on the core domain).
The presentation will be in Swedish and the event is free to attend.
Sign up at http://www.eventbrite.com/event/445416252
Welcome!
Labels:
citerus,
DDD,
development,
java,
spam
Tuesday, October 06, 2009
Mocking to the Rescue!
I am not really a big fan of mocking. My experience is that if you design your code to be testable, you only rarely have to rely on mocks, instead you'll be fine just by stubbing an interface or two. But even as a proponent of what Martin Fowler calls classic TDD, I find it there are times when a mocking tool can come in handy. One situation is when you have to work with API:s that lack good interfaces, in these cases a good mocking tool with support for mocking concrete classes can be of great help.
Mockito is what I would like to consider a next-generation mocking tool, with support for both mocking and stubbing. Mockito fully and naturally uses recent language enhancements in Java, such as generics, static imports and annotations, to make the tool easy to use. Writing clean and elegant test code that is easy to understand can actually be pretty simple. TheMockito API is straightforward and well designed, the need for infrastructure code is kept to a minimum. If you are an EasyMock user, this comparison may be helpful when following along in the code below: http://code.google.com/p/mockito/wiki/MockitoVSEasyMock
Let's look at a few examples!
Stubbing the concrete class
If we would like to make data available to a job or read the result from a job execution we have to create an instance of
Use Mockito to setup the context and set a fictional
Mockito is what I would like to consider a next-generation mocking tool, with support for both mocking and stubbing. Mockito fully and naturally uses recent language enhancements in Java, such as generics, static imports and annotations, to make the tool easy to use. Writing clean and elegant test code that is easy to understand can actually be pretty simple. TheMockito API is straightforward and well designed, the need for infrastructure code is kept to a minimum. If you are an EasyMock user, this comparison may be helpful when following along in the code below: http://code.google.com/p/mockito/wiki/MockitoVSEasyMock
Let's look at a few examples!
Stub an interface
A nice property of systems built using dependency injection is that you get loosely coupled systems with well-defined interfaces that are easy to stub for testing. It is easy enough to provide stub implementations of these interface directly in the test classes, e.g. as anonymous implementations or inner classes. But despite this, I have found myself more and more starting to rely on Mockito for these situations, it's fewer lines of code, and very convenient!import static org.mockito.Mockito.mock;Now, as an example, we can use our ClientRepository instance to test a service class:
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.junit.Assert.assertEquals;
[...]
ClientRepository repository = mock(ClientRepository.class);
ClientId clientId = new ClientId(123);
Client client = new Client(clientId, new Name("Test", "User"));
when(repository.findById(clientId)).thenReturn(client);
FancyService service = new FancyServiceImpl();When stubbing like this we are usually not that interested in verifying behaviour of the stub. But if we, for some reason, would like to explicitly make sure that the method
service.setRepository(repository);
assertEquals(client, service.findClientAndDoSomethingTrulyAwesome(123));
findById(...)
was called, we can do this with the following line of code:verify(repository).findById(clientId);
Stubbing concrete classes
Now and then you encounter API:s that were not as designed for testing that you could wish for. In these cases, the possibilities of stubbing concrete classes can be very helpful.Restlet
Restlet is a Java framework for creating RESTful web service. Reslet consists of quite a big API, and the authors have, among other things, decide to create their own implementation of things likeRequest
, Response
, Status.SUCCESS_OK
(HTTP response 200) etc. Unfortunately, many parts of the API consists of concrete classes, instead of interfaces. One downside of this is that it is sometimes hard to write tests for code that uses the Restlet APIs.Stubbing the concrete class
org.restlet.data.Response
is easily done in the same way we stubbed the ClientRepository
interface above:import static org.mockito.Mockito.*;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.Representation;
[...]
Response response = mock(Response.class);
Representation entity = mock(Representation.class);
when(response.getStatus()).thenReturn(Status.SUCCESS_OK);
when(response.getEntity()).thenReturn(entity);
Quartz
Quartz is a scheduling component that is supported and also used by many popular application development frameworks and application servers, including Spring and Seam. When using Quartz you define jobs that execute according to a schedule. Every time a job is triggered a new instance of the job class is created, and executed. If state is to be saved between job executions it has to be stored in some kind data structure outside of the job. Quartz makes a context available,org.quartz.JobExecutionContext
, for this and other purposes. The context is handed to every newly created job instance. The context can, a bit simplified, be viewed as Map
where the job can store and retrieve data.If we would like to make data available to a job or read the result from a job execution we have to create an instance of
JobExecutionContext
and hand to our job. Creating this instance is however quite complicated, and since Quartz also tends to favor concrete classes over interfaces, it makes it hard for us to provide our own implementation. Fortunately, Mockito (or another mocking tool that can mock concrete classes) can help us out here as well!Use Mockito to setup the context and set a fictional
indexCount
parameter as input value to the job:import static org.mockito.Mockito.*;Now we can use the context in our test:
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
[...]
JobExecutionContext ctx = mock(JobExecutionContext.class);
JobDetail detail = mock(JobDetail.class);
JobDataMap map = new JobDataMap();
map.put("indexCount", 145);
when(detail.getJobDataMap()).thenReturn(map);
when(ctx.getJobDetail()).thenReturn(detail);
IndexUpdaterJob job = new IndexUpdater();And verify that the index was updated:
job.execute(ctx);
map = ctx.getJobDetail().getJobDataMap();
assertEquals(146, map.get("indexCount"));
Mocking
As the name suggests, Mockito can of course be used for different kinds of mocking as well. For more examples, have a look at the Mockito documentation.
Subscribe to:
Posts (Atom)