dimecres, 21 de setembre del 2016
dimarts, 13 de setembre del 2016
The one about estimates
Other: "How long will this take?"
You: "I don't know"
Other: "It's just a button like the other"
You: "I know it looks like the other button but there's a whole different list of things to consider"
Other: "But I need costs to prioritise"
You: "I understand, and I wish I could help you. You know I won't lower quality and you don't want scope being reduced... in that case time is an open variable."
Other: "Not again with the triangle thing. You've done that a thousand times, that's jour profession".
(pause for drama)
You: "Ok. Let's play this game. I've already told you about scope-quality-time, right?"
Other: "Yes"
You: "Ok, John/Jane/MrSmith... do you have kids?"
Other: "Uuuh. Yes. How is that related?"
You: "Ok, let's imagine I asked how long will it take you to bath, feed and put to sleep tonight. I need to know so we can skype with Australia".
Other: "Uuuh... well, If we have to skype I can have my significant other to do it"
Other: "Uuuh... well, If we have to skype I can have my significant other to do it"
You: "Don't be a chicken. Give me the time when the kid will be bathed, belly-full and wonderfuly asleep"
Other: "9pm"
You: "exactly 9pm?"
Other: "9-ish"
Other: "9-ish"
You: "and bathroom is cleaned, kitchen is all cleaned up too, right? No traces of food on the wall or ceiling, right?"
Other: "Ok, maybe 9.30"
You: "9 or 9.30. You mentioned you start your routines at 7.30 so you just admitted to a 30% potential deviation."
Other: "err..."

This work is licensed under a Creative Commons Attribution 4.0 International License.
Other: "err..."
You: "But you do this everyday. Ok, forget about tonight. Let me ask you something different. What time will your kid be at kindergarten tomorrow?"
Other: "8.30 sharp"
Other: "8.30 sharp"
You: "not 8.35?"
Other: "No, 8.30 or they have shut the door"
Other: "No, 8.30 or they have shut the door"
You: "And the kid was perfectly dressed and ate everything you prepared for breakfast, right?"
Other: "Well, not always."
Other: "Well, not always."
You: "No traces of food on the wall or ceiling, right? Bed is made and there's no breakfast utensils laying around."
Other: "We have to make it to the 8.30 deadline"
Other: "We have to make it to the 8.30 deadline"
You: "But you do this every day. It's you field of expertise. Daily repetition, same tools, same team, same risks, ..."
Other: "yeahs, but kids... entropy."
Other: "yeahs, but kids... entropy."
You: "Daily repetition, same tools, same team, same risks, ... I don't deal with any of those simplifications. Plus I also get entropy, arguably smaller than the entropy generated by kids or toddlers, but entropy nonetheless."
Other: "Ok, but how long will this take?"
Special thanks to Roger Segura and Yorgo Saslis, their parenthood inspired this story.
DISCLAIMER: None of them are The Other in the story, they just happened to tell personal experiences that helped building the script.
Other: "Ok, but how long will this take?"
Special thanks to Roger Segura and Yorgo Saslis, their parenthood inspired this story.
DISCLAIMER: None of them are The Other in the story, they just happened to tell personal experiences that helped building the script.

