Sunday, December 4, 2016

Using groovy for tests

While I already has some exposure to dynamic languages - also those working under control of JVM, until now I had not touched Groovy, despite its presence on JUG meetings, conferences etc. I could of course see lot of value in tools like Spock, Geb or recently popular Gradle. However that was for me more a nice-to-have, rather than a must.
So with pleasure I am now discovering really nice points of using Groovy - as language that powers the tests and complements the Java main sources. It turns out that even with no frameworks mentioned above, you can benefit just from using Groovy in your test. Here are the reasons:
  1. You already know almost all of syntax. Old good Java code will probably just work. It is not like JavaScript, which is similar to Java just in name. Rest things you need you can find in documentation - which is quite good and answers most of my questions.
  2. Forget semicolons, alias imported objects, use list and map literals, multiline strings, use def. Almost like Scala.
  3. No more @VisibleForTesting. Groovy allows you to break object members visibility. Maybe it is not best idea to look into internal state of objects, but now you can. At least tested methods do not need to be kept in package visibility.
  4. Power assert. This looks just like Java assert. But output on your console when there is a failure... I just love this feature. Just take a look:
    Assertion failed:
    assert apiResponse.code() >= 200 && apiResponse.code() < 300
           |           |      |      |  |           |      |
           |           404    true   |  |           404    false
           |                         |  retrofit2.Response@42d0a255
           |                         false
  5. BigDecimal everywhere. 42.0 is not a float any longer. If your code has something in common with money you can feel relief.
  6. @TypeChecked. Why not just use compiler? With Groovy you can! It is so nice when machine corrects your errors.
I am not convinced whether Groovy is language of future :> But definitely worth trying.

Friday, October 7, 2016

IT Aristocracy to guillotine! How to treat IT head hunters?

Recently JUG in Warsaw published a newsletter containing quite an unusual link to an article created by a professional IT recruiter. The author is asking a very interesting question - why is she and her colleagues regulary offended by potential candidates, who are belonging to group of best educated engineers, holding lucrative position on job market. Top rated IT people. The "IT Aristocracy". I was touched. So I decided to appeal, to you readers.

Dear programmers!

I know you get 100 calls from desperate head hunters each week. I am aware, they are disturbing our flow of mind and taking us from zone away so we need to spend counterproductively next half hour to recover. But, hey, isn't that you who posted your phone/email on linkedin and N other jobboards along with shiny CV full of keywords? Is it more or less ridiculous than guys posting their ID into facebook? Have you expected that none of invited to your professional/social network recruiters ever call you? They may of course have sometimes be prepared to talk to you less than expected. Not knowing all that 3,4 letters acronyms and not knowing technology stack. That's right. They have no clue. That is why YOU are doing the job worth 6x more that what people you talk to by phone earn. They just have not dedicated half of their lives to profound depths of technological magic.
Nothing bad will happen also when we expose unprofessional behavior on the other side and talk about problems in our two-way communication. I am also aware not everyone is able to do it in such an elegant form as Rafal did.
Sometimes all of us have bad day, or just have been contacted by company which fired them 3 years ago. I can understand that each of us could behave less professionally in some conditions. Me too. I am sure that soft-skilled recruiters are also able to understand and forgive that.
But primitive, vulgar offence is not "unprofessional behavior"! That is not acceptable! Das ist unglaubich!!! That kind of freaks must be stigmatized!
Otherwise we, as the "computer people" will receive back from our society just hatred for being vulgar jerks. Just imagine that could have happened just before this or next government is run out of (our...) money and seeks for new taxpayers. Who will be the most unpopular group in our society? Whose heads will that revolution demand? Are you ready for fiscal guillotine?
One day, sooner or later, you will be looking forward to change your job. One day you will wish the head hunters to call you, and treat you not like just one more CV from million. That people are really able to help you get where you want. Unless you're a dick.
TL;DR If you are frustrated buy the rubber duck! Never offend head hunters.

Thursday, May 19, 2016

Changing merge request target branch in gitlab

Yes, it's possible with API usage.
There is even a script that chamges target branch with minimal configuration.

Gitlab is increasingly popular alternative for Github, commonly used by corporations that are able to save monthly fee for Github. It's open source project and front end and its usability seems to be still behind commercial and successful predecessor.
In my opinion Merge Requests are functionality that is exceptionally affected by suboptimal design. You just need to get used to it and train yourself not to click big green 'Click me' button, which causes MR to be merged. And changing the target branch of merge request seems to be impossible.
Thanks to careful readers among my colleagues, I have found out that this option exists, however only way to do it is to use Gitlab API. The API (similarly to Jenkins) utilizes concept of private token. It is a secret that allows a user to authenticate using unique token instead standard username and password. Maybe it is not most secure way, but certainly that is easy and convenient. Each HTTP request to Gitlab API that is performed in some user context, must contain that private token. It may be sent as a header or url parameter. Depending on your deployment configurationone of that ways may or may not be disabled ;> Url parameter worked for me quite well.
To edit a Merge Request we need to know project it relates to, as well as MR identifier, which is not same as visible in GUI (that one is referred to as iid, unique in project scope).
Operation will take 3 HTTP calls. First is ment to retrieve project id by its name.
GET /projects/search/:name_to_find
I assume there are no more than one projects found by given name.
Second will convert id from GUI to MR id.
GET /projects/:id/merge_requests?iid=42
or you can select manually from all opened MRs.
GET /projects/:id/merge_requests?state=opened
Knowing project id and MR id we can now update target branch by sending simple json object carrying new target branch as a value.
PUT /projects/:id/merge_request/:merge_request_id
{ "target_branch": "the_target_br" }
In my case I had to remove plural form `s` from merge_requests in url (that was different from API documentation, but I assume it's change in some other version of Gitlab). I was happy this option was possible, however I must admit I had to write the script to make the changing user friendly.

Saturday, April 2, 2016

massive directory name case change

Some time ago I had a disk failure. One project code was affected. I managed to restore almost all data, but result was often a file with name changed to upper case. As this happened to a windows machine, I could probably live with that, but it turned out package name in java is case sensitive, and Idea was not able to do quick fix as quickly as I would expect. Manual change is not an option for a developer.
So let's automate that. Solution would be to recursively visit each directory and in case its case is wrong - rename. You can have that in java, I would rather be happy to have that in script, however I am not sure whether scripting cmd or bash port on windows will actually handle that rename sanely.
Fortunately there is nice tool in python that accomplishes the same goal - os.walk. Usage is trivial and script is portable to any platform. File system paths can be also abstracted easily with os.path.join. There is even a method in python string that checks case of whole content - so you will not write any extra loop iterating over characters. Python handles nicely filtering in list comprehensions - so it is possible to use the condition in for statement.
from os import walk, rename
from os.path import join

for (dirpath, dirnames, filenames) in walk( join('src', 'main', 'java') ):
  for d in [f for f in dirnames if f.isupper()]:
       rename(join(dirpath, d), join(dirpath, d.lower()))
As you can see some APIs may be even more developer friendly than what is in Java standard. Now came the difficult part - for some reason git was unable to recognize character case change in filenames. It happens that some default on windows is aligned with os approach to case sensitivity. Making git see the difference is changing its configuration:
git config core.ignorecase false

Monday, March 21, 2016

Guava's Optional defficiencies

TL;DR: There is no reason to use Optional from Guava, Java 8 is better.

Guva used to be a most handy toolbox for modern (post-Java 5) projects. It was able to leverage new features and quickly became even more popular than old, good apache-commons (in my opinion some commons classes are still indispensible). Lot of ideas introduced by googlers behind Guava were incorporated into  official Java releases (mostly 8, however in 7 you may find some pieces of API visibly inspired by spirit of Guava helpers).
One of most popular innovations was Guava's approach to bringing Scala's Option[T] into world of Java. I assume idea is known and I hope also readers would agree with me that derogating `null` values would be a benefit for each developer as well for end users. After very enthusiastic reception, some critical voices could have been heard. Namingly Guava's Optional was missing important feature to call it a monad. That was an offence to real functional programmers.

Copernicus agreed with Guava guys - no Flat Map!

Is that problem really that severe? Well, Optional is by now integrated very well with other nice Guava's classes. This is still tempting to use it along with eg. FluentIterable, which has brought Stream-alike API into pre-Java 8 development. It can greatly be used to address deficiency mentioned above. Consider following code:
public static <In, Out> Optional<Out> flatMap(Optional<In> in, Function<In, Out> function) {
  Function<Out, Iterable<Out>> asIterable = asIterable();
  return FluentIterable.from(in.asSet()).transform(function).transformAndConcat(asIterable).first();

private static <In> Function<In, Iterable<In>> asIterable() {
  return new Function<In, Iterable<In>>() {
    @Override public Iterable<In> apply(In input) {
       return Optional.fromNullable(input).asSet();

Using the function above we managed to implement quite succint version of `flatMap` for Optional. We could now conclude, everything's fine, we have our monad now, and everyone's happy.
There is more problematic issue with this implementation.
The issue that degrades Optional just to simple null pointer warning, built into static code inspection, similarily to what would we gained by declaring checked exception. It however is useless as a flow control tool. Something that we are used to when using Scala's Option, and also much better implemented in java.util.Optional. The very problem is that our `map` function (known here as `transform`) is not really working. Let's verify what would happen when passed an null value to a transformation.

public class BrokenGuava {
    public static void main(String[] args) {
        Optional<String> optional = Optional.fromNullable("aaa");
        System.out.println("optional = " + optional);

        Optional<String> transformed = optional.transform(x -> null);
        System.out.println("transformed = " + transformed);

which brings us the result of:

optional = Optional.of(aaa)
Exception in thread "main" java.lang.NullPointerException: the Function passed to Optional.transform() must not return null.
 at options.guava.BrokenGuava.main(
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(
 at java.lang.reflect.Method.invoke(
 at com.intellij.rt.execution.application.AppMain.main(

NullPointerException! The same one that we expected to get eradicated by using Optionals all around our code!
The standard has got it implemented in a much better way:

import java.util.Optional;

public class NotSoBrokenUtil {
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("aaa");
        System.out.println("optional = " + optional);

        Optional<String> transformed = -> null);
        System.out.println("mapped = " + transformed);

this time you can see:
optional = Optional[aaa]
mapped = Optional.empty

This time it worked much better. Maybe not perfect (as we have empty as result - this is good topic for some next post), but at least not exploded in runtime.
So... Price is the same, why whould I choose suboptimal solution? Time to mark Guava's Optional deprecated.

Wednesday, January 27, 2016

Idea: Ctrl+w considered harmful

After some years of using Eclipse as my IDE I have found myself being quite efficient in code production using that environment. My typical flow was like:
- code
- select
- extract variable/method
For selection of expressions I have been using Shift+Alt+UpArrow. It selects expression under a caret position, and each repetition will cause expanding selection to next lexical unit. Very useful.  For some time I could not find it in any other editor or IDE.
I used to be a bit affraid to loose my typing efficiency when some colleagues suggested me trying IntelliJ Idea. So I refused. Learning keymap of new IDE actually is a time consuming process and you may not feel instant gratification. And Idea's kyes seemed so weird to Eclipse guys. Also IDEA's supporters arguing that F6 changes name of file in Total Commander were... not really helpful.
I remember my first ride with IDEA during a code randori session. I switched to 'Eclipse keymap' just to edit code. It should just work like in Eclipse, right? So let's start with running some tests. Ctrl+x t. So easy. Wait! It deleted something. Damn! Code no longer compiles and public is getting bored. Not a nice first impression.
Well, today really lot of companies are using Idea, so if you want to smoothly fit into team's coding manner, probably you will end up using IntelliJ. It makes also sense to learn basic commands and shortcuts available out of the box, as non-default keymaps are not that well documented (refcards etc) and as I mentioned you will not feel like in Eclipse anymore.
And here comes the surprise: Idea also has my favourite word selection feature built in. It's named 'expand selection'. A nice surprise. The bad part is how this shortcut is located. Namely Ctrl+w. Sounds like a crime, doesn't it? This very shortcut is something that was closing current editor tab at your previous IDE is now giving you a selection. Try using both IDEs (which I think initially everyone does when switching). What you have is getting some words selected when trying to close, and (while getting back to Eclipse) situation is even worse: you close your current tab when trying to select.
 You can think about the shortcut policy in Idea as a 'vendor lock in'. You just cannot switch to any other IDE after getting used to IDEA's native keymap. I believe at IntelliJ they call it feature.
But situation is even worse: this is not only about other IDE.
Every other program you use, and it supports tab view, probably uses Ctrl+w to close current tab. Last week when trying to select few words in Chrome browser I accidentally closed window I was working with. Such things are really disturbing and cause programmer to leave their 'zone' immediatelly. Too much for me.
But nice thing about IDEA is that you are able to turn the shortcut off. Today I visited Settings | Keymap, found 'Expand selection' and remapped to old, good shortcut from Eclipse. I should just have done it when starting with IDEA two years ago.