This work is licensed under a Creative Commons Attribution 4.0 International License.
dilluns, 8 d’agost del 2016
jCrete 2016
Many harvested content, videos and other materials are available at: https://github.com/JCrete/jcrete2016
dimarts, 16 de desembre del 2014
CQRS Recipes (by @tjaskula)
Been trying to grasp my head around the DDD+CQRS+ES+CS+... concepts and finally found this step by step presentation:
Enjoy! PS: kudos tjaskula
Enjoy! PS: kudos tjaskula
dissabte, 30 d’agost del 2014
JCrete 2014
This post is, sort of, a reply to Geertjan’s post about JCrete (https://blogs.oracle.com/geertjan/entry/jcrete_2014).
Geertjan describes a group of trees and paths and a river and (purposely or not) lacks to mention he’s describing a forest. It’s great to have people with Geertjan’s reach to present and support this way of organising conferences, but I’d like to give my two cents on the subject.
Before continuing, let me say what Geertjan didn’t: "JCrete is a conference that uses Open Space Technology (http://en.wikipedia.org/wiki/Open_Space_Technology)”. A description like that is usually simplified as “FOO is an Open Space”. Hmm! We got rid of ’technology' and ‘conference’.
I’m still surprised to see the amount of people still unfamiliar with OpenSpace Technolgy, but that’s probably because we’ve been using a lot in Barcelona (more on that later), therefore I'm the weird one. As Dmitry said during the wrap-up, this format should be used all around and I completely agree to that.
But! I think wide adoption of Open Space Technology is still not possible, or that it should happen slowly.
Open Spaces don’t scale well. Even in JCrete things changed comparing 2012 edition and 2014. There were twice as many attendees and I’d say the number of people familiar with Open Space Technology is and how to *use it* remained the same (thus decreasing the %).
While preparing the main room on Sunday evening, some of the un-organizers and I went for a round gathering of chairs. That mutated the day after into a semi-circle around the screen the following days. Ok, we need to see code, it’s true. But then I noticed all rooms ended up in a similar layout. We are still too wired for the sit-and-listen conference format and unlearning this takes time.
In Agile Barcelona there’s been an open space every 6 months for the last few years. That led to some other communities (AngularJS, Java Hispano, Bcn Dev Con,…) to adopt it. The results are usually the same: people unfamiliar with the format, even when it’s explained (including 4 principles and law) still don’t grok it.
Open Space Technology is easy to explain but hard to use.
I think one of the reasons why people get so surprised in JCrete is because it’s an Open Space, not a Conference. What I’m trying to say here is that when a conference was publicised as a using Open Space Technology, attendees should only hear the ‘Open Space’ part. Actually, it might be a good thing to just use the two terms separately: Conference vs Open Space. These are not exclusive terms though. It’s possible to have the two mixed up: plain-old-cfp-talks-in-slots during the morning and open spaces during the afternoon (see for instance ALE 2014 program http://ale2014.alenetwork.eu/ale14-program/ ).
But I agree with Geertjan on that (1) morning open space followed by (2) at-the-beach, spontaneous sessions in the afternoon followed by (3) wonderful share-all food is plain genius.
PS: I was really surprised to see talks popup out of nowhere and happen on the so-called 'room 5' (see first picture of Geertjan’s post) as that is actually the ultimate ‘Open Space’.
dilluns, 18 d’agost del 2014
Baggage Collector Kata
I recently worked with a team trying to get them to grok some habits around testing.
One of the most challenging tasks was to make them learn to unlearn.
They know a lot about their business and so they know all exceptions to all the rules. This leads to overcomplexifying any solution. That leads to paralysis by analysis in some cases too. Since the problem we were using to practice testing was getting in the way again and again (due to corner cases) I decided we would ignore the problem and do a kata instead.
Since I also wanted them to do a kata similar enough to what they were trying to solve I just made one up on the spot and made it so that some problems in the kata were close enough to the actual problem.
DISCLAIMER: I know this intro is extremely vague. Just cut to the chase.
They know a lot about their business and so they know all exceptions to all the rules. This leads to overcomplexifying any solution. That leads to paralysis by analysis in some cases too. Since the problem we were using to practice testing was getting in the way again and again (due to corner cases) I decided we would ignore the problem and do a kata instead.
Since I also wanted them to do a kata similar enough to what they were trying to solve I just made one up on the spot and made it so that some problems in the kata were close enough to the actual problem.
DISCLAIMER: I know this intro is extremely vague. Just cut to the chase.
Baggage Collector Kata
Imagine you work at a baggage handling service of a regional airport in 1987. You spend your day taking bags that fall through a slide into a pile of baggage, from the pile to (a) the Hangars, (b) the baggage claim Hall or (c) Lost and Found.
Write the code so that a baggage is sent to the appropriate location:
- a baggage has a label with a FROM and TO
- a baggage whose FROM matches the current airport goes to the HANGARS
- a baggage whose TO matches the current airport goes to the HALL
(Hidden rule)
- all others go to LOST and FOUND
NOTE: The hidden rule was left out on purpose. I expected the team to notice there's cases not covered by the original set of rules and to (1) go ask the business expert (me) about what to do and (2) get a test for those cases.
Moving on to the future
While they were coding, I decided time was a variable to consider so I made it so each year would actually happen in 10 minutes. Meaning I added extra rules every 10 minutes.
Time goes by and the airport is being successful. Management is preparing some changes in order to make the airport an international hub.
Your team is merged with the Hangar's team. You now must:
- send baggages to appropriate HANGAR depending on the TO indicated on the label. That is, you no longer send baggages to HANGAR but you send them to HANGAR-8 or HANGAR-4, etc...
Also, you may start receiving bags that are on transit!
- a bag's label may now have several hops on the itinerary. Send bags to HALL if bag is on the last hop or send them to the appropriate hangar if current airport is on the itinerary.
-if the current airport is not on the itinerary, just move the bag to LOST and FOUND.
The Golden Years
The plan seems to be working and your airport is now an international airport! Kudos!
Here's some more considerations:
- if a bag FROM your airport will go abroad, you must send it to X-Ray and then to the appropriate Hangar
- a bag arriving (our airport is final destination) from a country abroad (original airport) then the bag must go to CUSTOMS and then to the HALL.
NOTE: At this point you can let your imagination flow and add all kinds of rules. For example:
- merge your team with lost-and-found teams so that if you receive a baggage you can re-route (even if you are not on the itinerary), just do it.
- make the hangar-to-flight mapping change during time. If a flight has a very early checkin, make it's baggage to the hangar even thought the plane is still not there or even if there's another plane there.
- remove all bags belonging to JACINTO RAMIREZ (a known drug dealer on Interpol's Most Wanted List)
Head fake
I used the kata as a way to get the team to get used to a set of simple rules changing very quickly. You can only go refactor crazy if your basic functionality is granted.
The original problem was simple and easy enough to reason about so as to dig deep into the possible corner cases it presented. We got into the exception handling quick enough. The message I was trying to pass on was: a simple problem is easy to reason but will surely have unspecified corner cases get your business expert in hand, find those cases quickly. Before you start coding your cathedral, step back and think of a good set of possible inputs and the expected outputs. If you find cases you can't answer to, get back to the business expert.
Also, your business will change soon enough and probably on a direction different than what you expected. Don't try to anticipate the future and keep you design simple and uncoupled so that it accepts change easily.
diumenge, 9 de març del 2014
My first take on reducing Garbage
I have been trying to grok several concepts regarding JIT, memory footprint, language abuse, mechanical sympathy, non-GC algorithms, etc... A problem I found is that there's so much to learn I was finding it hard to focus on a single idea and any attempt to do it faced a great difficulty to obtain clean info.
Few months ago I met Peter Lawrey of the http://vanillajava.blogspot.com and https://github.com/OpenHFT. At the moment I was not aware of who he was and so I missed the chance to ask him for some directions. Luckily enough, when I reach out to him earlier this year and presented my dilemma he was very kind and agreed to help. His first suggestion was to select one subject and then he offered to help me take small steps. The choice was no-GC algorythms and this is my first post on the subject.
First challenge is was presented was simple enough: "How can you iterate an ArrayList (without generating garbage)?". My first reaction was shock. It never occurred to me that a simple ArrayList iteration was creating garbage (which it sometimes is... not always...).
From the challenge I knew there's garbage on:
At Peter’s direction I run the code and then checked the output of jmap (http://docs.oracle.com/ javase/6/docs/technotes/tools/ share/jmap.html). After playing around with parameters I fired up a ‘watch’ on my command:
num #instances #bytes class name
------------------------------ ----------------
Now that I finally knew how to get some more insight re my memory usage and GC activity it was time to start searching for an alternative which didn’t generate Garbage. that was pretty easy:
List l = new ArrayList<>();
int lsize = l.size();
for (long i = 0; i < GAZILLION; i++) {
for (int j = 0; j < lsize; j++) {
}
}
Few months ago I met Peter Lawrey of the http://vanillajava.blogspot.com and https://github.com/OpenHFT. At the moment I was not aware of who he was and so I missed the chance to ask him for some directions. Luckily enough, when I reach out to him earlier this year and presented my dilemma he was very kind and agreed to help. His first suggestion was to select one subject and then he offered to help me take small steps. The choice was no-GC algorythms and this is my first post on the subject.
Simple Garbage generation
Demonstrating there’s Garbage
public static void main(String…args) {
List l = new ArrayList();
for (String s : l) {}
}
This can be verified with several methods but first thing that came to mind was running this main with params:
-verbose:gc -Xms4m -Xmx4m
which display the output:
...
[GC (Allocation Failure) 2436K->388K(5632K), 0.0003570 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004620 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004700 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004410 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0006780 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004480 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004540 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004570 secs]
…
which proves there's GC activity.
After a code review of the hotspot I found out the problem is caused in the foreach(). That is invoking ArrayList$iterator to iterate over the the list. In the (Hotspot) JVM that ArrayList$iterator returns a new instance of an inner class named ArrayList$Itr.
After checking out with Peter he confirmed I was on the right track but that I had to prove with a direct measure that my suspicion was correct.
[GC (Allocation Failure) 2436K->388K(5632K), 0.0003570 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004620 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004700 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004410 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0006780 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004480 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004540 secs]
[GC (Allocation Failure) 2436K->388K(5632K), 0.0004570 secs]
…
which proves there's GC activity.
After a code review of the hotspot I found out the problem is caused in the foreach(). That is invoking ArrayList$iterator to iterate over the the list. In the (Hotspot) JVM that ArrayList$iterator returns a new instance of an inner class named ArrayList$Itr.
After checking out with Peter he confirmed I was on the right track but that I had to prove with a direct measure that my suspicion was correct.
Observing the memory consumption
$watch “jmap -histo `jps|grep Main|awk -F\ '{print $1}’`"
With that I’d be constantly running jps and then filtering and asking to obtain y App’s PID. With my app’s PID I’d only need to jmap -histo.
With that I’d be constantly running jps and then filtering and asking to obtain y App’s PID. With my app’s PID I’d only need to jmap -histo.
num #instances #bytes class name
------------------------------
1: 65486 2095552 java.util.ArrayList$Itr
2: 6619 853136 < methodKlass >
3: 6619 764496 < constMethodKlass >
4: 456 538304 < constantPoolKlass >
5: 421 342368 < constantPoolCacheKlass >
6: 456 308984 < instanceKlassKlass >
7: 1373 135048 [C
8: 111 117992 [I
9: 702 116976 [B
...
What you don’t see in this output is that every 2 seconds (watch) the number of instances of java.util.ArrayList$Itr would change and increase until it’d disappear (GC wiping out old instances).
Go! Fire up your IDE of choice and try what we’ve done so far. I’ll wait.
2: 6619 853136 < methodKlass >
3: 6619 764496 < constMethodKlass >
4: 456 538304 < constantPoolKlass >
5: 421 342368 < constantPoolCacheKlass >
6: 456 308984 < instanceKlassKlass >
7: 1373 135048 [C
8: 111 117992 [I
9: 702 116976 [B
...
What you don’t see in this output is that every 2 seconds (watch) the number of instances of java.util.ArrayList$Itr would change and increase until it’d disappear (GC wiping out old instances).
Go! Fire up your IDE of choice and try what we’ve done so far. I’ll wait.
Finding an alternative without Garbage
Now that I finally knew how to get some more insight re my memory usage and GC activity it was time to start searching for an alternative which didn’t generate Garbage. that was pretty easy:
List l = new ArrayList<>();
int lsize = l.size();
for (long i = 0; i < GAZILLION; i++) {
for (int j = 0; j < lsize; j++) {
}
}
Believe it or not. This plain old for-loop is better in terms of garbage generation.
Actually, if you don't believe you can go fire up your IDE and check. ;-)
dimecres, 29 de gener del 2014
Scala code in Android app
I've been meeting Dani at several meetups in Barcelona lately.
We're both interested on scala but he also investigates the options to use it in android apps.
Last Saturday I remebered reading something about scala being used in android apps and tried to restore my notes to share them with Dani. Here's what I could recover:
ALERT: The following is a druid recipee based on maven.
Note: the previous uses a Mac OSX flavour 'sed' that requires an extra pair of simple quotes.
We're both interested on scala but he also investigates the options to use it in android apps.
Last Saturday I remebered reading something about scala being used in android apps and tried to restore my notes to share them with Dani. Here's what I could recover:
ALERT: The following is a druid recipee based on maven.
git clone git@github.com:jayway/maven-android-plugin.gitgit clone \git@github.com:jayway/maven-android-plugin-samples.gitcd maven-android-pluginmvn clean installcd ../maven-android-plugin-samples/cd scala/sed -i '' 's/2.8.0/2.10.3/' pom.xmlmvn clean installadb install -r target/scala-1.0.0-SNAPSHOT.apk
Note: the previous uses a Mac OSX flavour 'sed' that requires an extra pair of simple quotes.
dissabte, 25 de gener del 2014
DI and testing without mocking in Play!
At the scala developers barcelona meetup we are running monthly challenges. This month's challenge is to implement a REST API. Easy peasy.
At some point, akustik had a question about his approach in Play! and so asked for opinions on the mailing list. Turns out I had been over the same problems few weeks earlier at my (then) current project so offered to help. Since the answer is quite reusable I'm cross-posting here so that you can comment and discuss if my suggestion is actually correct. I worked may way into the solution to make sure I remembered all steps and the PR'd my code into the challenges github: https://github.com/scala-developers-bcn/challenges/pull/29
DISCLAIMER: I'm quite new to Play! and it's very possible there's a better way than what I suggest.
Dependency Injection and testing without Mocking in Play!
Play!'s Main Problem (TM) is the abuse of singleton objects for everything. While it's a great idea to create a single instance of anything and reuse it again and again it's also a problem to make everything object (scala equivalent for classes that contain only static methods). This object-based approach makes it difficult to inject instances at will.
Back to the trigger, here's akustik's question:
Dependency Injection
To escape the object singleton mess which forbids you from doing plain old DI you first have to convert you controllers from objects to classes.
(I'm not 100% of what I'll explain now)
But once you did that you have to prepend your routes mappings with an '@' sign. That causes you HTTP requests to request an instance to Play! The responsible to resolve the required instance is a thing** called GlobalSettings.
(back to 100% sure)
Then you have to create your subclass of play.GlobalSettings and then go to application.conf and specify what your Global class is. But you class controllers still use singleton repositories. Let's make the repos injectable. Add a constructor parameter to your controller:
class MyCtlr(repo:MyRepo) extends Controller
And now you made your controller unavailable because Play can't resolve the incoming requests. Here's where you go back to your Global class and override the method getControllerInstance so that any incoming request lets you decide what Controller to use. And there you have it!
Your Global soon becomes this:
def flightRepo = new InMemFlightsRepository
def flightCtlr = new FlightsCtlr(flightRepo)
override def getControllerInstance[A]( controllerClass: Class[A]): A = {
// extend here when adding more controllers... probably a pattern matching.
flightCtlr.asInstanceOf[A]
}
So far so good. We got ourselves so DI wonders.
(trolling mode on)
It's at this point where your Global should be renamed ApplicationContext and you should consider your:
def flightCtlr = new FlightsCtlr(flightRepo)
a synonim of: (blogspot won't let me use lt and gt)
bean id=flightCtlr class=controller.FlightsCtlr scope=request
constructor-arg="flightRepo"
You could have also done:
val flightCtlr = ...
which would be:
bean id=... class=... scope=singleton
Scala 1 - XML fuck you!... I mean 0
(trolling mode off)
Unit Testing (without mocking)
And so we end up on our wonderful test.
If you've read the Play docs you probably have a test that looks like this:
"return 200 on flights/" in {
running(FakeApplication()) {
val flights = route(FakeRequest(GET, "/flights")).get
...
Well, without you knowing it uses your Global class. The final trick to easily inject your Mock classes is to tell your Fake Application to use a different Global:
running(FakeApplication( withGlobal= Some(MockingGlobal() ) )) {
And that's it!
Well, no!
Oh God this is horrible!
** Remember when I said "a thing** called GlobalSettings" , well by thing I mean some bytecode that may be class or trait and I was being vague on purpose because there's both a class and a trait called
GlobalSettings and you'll need to use both to achieve DI and testing. To distinguish which GlobalSettings you are using pay close attention at the package.
So, to make your testing work you have to provide a MockingGlobal of yours which must mix-in play.api.GlobalSettings. I chose reusing my original Global class and just override a faked repository.
Again, while the running environment requires you to provide a subclass of play.GlobalSettings, FakeApplications expects an Option[play.api. GlobalSettings] (which is the trait). (Mother of Mercy this is wrong!)
I just go and extend and mixin to keep all my DI in a single place:
class MyGlobal extends play.GlobalSettings
with play.api.GlobalSettings { ...
and finally:
val globalForTest = new Global {
override def flightRepo = new InMemFlightsRepository {
override def loadAll(): List[Flight] =
List(Flight("ON_TIME","BOS", "CHG", "19B"))
}
}
Conclusion
Now, after this terrible mess lets puts this in context (no pun intended) and compare this with the 'easy' setup of a Spring-MVC app with testing and everything.
It's not much simpler but it's 100% scala so it must be cooler.
At some point, akustik had a question about his approach in Play! and so asked for opinions on the mailing list. Turns out I had been over the same problems few weeks earlier at my (then) current project so offered to help. Since the answer is quite reusable I'm cross-posting here so that you can comment and discuss if my suggestion is actually correct. I worked may way into the solution to make sure I remembered all steps and the PR'd my code into the challenges github: https://github.com/scala-developers-bcn/challenges/pull/29
DISCLAIMER: I'm quite new to Play! and it's very possible there's a better way than what I suggest.
Dependency Injection and testing without Mocking in Play!
Play!'s Main Problem (TM) is the abuse of singleton objects for everything. While it's a great idea to create a single instance of anything and reuse it again and again it's also a problem to make everything object (scala equivalent for classes that contain only static methods). This object-based approach makes it difficult to inject instances at will.
Back to the trigger, here's akustik's question:
I wanted to change [the controller] implementation for testing purposes without modifying the code nor changing to a variable and adding a setter.To which I could only reply:
You hit one of the big problems of Play! testing: there's no easyAnd finally found few minutes to properly solve the problem.
recommendation for unit testing. The path of objects and Integration
Testing is the default suggestion. Sad.
Dependency Injection
To escape the object singleton mess which forbids you from doing plain old DI you first have to convert you controllers from objects to classes.
(I'm not 100% of what I'll explain now)
But once you did that you have to prepend your routes mappings with an '@' sign. That causes you HTTP requests to request an instance to Play! The responsible to resolve the required instance is a thing** called GlobalSettings.
(back to 100% sure)
Then you have to create your subclass of play.GlobalSettings and then go to application.conf and specify what your Global class is. But you class controllers still use singleton repositories. Let's make the repos injectable. Add a constructor parameter to your controller:
class MyCtlr(repo:MyRepo) extends Controller
And now you made your controller unavailable because Play can't resolve the incoming requests. Here's where you go back to your Global class and override the method getControllerInstance so that any incoming request lets you decide what Controller to use. And there you have it!
Your Global soon becomes this:
def flightRepo = new InMemFlightsRepository
def flightCtlr = new FlightsCtlr(flightRepo)
override def getControllerInstance[A](
// extend here when adding more controllers... probably a pattern matching.
flightCtlr.asInstanceOf[A]
}
So far so good. We got ourselves so DI wonders.
(trolling mode on)
It's at this point where your Global should be renamed ApplicationContext and you should consider your:
def flightCtlr = new FlightsCtlr(flightRepo)
a synonim of: (blogspot won't let me use lt and gt)
bean id=flightCtlr class=controller.
constructor-arg="flightRepo"
You could have also done:
val flightCtlr = ...
which would be:
bean id=... class=... scope=singleton
Scala 1 - XML fuck you!... I mean 0
(trolling mode off)
Unit Testing (without mocking)
And so we end up on our wonderful test.
If you've read the Play docs you probably have a test that looks like this:
"return 200 on flights/" in {
running(FakeApplication()) {
val flights = route(FakeRequest(GET, "/flights")).get
...
Well, without you knowing it uses your Global class. The final trick to easily inject your Mock classes is to tell your Fake Application to use a different Global:
running(FakeApplication( withGlobal= Some(MockingGlobal() ) )) {
And that's it!
Well, no!
Oh God this is horrible!
** Remember when I said "a thing** called GlobalSettings" , well by thing I mean some bytecode that may be class or trait and I was being vague on purpose because there's both a class and a trait called
GlobalSettings and you'll need to use both to achieve DI and testing. To distinguish which GlobalSettings you are using pay close attention at the package.
- To override Global for you app extend play.GlobalSettings
- To inject a MockGlobal into FakeApplication when testing mixing play.api.GlobalSettigns
So, to make your testing work you have to provide a MockingGlobal of yours which must mix-in play.api.GlobalSettings. I chose reusing my original Global class and just override a faked repository.
Again, while the running environment requires you to provide a subclass of play.GlobalSettings, FakeApplications expects an Option[play.api.
I just go and extend and mixin to keep all my DI in a single place:
class MyGlobal extends play.GlobalSettings
with play.api.GlobalSettings { ...
and finally:
val globalForTest = new Global {
override def flightRepo = new InMemFlightsRepository {
override def loadAll(): List[Flight] =
List(Flight("ON_TIME","BOS", "CHG", "19B"))
}
}
Conclusion
Now, after this terrible mess lets puts this in context (no pun intended) and compare this with the 'easy' setup of a Spring-MVC app with testing and everything.
It's not much simpler but it's 100% scala so it must be cooler.
dilluns, 20 de gener del 2014
dimecres, 8 de gener del 2014
More on Neo4J 2.x: Querying over labels
I'm just starting with Neo4J and got straight into v2.0 so my first models already use labels. I just got into a case where I expected labels be of help but not sure if what I want to do is possible. Let me explain:
THE DOMAIN
Let's imagine we modelled a food chain: (in pseudo-cypher)
(grass:Vegetable)-[:EATS]-(marie:Cow) (marie)-[:EATS]-(ferocious:Velociraptor) (marie)-[:EATS]-(joseph:Human)
DETECTING CANNIBALISM
Turns out the solution was right in my face... that is, in the docs.
MATCH (n)--(p)
WHERE labels(n) = labels(p)
RETURN n, p
Now, this works because I only added a label to each of my nodes but if I were to use labels aggressively this query would not solve my cannibalism detection.
divendres, 27 de desembre del 2013
Neo4j 2.0 - Indexing
NOTE: this post is the unexpected continuation to my yesterday's post on Neo4J. You might want to start there.
DISCLAIMER: I'm no expert on the technology and this is more of personal notes while I keep playing around and learning.
INDEXING
So I went on with Alberto's workshop slides to learn Neo4J to refresh my memory on the features until I reached a certain slide which used indexing:
START tom=node:node_auto_index(name="Tom Hanks")
MATCH (tom)-[:ACTED_IN]->()<- director="" span="">->
RETURN director.name;
I then tried to execute it and found a nasty error message:
Index `node_auto_index` does not exist
It is clear what the problem is: the index is missing. But considering it's the auto_index I was trying to use I assume there's no more indexing magic in Neo4J. I then started a pursuit to create an index so that I could reproduce what I had in Neo4J 1.9.x. I mean, it was clear to me now that if I wanted indexing over actors-name I would have to create it myself. So I started digging google to learn some more about indexing in 2.0.0.
Creating and using Indexes
First hit I checked on Indexing is a great webinar by Michael Hunger on new features in Neo4J. For what I could gather (in the matter of indexing) is that the main difference is that they are now truly indexes meaning once created they auto-magically maintained when data is updated/added. I deduce from that statement that this wasn't the case in previous versions. BTW, the index is maintained transactionally, the index is bound to the data transactionally.
So, to create an index you simply need to:
CREATE INDEX ON :Actor(name)
This approach really simplifies the queries so that my original Cypher query becomes:
MATCH (actor:Actor)-[:ACTED_IN]->()<- director="" span="">->
WHERE actor.name="Tom Hanks"
RETURN director.name;
which is simpler and also more aligned to what a SQL-John might expect. What happens under the covers is that Neo4J detects I'm filtering by a field (name) over a labelled node (actor:Actor) and then finds out there's an index by ':Actor(name)'. So, it goes and automagically tries to use it.
But it is flawed
Turns out when I tried try to create the index using:
CREATE INDEX ON :Actor(name)
it worked at indexing nothing because my dataset doesn't use labels. So I then tried to index anything by name:
CREATE INDEX ON :(name)
CREATE INDEX ON :*(name)
CREATE INDEX ON (name)
it was a total waste of time since indexing requires labels in Neo4J 2.0.x. (insert sadface here).
INTRODUCING LABELS!
Then, back on my quest to query using an index I noticed my only chance was to create a label and have all nodes that [:ACTED_IN] another node to be labelled as Actor. Turns out to be quite straight forward:
MATCH (actor)-[:ACTED_IN]->(movie)
SET actor :Actor
RETURN actor;
This finally created my label, which unblocked my power to created indexes which allowed to query using them.
FUTURE WORK
Some doubts I need to investigate further:
- The video mentions there's "no unique indexing yet" but the video is few months old now and is based on Neo4J 2.0.0-M0
- there's also a mention to 'simple lookups for now' and I wonder what that might mean.
- While reading the docs on indexing I noticed it is possible to force the usage of a given index when querying (which is wonderful and also expected by some SQL-John's).
- I read s/where it's possible to alter the indexing technology. That's definitely worth a look at.
dijous, 26 de desembre del 2013
Neo4j 2.0 - Setup and first impressions
During the Christmas Holidays I took some time to play around with Neo4J. This is not the first time I tinker with it but definitely the first time I do it unsupervised. I must say the first time I played around with Neo4J it was under @albertoperdomo 's guidance and it felt like a liberation after several years of RDBMS.
DISCLAIMER: I'm a total newbie at Neo4j so don't take my advice for anything I'll be writing, this post is more of a compendium of notes for myself to check in the future.
INSTALLING
Installing any version (I needed 2.0.0) of Neo4J is insultingly simple thanks to @thedevel script: ndm. I even tweeted about it (again, for my own reference). Let me point out that even manually, isntalling neo4j is really simple.
IMPORTING MOVIE DATABASE
During Alberto's workshop intro to Neo4J we had a lot of small quizes so that each would have to keep on investigating and putting small concepts into practice. My idea to start playing around with Neo4J was to load that clean movie database, refresh some concepts from the notes I took during the workshop and then try to move on from that point.
First issue I faced with new features in Neo4J 2.0.0 were small syntax changes causing the load of a 1.9.3 database to fail. It's ended up being something quite silly though. What used to be:
now turned into:
START n=node(*)
MATCH (n)--()
OPTIONAL MATCH ()-[r]-()
DELETE r,n
There seems to be 2 differences:
START n=node(*) MATCH (n)-[r?]-() DELETE r,n;
now turned into:
START n=node(*)
MATCH (n)--()
OPTIONAL MATCH ()-[r]-()
DELETE r,n
There seems to be 2 differences:
- the trailing semicolon seems to be unnecessary now. It was causing a parsing error when reading the following line which caused the error message to be miss-leading since it pointed me in the wrong direction. I finally noticed the error message made no sense and tried to remove the semi-colon. It worked.
- Second thing is the replacement of '?' char to mark 'r' relationship optional in the query. Optional matcher's syntax seems to be new (or restricted to): OPTIONAL MATCH. I then replaced the edge from the query MATCHer and created an OPTIONAL MATCHer for it. It worked but I really doubt the two queries (old 1.9.x vs new 2.0.x) do the exact same thing. What I intended was to delete everything and that's what happens, but that's not enough proof to be satisfied with the rewrite.
(I'm not sure I can freely distribute the movies.cyp database) :-(
FIRST IMPRESSIONS
FIRST IMPRESSIONS
- The web console has improved incredibly. It was a great tool already but it is now beyond awesome. You can judge yourself:
- not only the tabular data presentation provides a clearer view of the schemaless data,
- you can now peek at the results in graph view
divendres, 20 de setembre del 2013
Parallel collection manipulation in scala
Scala collections API comes packed with a very cool feature which is parallelizing any processing. See this example:
I first create a list (I could use a range or s/thing else too):
scala> List(1,2,3,4,5,6,7,8,9)
res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
... and then build the skeleton of my processing. What I want to to multiply each value by 1000 and then divide each value by 500:
scala> res0.map{
i => i*1000
}.map{
i => i/500
}
res1: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18)
Nothing fancy so far.
Entering par
In scala every collection can be automagically wrapped into a counterpart that implements processing with a thread pool. I actually have no clue what the implementation is. Damn! I'll have to look it up. Anyway, insert 'par.' on your code and...
scala> res0.par.map{
i => i*1000
}.par.map{
i => i/500
}
res2: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(2, 4, 6, 8, 10, 12, 14, 16, 18)
... the list becomes a ParVector and keeps all items sorted in the original position.
Let's try and see it in action: (added random sleep to 'help' context switching)
scala> import java.util.concurrent.TimeUnitimport java.util.concurrent.TimeUnit
scala> import java.util.Random
import java.util.Random
scala> new Random
res6: java.util.Random = java.util.Random@b9d964d
scala> res0.par.map {
i => TimeUnit.MILLISECONDS.sleep(res6.nextInt(1000));
println(i);
i*1000
}.par.map{
i => TimeUnit.MILLISECONDS.sleep(res6.nextInt(1000));
println(i);
i/500
}
3
7
4
5
8
2
1
9
6
7000
3000
5000
4000
1000
6000
8000
9000
2000
res13: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(2, 4, 6, 8, 10, 12, 14, 16, 18)
scala>
Ta dah! Execution is run in parallel.
I first create a list (I could use a range or s/thing else too):
scala> List(1,2,3,4,5,6,7,8,9)
res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
... and then build the skeleton of my processing. What I want to to multiply each value by 1000 and then divide each value by 500:
i => i*1000
}.map{
i => i/500
}
res1: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18)
Nothing fancy so far.
Entering par
In scala every collection can be automagically wrapped into a counterpart that implements processing with a thread pool. I actually have no clue what the implementation is. Damn! I'll have to look it up. Anyway, insert 'par.' on your code and...
scala> res0.par.map{
i => i*1000
}.par.map{
i => i/500
}
res2: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(2, 4, 6, 8, 10, 12, 14, 16, 18)
... the list becomes a ParVector and keeps all items sorted in the original position.
Let's try and see it in action: (added random sleep to 'help' context switching)
scala> import java.util.concurrent.TimeUnitimport java.util.concurrent.TimeUnit
scala> import java.util.Random
import java.util.Random
scala> new Random
res6: java.util.Random = java.util.Random@b9d964d
scala> res0.par.map {
i => TimeUnit.MILLISECONDS.sleep(res6.nextInt(1000));
println(i);
i*1000
}.par.map{
i => TimeUnit.MILLISECONDS.sleep(res6.nextInt(1000));
println(i);
i/500
}
3
7
4
5
8
2
1
9
6
7000
3000
5000
4000
1000
6000
8000
9000
2000
res13: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(2, 4, 6, 8, 10, 12, 14, 16, 18)
scala>
Ta dah! Execution is run in parallel.
See more information re Parallel Collections on the overviews of the Scala Docs.
PS: For the curious...
If I get rid of the first 'par', the first processing is sequential, and the delays add up.
scala> res0.map { i => TimeUnit.MILLISECONDS.sleep( res6.nextInt(1000) );println(i) ;i*1000}.par . map { i => TimeUnit.MILLISECONDS.sleep( res6.nextInt(1000) ); println(i); i/500 }
1
2
3
4
5
6
7
8
9
5000
2000
1000
6000
3000
4000
9000
7000
8000
res17: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(2, 4, 6, 8, 10, 12, 14, 16, 18)
dijous, 1 d’agost del 2013
SBT and ScalaTest and a strange exception
After few weeks developing in Play! at some point today I started getting an Exception out of nowhere.
[info]
Exception in thread "Thread-109" java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2577)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1315)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at sbt.React.react(ForkTests.scala:98)
at sbt.ForkTests$$anonfun$apply$2$Acceptor$2$.run(ForkTests.scala:66)
at java.lang.Thread.run(Thread.java:722)
[info] Passed: : Total 23, Failed 0, Errors 0, Passed 23, Skipped 0
[info]
Exception in thread "Thread-109" java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2577)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1315)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at sbt.React.react(ForkTests.scala:98)
at sbt.ForkTests$$anonfun$apply$2$Acceptor$2$.run(ForkTests.scala:66)
at java.lang.Thread.run(Thread.java:722)
[info] Passed: : Total 23, Failed 0, Errors 0, Passed 23, Skipped 0
Strangely enough it would be thrown on every test execution but all tests pass (see last line).
Turns out it's a known (and already fixed) issue in sbt 0.12.2 so that was only a matter of updating:
# sed -e 's/0.12.2/0.12.3/g' project/build.properties
dissabte, 18 de maig del 2013
Word Wrap #katayuno
I finally got the chance to attend a Softonic's Katayuno.
I love the Coding Dojo's in general, but those organised at Softonic are special because of their office decoration (out of the average) and because they're breakfast.
Once I got at Softonic I must say the ambient, even with an empty office, felt different from many other companies I had visited before. The place is clean, ample and colorful you also have to consider the fact that's we were at story 9 which is over the average building height in Barcelona so the view was also quite stunning. Yes, you can see the sea from the dinner. And yes, there's a dinner.
Back to work
We got to work and after fiunchinho's introduction to TDD and red-green-refactor warmed-up on a first 30 minute pomodoro. The problem at hand was the KataWordWrap which fiunchinho selected specially for it's simplicity. It's not that he thinks we are stupid (which we are) it's that eh wanted us to complete the kata for once. SPOILER some of the pairs did complete the kata so fiunchinho just got a badge unlocked!
I paired twice in Java and after the break I paired once in scala. I'm still not very fluent in scala but I'm happy to report that we completed the kata in scala in little over a pomodoro (and I think we got further than previous pomodoros too!). Here's the final code:
This last session I paired with dvillacampa that is completely new to scala. I must say he very patiently listened to all my funoby comments about the language.
I love the Coding Dojo's in general, but those organised at Softonic are special because of their office decoration (out of the average) and because they're breakfast.
Once I got at Softonic I must say the ambient, even with an empty office, felt different from many other companies I had visited before. The place is clean, ample and colorful you also have to consider the fact that's we were at story 9 which is over the average building height in Barcelona so the view was also quite stunning. Yes, you can see the sea from the dinner. And yes, there's a dinner.
Back to work
We got to work and after fiunchinho's introduction to TDD and red-green-refactor warmed-up on a first 30 minute pomodoro. The problem at hand was the KataWordWrap which fiunchinho selected specially for it's simplicity. It's not that he thinks we are stupid (which we are) it's that eh wanted us to complete the kata for once. SPOILER some of the pairs did complete the kata so fiunchinho just got a badge unlocked!
I paired twice in Java and after the break I paired once in scala. I'm still not very fluent in scala but I'm happy to report that we completed the kata in scala in little over a pomodoro (and I think we got further than previous pomodoros too!). Here's the final code:
This last session I paired with dvillacampa that is completely new to scala. I must say he very patiently listened to all my funoby comments about the language.
dimarts, 8 de maig del 2012
Simple Build Tool
Today I finally jumped into using sbt.
I found how to get it and how to setup my machine at it's GitHub documentation (https://github.com/harrah/xsbt/wiki/Getting-Started-Setup), and now trying to make it work with my current code (https://bitbucket.org/ignasi35/scala-eclipse).
The main reason why I chose to test sbt is the continous testing:
I found how to get it and how to setup my machine at it's GitHub documentation (https://github.com/harrah/xsbt/wiki/Getting-Started-Setup), and now trying to make it work with my current code (https://bitbucket.org/ignasi35/scala-eclipse).
The main reason why I chose to test sbt is the continous testing:
- you can have sbt continually running (actually waiting for you to change something) and it will notice when something changed and compile and run it's tests. Actually, that's just a case of the actual feature: continous
so you are not limited to continous testing.
dissabte, 28 d’abril del 2012
Reactor Pattern
It's been long since I last wrote in english (probably never) but I found today was a good day to take this nack (start anew).
I read lately a lot about programming languages. Being a 100% JAVA (lazy) guy I never found the right moment to start. Finally via Coding Dojo's at Run Room with the people from Agile Spain I lost fear and made the first step.
I'm currently focused on Scala. I chose an OOP+Functional to start with and discovered it's scripting too !?!?. I made that choice after I had my attempts the past with python (scripting) and found that learning paradigm and API all at once was too much for me. Having JAVA's API in Scala world is really helping.
But let's get back to the subject of the post.
Something I've been paying some attention involuntary is the reactor pattern. I read from it today at aitorciki's post on concurrency inabout python and there I learnt that it's what Node.Js is actually doing. That struck me. I had read about Twisted and also had seen Node.Js code but failed to see the pattern there. I'll now get to the theory and will start digging.
I read lately a lot about programming languages. Being a 100% JAVA (lazy) guy I never found the right moment to start. Finally via Coding Dojo's at Run Room with the people from Agile Spain I lost fear and made the first step.
I'm currently focused on Scala. I chose an OOP+Functional to start with and discovered it's scripting too !?!?. I made that choice after I had my attempts the past with python (scripting) and found that learning paradigm and API all at once was too much for me. Having JAVA's API in Scala world is really helping.
But let's get back to the subject of the post.
Something I've been paying some attention involuntary is the reactor pattern. I read from it today at aitorciki's post on concurrency inabout python and there I learnt that it's what Node.Js is actually doing. That struck me. I had read about Twisted and also had seen Node.Js code but failed to see the pattern there. I'll now get to the theory and will start digging.
dijous, 11 d’agost del 2011
Cassandra
Fa unes setmanes que estic llegint Cassandra: The Definitive Guide [Kindle Edition]. A veure quan trobo l'excusa, el temps i els recursos per a posar en pràctica el que hi estic aprenent.
NOTA: Allí hi he descobert els Bloom Filters i he recuperat l'interès per les estructures de dades.
NOTA: Allí hi he descobert els Bloom Filters i he recuperat l'interès per les estructures de dades.
Subscriure's a:
Missatges (Atom)


