tag:blogger.com,1999:blog-59769977406017609262024-02-20T03:48:27.568+01:00software engineer's backlogUnknownnoreply@blogger.comBlogger34125tag:blogger.com,1999:blog-5976997740601760926.post-46301243888773492482023-09-10T18:03:00.001+02:002023-09-10T18:03:37.391+02:00Using .env with maven<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikAn4O5rr7tgujdiqIO-ev5d1KZfapfmiLMrMfedpC45tU1doK_hjdAmxbyEESKrMcVAUY9Q9aZ2pl1Ecqcd21rxENnOLIkDREqybRxu9qDUWfchxTYLO8D0NUjPlx8hW5L4LF8u98I8w01DIn99X_yJ_DPofoTO0qkOiWMXh4ti1sOS7VWuNsoX0Is9s/s324/dotenv.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="400" data-original-height="220" data-original-width="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikAn4O5rr7tgujdiqIO-ev5d1KZfapfmiLMrMfedpC45tU1doK_hjdAmxbyEESKrMcVAUY9Q9aZ2pl1Ecqcd21rxENnOLIkDREqybRxu9qDUWfchxTYLO8D0NUjPlx8hW5L4LF8u98I8w01DIn99X_yJ_DPofoTO0qkOiWMXh4ti1sOS7VWuNsoX0Is9s/s400/dotenv.png"/></a></div>
Dotfiles are quite popular in ruby and js ecosystem. <br>
They are not popular however in java world as we can use maven (still not 0xDEAD ;) and pass configuration directly from the command line or create script for that.
But why not take some standards from the other universes? <br>
Having other ways to configure app provided by eg. spring boot it may be still useful for java developers. <br>
<br>
You can use .env file to inject variables into your maven build, then it can get picked by spring boot and passed to configuration eg. while running tests. <br>
Use case is to avoid putting the secrets into version control, while letting local integration tests to run. Without any extra script files and using tool that is known by other developers.<br><br>
There is of course a maven plugin for that:
<pre class="brush:html"><groupid>io.github.mjourard</groupid>
<artifactid>env-file-maven-plugin</artifactid>
</pre>
I have prepared a small example of usage with groovy and spring boot. <br>
You can find it here: <a href="https://github.com/konopski/using-dotenv-with-maven">https://github.com/konopski/using-dotenv-with-maven</a>. <br><br>
It is a simplest spring boot application containing one bean (TheBean) which is using to configuration values. The very standard stuff to obtain a DB connection.
<pre class="brush:java">
@Component
class TheBean {
@Value('${spring.datasource.username}')
String username
@Value('${spring.datasource.password}')
String pass
//...
</pre>
Now spring lets us deliver the actual values using <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html" > externalized config mechanism </a>. Typically we use properties files and spring profiles. In our example there is a 'dev' profile defined, that provides a clear text password. It is good enough if you remeber to keep the dedicated profile properties file out of your version control. <br>
The file (application-dev.properties) can look like this:
<pre>
spring.datasource.password=secret
</pre>
In the main application.properties file we do not define this entry - so in case it is missing (eg. ommiting the profile) the app will not start.
<br><br>
You can also have another mechanism controlling your password. Spring will take a corresponding definition from system environment.<br>
In our case it is delivered by our .env file.
<pre>
SPRING_DATASOURCE_PASSWORD=t3st_s3cr3t
</pre>
That is verified in ApplicationTest class:
<pre class="brush:java">
@SpringBootTest
class ApplicationTests {
@Autowired TheBean bean
//...
@Test
void shouldReadFromDotEnv() {
bean.pass == "t3st_s3cr3t"
}
}
</pre>
We can also use different values by using spring's properties overriding, adding to our .env file:
<pre>
OVERRIDE_DB_PASS=password_override
</pre>
And test for that:
<pre class="brush:java">
@SpringBootTest(
properties = ['spring.datasource.password=${OVERRIDE_DB_PASS}'] )
class PropsOverrideTest {
@Autowired TheBean bean
//...
@Test
void shouldOverride() {
bean.pass == "password_override1"
}
}
</pre>
For me this approach is quite clean, allows easy sharing among the team and composes quite well with existing environment. <br>
And remember to keep your passwords away from git.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-81798599572906506322019-09-27T23:15:00.001+02:002019-09-27T23:15:04.099+02:00Map or any other option?
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE6SNuZxT5yKSmz1YwxYcnUVKuw-viVa-ofBAcm31eLVYeihHPXEMA8rYyK7TCeeCIrJDGQ1gz9PIwF3hzGbS6zvSQDHnV69Ubzn79gczU5W2RtAWnCTMRCzZchSHom55HX70zvlXHNu4/s1600/P_20190207_183206.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE6SNuZxT5yKSmz1YwxYcnUVKuw-viVa-ofBAcm31eLVYeihHPXEMA8rYyK7TCeeCIrJDGQ1gz9PIwF3hzGbS6zvSQDHnV69Ubzn79gczU5W2RtAWnCTMRCzZchSHom55HX70zvlXHNu4/s320/P_20190207_183206.jpg" width="520" height="280" data-original-width="1600" data-original-height="900" /></a></div>
I must admit that sometimes we can go too far with using Optionals as silver bullet. Let's take a look at a simple mapper class, defined like this:
<br />
<pre class="brush:java">class Mapper {
Optional<Dto> map(Optional<Entity> input) {
//... implementation
}
}
</entity></dto></pre>
At first passing an Optional instance looks like a good idea - we want to be safe from null values, we express our defensive intent in types. What can go wrong?
Let's now take a look at how this mapper may be used.
<br />
<pre class="brush:java">Entity entity = //...
Dto dto = mapper.map(Optional.of(entity)).get();
</pre>
Well, typical code involving the mapper is packing the input entity into an instance of Optional, just to get to output value.
Even worse could look usage for a collection.
<br />
<pre class="brush:java">List<entity> ents = //...
List<dto> dtos = ents.stream()
.map(Optional::of)
.map( x -> mapper.map(x) )
.map(Optional::get)
.collect(toList());
</dto></entity></pre>
Instead of using type system and compiler to our benefit, we lie about our input value - which we actually know that is never null. Not only we do not use the knowledge we already have, but put extra burden of reading through the wrapping on reader's eyes. I do not mention creating extra instances of Optional, and making common use of calling <code>.get() </code> - which is <em> not best practice</em>. I do not want to get familiar to that. <br>
What I also do not like in the code is forcing the user of our mapper to provide object wrapped into the very implementation of Optional. Actually mapper should not care which implementation of Optional I use. There are more than the standard one, and they may have some properties that are more useful for me in the context of my implementation. Last thing, we may observe here is that the API actually mimics what the Optionals are expected to provide - the map method itself. <br>
What we need is just:
<pre class="brush:java">
Dto map(Entity in) {
//....
}
</pre> That simple. <br>
Implementation of very mapping is what should be provided directly by mapper, without requirement for a wrapped value. We should require that value will be non-null. Optionality should be handled in client code somewhere else, we will not tolerate <code>null</code> values anyhow, right? Such mapper can be also easily used when applied to streams or collections. We save machine's memory from wrapping non-null values into Optionals and our precious eyes from reading the code that would cause the latter.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-39548947570102607002019-07-19T12:43:00.001+02:002019-07-19T12:46:17.435+02:00Woobie Doobie - switching database access library in ScalaDoobie is getting more and more popular as a database access tool in modern applications.
This year on <a href = "https://blog.softwaremill.com/scalar-2019-whiteboard-voting-40b31e4f7f7">Scalar conference voting Doobie won over its competition</a> - particularly Slick. Not without a reason. Recently my project also dropped Slick. <br>
Doobie gave us nearly immediately:
<li> easier learning curve - it is about plain, old SQL ;
<li> more compile time verification - now you do not need to run your query to find out your type mapping is broken ;
<li> referential transparency and better integration with effects system used in project ;
<li> no hacking needed when you need to select more columns than unfamous 22.
One particular issue that came out quite early was a bit tricky to resolve with given message:
<pre>
[error] Cannot construct a parameter vector of the following type:
[error]
[error] Boolean(true) :: shapeless.HNil
[error]
[error] Because one or more types therein (disregarding HNil) does not have a Put
[error] instance in scope. Try them one by one in the REPL or in your code:
[error]
[error] scala> Put[Foo]
[error]
[error] and find the one that has no instance, then construct one as needed. Refer to
[error] Chapter 12 of the book of doobie for more information.
</pre>
Studying chapter 12 did not help.
Here is the query that caused the issue:
<pre class="brush:java">
sql"select one_col, two_col from TABLE where flag = ${true} "
</pre>
It turns out that Doobie (actually Shapeless) does not handle properly the inlined <code>true</code> literal.
What is needed is just to extract it to separate value:
<pre class="brush:java">
val flag = true
sql"select one_col, two_col from TABLE where flag = ${flag} "
</pre>
That resolves the problem. It would also work if we added type annotation:
<pre class="brush:java">
sql"select one_col, two_col from TABLE where flag = ${true: Boolean} "
</pre>
It's up to you which way you prefer.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-85121265512925142912018-10-31T21:15:00.000+01:002019-01-28T11:49:35.034+01:00Remove one file from git commit to a remote branchOoops, I did it again. Commited and pushed one file too much.
<pre>
? git push --set-upstream origin bugfix/JRASERVER-65811
</pre>
What now? How to remove the file from a public commit?
<br/>
<img src="https://pbs.twimg.com/media/B093CwRCQAEwnD4.jpg" />
<br/>
Let's first go back to the base branch.
<pre>
? git checkout -
</pre>
<pre>
Switched to branch 'develop'
Your branch is up to date with 'origin/develop'.
</pre>
I assume I may have some changes in my local copy so first need to clean it.
I am going to delete my local branch.
<pre>
? git branch -D bugfix/JRASERVER-65811
Deleted branch bugfix/JRASERVER-65811 (was 5e17f72f).
</pre>
Next step is to synchronize with remote repository and fetch the branch again.
<pre>
? git pull
remote: Enumerating objects: 119, done.
remote: Counting objects: 100% (119/119), done.
remote: Compressing objects: 100% (119/119), done.
remote: Total 119 (delta 41), reused 0 (delta 0)
Receiving objects: 100% (119/119), 43.63 KiB | 1.82 MiB/s, done.
Resolving deltas: 100% (41/41), done.
From gitlab:project/frontend
736ac14a..ea0ba57e bugfix/JRASERVER-65811-allopenissues -> origin/bugfix/JRASERVER-65811-allopenissues
Already up to date.
</pre>
I can now switch to the branch back.
<pre>
? git checkout bugfix/JRASERVER-65811
Switched to a new branch 'bugfix/JRASERVER-65811'
Branch 'bugfix/JRASERVER-65811' set up to track remote branch 'bugfix/JRASERVER-65811' from 'origin'.
</pre>
Time to bring the last commit into staging.
<pre>
? git reset --soft HEAD^
</pre>
I can see this was done by showing status.
<pre>
? git status
On branch bugfix/JRASERVER-65811
Your branch is behind 'origin/bugfix/JRASERVER-65811' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: src/app/lktree/lktree.component.spec.ts
modified: src/app/modules/spaces/data/space-datasource.ts
modified: src/app/modules/spaces/document-details/document-details.component.html
modified: src/app/modules/spaces/spaces-tree/spaces-tree.component.ts
modified: src/app/modules/user-context/data/user-context-datasource.ts
</pre>
The first of files is the one I want to extract and unstage from to working copy. This simply undo <code>git add</code>.
<pre>
? git reset src/app/lktree/lktree.component.spec.ts
</pre>
Yeah! My changes are now in state I wanted!
<pre>
? git status
On branch bugfix/JRASERVER-65811
Your branch is behind 'origin/bugfix/JRASERVER-65811' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: src/app/modules/spaces/data/space-datasource.ts
modified: src/app/modules/spaces/document-details/document-details.component.html
modified: src/app/modules/spaces/spaces-tree/spaces-tree.component.ts
modified: src/app/modules/user-context/data/user-context-datasource.ts
Untracked files:
(use "git add <file>..." to include in what will be committed)
src/app/lktree/
</pre>
I can commit again - this time the right files.
<pre>
? git commit src/app/modules/spaces/ src/app/modules/user-context/data/user-context-datasource.ts -m "JRASERVER-65811: allopenissues"
[bugfix/JRASERVER-65811 80002b42] JRASERVER-65811: allopenissues
4 files changed, 60 insertions(+), 25 deletions(-)
</pre>
Last commit is to overwrite the remote branch. Do not do it at home ;)
<pre>
? git push --force
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-42644971452301377972018-06-22T10:48:00.003+02:002018-06-22T10:48:54.049+02:00Authenticating with deploy keys in Jenkins pipelinesWhile using M$ github you may use deploy keys dedicated to a specific repository instead of giving your private key to Jenkins. And yes, it is possible to use deploy key in Jenkins pipelines.<br />
<br />
To be able to manage your ssh identity you need first to install sshagent plugin.
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaaUUitHilHRLO4YnpdSzmlCw3etsXblvWlULI0H52-Dr0Gn3e7yL92DNGO9jqiFjR0lW7azjsZQ0on4UbOatRog677Jim3_Ka_mzZGkx4Ce5MM4CpTKBt94hOR7VV9xKqomfbtKoV1Hg/s1600/jenkins-sshagent-plugin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="561" data-original-width="790" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaaUUitHilHRLO4YnpdSzmlCw3etsXblvWlULI0H52-Dr0Gn3e7yL92DNGO9jqiFjR0lW7azjsZQ0on4UbOatRog677Jim3_Ka_mzZGkx4Ce5MM4CpTKBt94hOR7VV9xKqomfbtKoV1Hg/s1600/jenkins-sshagent-plugin.png" /></a></div>
<br />
<i><br /></i>
<i>BTW If you are running Jenkins instance on M$ windows machine remember to add sshagent (eg. from your git distribution) to your %PATH%.
</i><br />
<br />
<br />
<br />
Generate a key pair.
<br />
<pre>ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
</pre>
<br />
<br />
Goto Credentials in Jenkins left-side main menu. Add credentials of type 'SSH Username with private key'. You can paste the created private key into text area.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkiVtwroqH2Psi7daF4Sq_eUnL3KhcPurY2AYwLttI7M29-bB3yJvVu6sgVIlPScYgr9aVnBvX-ATyWwDkLNKGQpzQaDYemP9_6YcXfOiD3RiUiZGWRg9Vjb72oR5F0DD-F-i5A9FIi48/s1600/jenkins-add-credentials.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="658" data-original-width="869" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkiVtwroqH2Psi7daF4Sq_eUnL3KhcPurY2AYwLttI7M29-bB3yJvVu6sgVIlPScYgr9aVnBvX-ATyWwDkLNKGQpzQaDYemP9_6YcXfOiD3RiUiZGWRg9Vjb72oR5F0DD-F-i5A9FIi48/s1600/jenkins-add-credentials.png" /></a></div>
<br />
<br />
In M$ github repository settings now you can add corresponding public key.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfADd2-hC6IyYPtVL-1NNIj_wDi0fg4aZPU5PA1jLG752CqUodlJcoM-zHBP38QlNxA2-IZMN9NSM5hyphenhyphenahm4E84OiLq0kujXCCQIVnsvXg8xIMnPxDt7J-WOakEAhj4fuvHKfdcpWfWak/s1600/github-deploy-key.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="339" data-original-width="1019" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfADd2-hC6IyYPtVL-1NNIj_wDi0fg4aZPU5PA1jLG752CqUodlJcoM-zHBP38QlNxA2-IZMN9NSM5hyphenhyphenahm4E84OiLq0kujXCCQIVnsvXg8xIMnPxDt7J-WOakEAhj4fuvHKfdcpWfWak/s1600/github-deploy-key.png" /></a></div>
<br />
<br />
In your pipeline code you can use credentials when you surround eg. git calls with sshagent block.<br />
<br />
<pre> sshagent(credentials: ['throw-me-away-key']) {
bat """git pull origin master"""
}
</pre>
<br />
<br />
<br />
If you get errors make sure that you are not using friendly name but right ID of credential in Jenkins.
<br />
<br />
<br />
<pre>10:09:04 FATAL: [ssh-agent] Could not find specified credentials
10:09:04 [ssh-agent] Looking for ssh-agent implementation...
10:09:04 [ssh-agent] Exec ssh-agent (binary ssh-agent on a remote machine)
10:09:04 $ ssh-agent
10:09:04 SSH_AUTH_SOCK=/tmp/ssh-vCKYmwW5gfvP/agent.5592
10:09:04 SSH_AGENT_PID=5572
10:09:04 [ssh-agent] Started.
10:09:04 [original] Running batch script
10:09:04
10:09:04 C:\Program Files (x86)\Jenkins\workspace\lk-pipeline-0\original>git pull
10:09:06 $ ssh-agent -k
10:09:06 git@github.com: Permission denied (publickey).
10:09:06 fatal: Could not read from remote repository.
10:09:06
10:09:06 Please make sure you have the correct access rights
10:09:06 and the repository exists.
10:09:06 unset SSH_AUTH_SOCK;
10:09:06 unset SSH_AGENT_PID;
10:09:06 echo Agent pid 5572 killed;
10:09:06 [ssh-agent] Stopped.
</pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQCi3m3iuaEcNq0tMr9p3c9_Z3yq0zcf_HUp5t72xAUVhE0zGuHIiGf28U3brW1_iDcbEifu98JMzAR0IH5oudBtZlMyQbbcNmpajL4d51RWEpwwqUm5tLuFoo80-V-TINsogfvvkZ_EM/s1600/jenkins-credentials.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="1186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQCi3m3iuaEcNq0tMr9p3c9_Z3yq0zcf_HUp5t72xAUVhE0zGuHIiGf28U3brW1_iDcbEifu98JMzAR0IH5oudBtZlMyQbbcNmpajL4d51RWEpwwqUm5tLuFoo80-V-TINsogfvvkZ_EM/s1600/jenkins-credentials.png" /></a></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5976997740601760926.post-40652470295518917432018-01-12T18:32:00.001+01:002022-04-24T06:41:32.508+02:00OOP is not dead: Elegant ObjectsRecently I have observed a growing wave of what I describe as kind of <i>anti-design
movement</i>. Experienced people find out they have been doing it wrong. One say: <a href="http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html" target="_blank">TDD is dead</a>,
other: we do not need interfaces. <strike>Script kiddies</strike> Dynamic language
programmers claim strongly typed languages are broken. It comes even to a very last
discovery that <a href="https://medium.com/@copyconstruct/small-functions-considered-harmful-91035d316c29" target="_blank">short methods are pure evil</a>!<br />
I've just spoken to a programmer, who had nearly 20 years of
experience with Java, yet trying to convince me that interfaces are useless,
just because for that long time he had never written an alternative implementation
of method. In same conversation however, he praised ORMs for possibility of painless
exchanging of DB engine!<br />
The leitmotiv of this new heresy is that we can easily cut off the effort
introduced by OOP, design patterns, TDD, DDD or any other, until now considered a good practice and focus on delivering just what matters
- the `business value` itself. So that we can successfully bill the client and go to the
next project.
This sounds good.<b> That may make sense.</b> <b><span style="color: magenta;">If your project is not going to be
maintained for years, </span>please feel free to skip paradigms.</b> Use spaghetti
architecture. Use mixed javascript, php, perl and have fun with testing on production. Building a prototype
is a kind of development. Write once and dispose the code soon.
But in project that is planned for more than three months this approach is just as
wrong like murdering your client with an axe and taking their money. Just like
Vikings did.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a title="Jakub T. Jankiewicz, CC BY-SA 4.0 <https://creativecommons.org/licenses/by-sa/4.0>, via Wikimedia Commons" href="https://commons.wikimedia.org/wiki/File:Wolin_2018_04.jpg"><img width="512" alt="Wikingowie (Wolin 2018 04)" src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Wolin_2018_04.jpg/512px-Wolin_2018_04.jpg"></a>
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
It is all about maintainability.
If you use dynamic typing but do not cover your app with test, expect your
work will get broken by colleagues siting next to you and following your
discipline. If you do not use interfaces - I expect I know already
how your tests look like. Like `<span style="font-family: "courier new" , "courier" , monospace;">null</span>`. If you prefer not to extract method I
know how lightweight your code is. I have seen java class source code that had
over 1 megabyte! Imagine how fast you can deliver business value in such a
project. If you think design is a waste - yeah... I was there, I have seen important
application presenting different results on each subpage, thanks to `<span style="font-family: "courier new" , "courier" , monospace;">if</span>`
pyramid of doom, copied, pasted and happily living its own life.<b>
It does cost.</b> Believe me. Technical debt is not something that will disappear
by just forgetting the matter.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9cCXkrTkX-U2uLDKGckDl385xdm-sqMzeb4_OwHINTgZDK4WO9uWKNeEhY8hpizv7zWy3FXXfwGM4QeHHLyVIj5-GJ7YmDSYuMUF5iWsZGO_LvDKmtBBBJvy2NZj0XFDeTnglYJsuDwU/s1600/20170929_173025.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9cCXkrTkX-U2uLDKGckDl385xdm-sqMzeb4_OwHINTgZDK4WO9uWKNeEhY8hpizv7zWy3FXXfwGM4QeHHLyVIj5-GJ7YmDSYuMUF5iWsZGO_LvDKmtBBBJvy2NZj0XFDeTnglYJsuDwU/s640/20170929_173025.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Elegant Objects by Yegor Bugayenko gives you some kind of framework. By
following author's 23 pieces of advice you can learn how to use Object
Oriented Paradigm in real language like Java. Yegor conducts <b>personalized
object </b>(Mr. Object) through journey of life. The very similar way as we personalize actors using eg. Akka and follow some important rules - not forced by language itself. This concept seems to be core of author's approach to improve maintainability of software we create. When we interact with a person, we stick to some polite way of communication, assuming we are not talking to an idiot. Same holds for our objects.<br />
<br />
There are some other helpful tricks and lot of strong opinions on using some code constructs and patterns/antipatterns. The book gives number of easy to remember code examples. Explains or recall you why constructor injection is the only right way and why `<span style="font-family: "courier new" , "courier" , monospace;">static`</span> is not welcomed (even if we do now FP in Java). If you are more interested in the content of the book - I can recommend <a href="http://tomaszdziurko.com/2017/07/lobotomy-to-your-object-oriented-thinking-elegant-objects-book-review/" target="_blank">Tomek's review</a> and page of <a href="http://www.yegor256.com/" target="_blank">Yegor Bugayenko</a>.<br />
<br />
Some of author's rules I think may be a bit controversial and exaggerated - at least in context of my last project. The only point I really didn't like was actually Yegor's approach to C++, a bit unfair as this language can be as object oriented as Java is.<br />
<br />
I am not imposing that there is only one way to create maintainable software.
Whether you will use header files to separate contract from implementation or
will you use java interfaces or maybe free monads that define program
separated from its interpretation. It is up to you. But please, take some set
of rules, and keep to them in consistent manner. That is what your client pays
you for.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-76014791213387453612017-12-08T23:36:00.000+01:002018-01-14T16:02:00.017+01:00Always say "Junk fix", never "quick fix"<span -="" a="" affects="" an="" and="" as="" difficult="" entities="" important="" in="" is="" know="" name="" naming="" of="" our="" perception="" process.="" span="" things="" well="" yet="" you="">software development area - names are almost only context that can be added to a computation. By using common vocabulary we build shared understanding of how things work and what is their meaning. When we communicate with outside world using our language we also put a corner stone under the how eg. business people will be able to visualize system we are responsible for.<br />
<br />
One of the greatest examples of metaphor used to explain the nature of projects to stakeholders is a term coined by Ward Cunningham -<b> technical debt</b>. In very illustrative way it mimics well known figure of a financial debt to explain the costs or possible impact that unmaintained <span style="color: black;">software brings to owners.</span>
In the opposite pole I can see a term used so often, while bringing so much confusion and leading to misunderstandings and even conflicts in many organisations. <b>I mean the "quick fix"</b>. Quick and dirty, when we tend often to forget how dirty it was, leaving it in our software just to make it rot. Please keep in mind each time you say "quick fix" what you really communicate is "cheap fix". Is it what you meant? Will it be that quick in the final picture? Or it is just half done, ad hoc patch that will not consist solution, but maybe bring counter productive impact to changed process?<br />
<span style="color: black;"><br /></span>
<br />
</span><br />
<div style="text-align: center;">
<span -="" a="" affects="" an="" and="" as="" difficult="" entities="" important="" in="" is="" know="" name="" naming="" of="" our="" perception="" process.="" span="" things="" well="" yet="" you=""><a href="https://twitter.com/chopeh/status/926074073767206912/photo/1?ref_src=twsrc%5Etfw&ref_url=http%3A%2F%2Flkonopski.blogspot.com%2F2017%2F12%2Falways-say-junk-fix-never-quick-fix.html" target="_blank"><img alt="About the false velocity of quick fixes" border="0" data-original-height="482" data-original-width="503" height="306" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXekDQ1Y-HBUja_uhV8AVkxHisouV18qo2VU-be3MMVUN2FkB37SInrzO02Wg9kJmXvMuJmvvk070KCPowdwdMCTS6xzhyphenhyphen2pL4KtOBjBbdp9vPPUbuhU93k50_7l7bvvF6FC2UVVBm-0c/s320/fixing_fix.png" width="320" /></a>
</span></div>
<span -="" a="" affects="" an="" and="" as="" difficult="" entities="" important="" in="" is="" know="" name="" naming="" of="" our="" perception="" process.="" span="" things="" well="" yet="" you="">
Recently I have watched Netflix "Cooked" series of four, visually elaborated stories about food and eating. It was about the real food, that brings value to our life, as opposed to what is often offered to us, mass product of industry, optimized for price only, washed from nearly everything our body needs. The junk food.
</span><br />
<div class="separator" style="clear: both; text-align: center;">
<span -="" a="" affects="" an="" and="" as="" difficult="" entities="" important="" in="" is="" know="" name="" naming="" of="" our="" perception="" process.="" span="" things="" well="" yet="" you=""><a href="https://pbs.twimg.com/media/C3v8QYHW8AIqI6Q.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="800" height="300" src="https://pbs.twimg.com/media/C3v8QYHW8AIqI6Q.jpg" width="400" /></a></span></div>
<span -="" a="" affects="" an="" and="" as="" difficult="" entities="" important="" in="" is="" know="" name="" naming="" of="" our="" perception="" process.="" span="" things="" well="" yet="" you="">
<br />
I find this being a perfect metaphor to what is often offered as a "quick fix". This word junk explains exactly nature of the fix without giving a false assumption that anything cheap is being discussed. Let's be clear about it.</span>
<b>It is a "junk fix", not "quick fix".</b>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-69232473044079820502017-11-12T14:54:00.000+01:002017-11-12T14:54:00.430+01:00Stand IT up!Recently I had a pleasure to join a presentation on how sitting at work is degrading ones health. IT industry is at highest risk. What <b>unhealthy position</b> does to us has <b>serious, even fatal consequences</b> in long term.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<img alt="" border="0" data-original-height="300" data-original-width="600" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEhL5ERx1w2KhtcBtbNQdFt7KyXLwQ3LgzMzFHv2RWV-SHymnX7rGHq0-o4XhopWzT8v_ftLzNcJd9c1m_-RpvQjaq03eEC9EsMoZm_-7dCQZkUmoP96R60f4m_bZdEwFwHvYwyMWDA0o/s320/standitup-evolution-logo.png" title="standitup.org" width="320" /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://standitup.org/">Sitting is new smoking - see the details</a></div>
<br />
Our way of living is far away from what is natural living that human bodies are created for. This has so many aspects and long term factors that cannot be neutral for our health.<br />
<br />
What we do to our bodies is what we call technical debt. Unfortunately, this project has very limited time dedicated for refactoring. Medicine is now clear about it.<b> Sitting at work can take YEARS from our lifetime. </b><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
IT is a fantastic community. We exchange knowledge to improve our skills. We are professionals willing to deliver our best to our business partners and apply best practices we know. We are able to <b>suppress all practices </b>regarding our job, that <b>we considered harmful</b>.<br />
<br />
Why not apply this approach to ourselves? Stop unhealthy practices that damage the only thing which really belongs to us - our body? There are scientific, medical, cultural and moral reasons for standing up at work. <b>Changing small habits </b>seems an easy way to live much happier, healthy life. I am convinced!<br />
<br />
TLDR; <span style="background-color: yellow; color: red;">quit sitting, it kills</span>.<br />
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-39587440739774808652017-07-07T12:27:00.000+02:002017-07-07T12:27:12.745+02:00I want my Rhino back! Switching to Nashornless.In JDK 8 default scripting engine had been changed. Nashorn replaced Rhino. I understand all positives of this change and how good the use of InvokeDynamic is, etc.<br />
But this change may be also seen as a <b>breaking </b>change. Which is quite normal in world of JavaScript btw :D And do not expect compile time errors! It is almost like node experience...<br />
<br />
<b>
Ok, your old Rhino-specific code will not run with Nashorn.</b> However, I have been using it for years, and truly speaking missing it a lot. I wrote test tooling scripted by Rhino, glue code that connects ETL to Java or dynamic backend of application, allowing website maintenance with no redeployment. Still, it is possible to go back to old good JavaScript implementation. So let's make our Rhino great again!<br />
<br />
We could, of course, use it like we did it before JDK 6: add just a lib to our project and evaluate script by means delivered by specific Mozilla implementation.<br />
<br />
If we are more familiar with Java scripting in JSR-223 style we would need extra code that is Sun specific part, already removed from recent Java. But fortunately someone already did the job for us and <a href="https://bitbucket.org/bunkenburg/rhino-js-engine">provided alternative JSR-223 wrapper</a> that uses original Rhino and provides all extra classes that are required by standardized engines.<br />
Let's just add dependency to pom.xml file:<br />
<pre class="brush:java"> <dependency>
<groupId>org.mozilla</groupId>
<artifactId>rhino</artifactId>
<version>1.7.7.1</version>
</dependency>
<dependency>
<groupId>cat.inspiracio</groupId>
<artifactId>rhino-js-engine</artifactId>
<version>1.7.7.1</version>
</dependency>
</pre>
<br />
And yes, now we can use old, good, nashornless Rhino again! Just one more thing to remember is to use right scripting engine instead of "javascript".<br />
<br />
<pre class="brush:java">
new ScriptEngineManager().getEngineByName("rhino");
</pre>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0vWUdjI9XDFC6Lf4MFQyVwPejxr7FWngOmMvhZmKO8RQVQwhmHUF1S4wIlOXA_pR4TFkscG4KDpt2MMbFieqNrNak6eePWD73Na7HfHDZPqcK8NwiITESurDVDY4TmprGCeyrGOUkuIE/s1600/rhino.jpg" imageanchor="1"><img border="0" data-original-height="1064" data-original-width="1600" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0vWUdjI9XDFC6Lf4MFQyVwPejxr7FWngOmMvhZmKO8RQVQwhmHUF1S4wIlOXA_pR4TFkscG4KDpt2MMbFieqNrNak6eePWD73Na7HfHDZPqcK8NwiITESurDVDY4TmprGCeyrGOUkuIE/s400/rhino.jpg" width="400" /></a></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-16013745005101132972017-06-08T12:00:00.003+02:002017-06-08T12:00:56.831+02:00No pride, no prejudice: Effective JavaWhile reading programmers' blogs you can be exposed not only to shiny technical stuff, as well you can meet author's private opinion. It's positive, as human being we want to share our opinions with others. But some opinions seem weired - and only possibility is to get used to that. One blogger dissed proggrammers' meetups, other advocated abortion, another one prefered <span style="font-family: Courier New, Courier, monospace;">null </span>checks over <span style="font-family: Courier New, Courier, monospace;">Optional</span>, million others actively hate statically typed languages. Not mentioning Emacs fans...<br />
<br />
Some time ago I read a blog post in which author rejected idea of reading "Effective Java". Blogger had explained that book must be clearly outdated as 2nd edition was released in 2008 and he is not going to loose time for reading things like string concatenation vs using <span style="font-family: "courier new" , "courier" , monospace;">StringBuilder</span>.<br />
Well...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLO4mmn8u4kHtLeQ-kAvvYRZrhdnzkSStBhYjdKBitjTVoUZYz2aVgnR521ArtHetgxUxhT72lztlSXTIdRG5efgs_VXUiVUq3wGllr6WeM6xazJWCQ1Uq3WRMnCJ8ZYf4Erd6DCTmFwE/s1600/facepalm.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1440" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLO4mmn8u4kHtLeQ-kAvvYRZrhdnzkSStBhYjdKBitjTVoUZYz2aVgnR521ArtHetgxUxhT72lztlSXTIdRG5efgs_VXUiVUq3wGllr6WeM6xazJWCQ1Uq3WRMnCJ8ZYf4Erd6DCTmFwE/s200/facepalm.jpg" width="200" /></a></div>
<br />
Fortunately this classical book is easy to defend, even for not such-a-proficient-blogger like me.<br />
Well recognized Java bestseller is not really about outdated micro-optimations on low layer (which btw may also be a good topic to know). It is not about what is different from C in Java.<br />
<br />
This book introduces readers into variety of interesting topics.<br />
After reading you will (not only) be more aware of why immutability is important in contemporary software, how to structure data better, or how to use compiler to ensure type safety to work for your benefit. It will encourage you to use language constructs that support safe coding (eg. using enums), name things correctly (like use static factory methods) and depict constructs that are problematic (eg. clone). And explain variance in generics... :D<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIGRtckGViwSmTpT4l7WvOj1xlE-9WuRjTWKAw2YkdopwknmLfG9_iB8NvuzNDdaeth1ZsKaSQ1D4FfAS5wiPELU3SaqfAqC0CsC7qKEslhqOvV5HgO_Wf0mp1sVLakK9oGsJjhZFSCf0/s1600/20170517_202936.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIGRtckGViwSmTpT4l7WvOj1xlE-9WuRjTWKAw2YkdopwknmLfG9_iB8NvuzNDdaeth1ZsKaSQ1D4FfAS5wiPELU3SaqfAqC0CsC7qKEslhqOvV5HgO_Wf0mp1sVLakK9oGsJjhZFSCf0/s320/20170517_202936.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
My personal observation is that Bloch's book was for some Java guys a first step into typed functional programming with Scala or even Haskell. I have seen lot of smart who followed this path. They could of course years ago assume that their knowledge of Java and enterprise technologies was good enough and they do not need to read one more book on `efficiency`.<br />
I think that they had a very good and respectable attitude to their own knowledge.<br />
Be like them. Do not believe you already know everything, rather as a software engineer you must be open to learn, read and try new things out. And sometimes read 10 years (or even more) old books.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-75437374299700431442017-03-01T21:13:00.000+01:002017-06-15T21:15:56.416+02:00Generating model with inheritance from swagger specificationThe post on <a href="http://tech.zooplus.com/generating-java-model-with-inheritance-from-swagger-specification/">generating java model with inheritance from swagger specification</a> is on Zooplus company blog.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4PhjGA87qU8ARg_RvIeGXMyiheNSy58fxtvaUPIE-AbVVQtebY_sEU6PTP_tfVKX25tptJ1RWh5JskfD_AoGijjEbXZ3dJTMEvtJrPIxBy0O5_TxGdSEjzz4PCKSj56JtWXjg_gaAcoo/s1600/order_line.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="210" data-original-width="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4PhjGA87qU8ARg_RvIeGXMyiheNSy58fxtvaUPIE-AbVVQtebY_sEU6PTP_tfVKX25tptJ1RWh5JskfD_AoGijjEbXZ3dJTMEvtJrPIxBy0O5_TxGdSEjzz4PCKSj56JtWXjg_gaAcoo/s1600/order_line.jpg" /></a></div>
<br />
<br />
BTW I must admit I like more code formatting options on ghost platform than what I have here with blogger.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-41280027123524570632017-01-21T14:10:00.000+01:002017-01-21T14:10:34.626+01:00The great red dragon and the novice programmer<div class="separator" style="clear: both; text-align: center;"><a href="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Reddragon.jpg/464px-Reddragon.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Reddragon.jpg/464px-Reddragon.jpg" /></a></div>
<p> As a novice software developer at some point of time you will find enlightenment. You will understand what is the source of Power. Power of perfect code development. Power of ideal expression ideas to text. SOLID and clean, intentional and free of any accidental complexity.
<p> You will desire that Power. Like the Pilgrim admired the power of The Great Red Dragon. But still you need a transformation. Pilgrim needed his victims to see his beauty, as he himself admired the Red Dragon. You will instead look at code you work with. The real code. Ugly. Legacy. Half year old code written on 2 releases backward Spring version. You will show your vict... sorry, colleagues that bad code. And yourself as a powerful Red Dragon. But... You're not yet him.
<p> You need your transformation. I was there too. Now I know. Please keep in mind one thing. Consult your more experienced colleagues before you start making that code better. Example from my transformation.
I spent some time years ago to refactor piece of code using collection to keep objects of various classes. Then cascade of <code>instanceOf</code>... This was looking for me as an unacceptable implementation. Unfortunately, my employer would have been more happy if I had focused on my tasks instead of refactoring code that was correctly working since years. From his perspective my hard work was not considered as productive. Now I know I just was not able to recognize which part of system needs what kind of refactoring.
<p> Here I must refer to Procent's
<a href="http://devstyle.pl/2016/10/03/devtalk41-o-legacy-code-z-jaroslawem-palka/"> excellent talk with Jarek Palka</a> (in Polish). You can find out a lot of important hints regarding working with legacy code. Which is code you have just commited. One of hints is why compulsive refactoring may affect your projects and may cause inability to deliver.
<p> After years I learnt that system I was working with was actually quite good thanks to good design and correct, efficient, event driven architecture. As a young developer, influenced by Clean-Code evangelism, I was focused on local parts, not on wider scope. Lot of implementation details were given to novice programmers and far from ideal. They SHOULD be better, but system was good enough to resist local code ugliness. Please try to learn what is important in your system first, before you start assuming that whoever wrote some piece of code was an ignorant or does not even know the programming language. Remember you have not yet transformed into The Great Red Dragon.
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5976997740601760926.post-67715441879948265052016-12-04T01:42:00.000+01:002016-12-07T15:42:37.228+01:00Using groovy for testsWhile 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. <br>
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:
<ol>
<li>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.</li>
<li>Forget semicolons, alias imported objects, use list and map literals, multiline strings, use def. Almost like Scala.</li>
<li>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.</li>
<li>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:
<pre>
Assertion failed:
assert apiResponse.code() >= 200 && apiResponse.code() < 300
| | | | | | |
| 404 true | | 404 false
| | retrofit2.Response@42d0a255
| false
retrofit2.Response@42d0a255
</pre>
</li>
<li>BigDecimal everywhere. 42.0 is not a float any longer. If your code has something in common with money you can feel relief.</li>
<li>@TypeChecked. Why not just use compiler? With Groovy you can! It is so nice when machine corrects your errors.</li>
</ol>
I am not convinced whether Groovy is language of future :> But definitely worth trying. Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-58304557478825102462016-10-07T00:33:00.001+02:002016-10-07T00:33:20.496+02:00IT Aristocracy to guillotine! How to treat IT head hunters?Recently JUG in Warsaw published a newsletter containing quite an unusual link to an <a href="https://www.linkedin.com/pulse/stop-hejtowi-w-rekrutacji-kamila-szkwarek"> article created by a professional IT recruiter</a>. 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.
<h3>Dear programmers!</h3>
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.<br>
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 <a href="https://www.linkedin.com/pulse/recruiter-you-may-get-my-ex-boss-telephone-number-rafal-chmielecki-"> elegant form as Rafal did</a>.<br>
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 <es>less professionally</es> in some conditions. Me too. I am sure that soft-skilled recruiters are also able to understand and forgive that.<br>
<b>But primitive, vulgar offence is not "unprofessional behavior"!</b>
That is not acceptable! <es>Das ist unglaubich!!!</es> That kind of freaks must be stigmatized! <br>
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 <es>(our...)</es> 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?
<br>
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.
<br>
TL;DR If you are frustrated buy the rubber duck! Never offend head hunters. Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-9508243368257383282016-05-19T00:52:00.002+02:002016-05-19T00:52:42.525+02:00Changing merge request target branch in gitlab<i>TDLR; </i><br />
Yes, it's possible with API usage.<br />
There is even a <a href="https://github.com/konopski/chmrbr">script that chamges target branch </a>with minimal configuration.
<br />
<br />
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. <br/>
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. <br/>
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. <br/>
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). <br/>
Operation will take 3 HTTP calls. First is ment to retrieve project id by its name. <br/>
<pre>
GET /projects/search/:name_to_find
</pre>
I assume there are no more than one projects found by given name.
<br/>
Second will convert id from GUI to MR id.
<pre>
GET /projects/:id/merge_requests?iid=42
</pre>
or you can select manually from all opened MRs.
<pre>
GET /projects/:id/merge_requests?state=opened
</pre>
Knowing project id and MR id we can now update target branch by sending simple json object carrying new target branch as a value.
<pre>
PUT /projects/:id/merge_request/:merge_request_id
{ "target_branch": "the_target_br" }
</pre>
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.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-16291459537859708452016-04-02T04:56:00.000+02:002016-04-02T05:01:32.701+02:00massive directory name case changeSome 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. <br/>
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.<br/>
Fortunately there is nice tool in python that accomplishes the same goal - <code> os.walk</code>. Usage is trivial and script is portable to any platform. File system paths can be also abstracted easily with <code>os.path.join</code>. There is even a method in python <code>string</code> 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.
<pre class="brush:java">
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()))
</pre>
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:
<pre class="brush:bash">
git config core.ignorecase false
</pre>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5976997740601760926.post-35930533280220681822016-03-21T20:09:00.004+01:002016-03-22T14:25:19.202+01:00Guava's Optional defficienciesTL;DR: There is no reason to use Optional from Guava, Java 8 is better.<br />
<br />
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). <br />
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. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLb3f9nmPOZUffjk8PdZwnSBVnxorasvHrlHp0L3Lkw6NbzvmFpuigX-O0eP606FnYFU0TBeNqwxza-CAIFyI_UJddMWoj8COmCUg7IQk_ceiGJ6PPNVcM74Les0fy_yP2EJL8BsZ7DiQ/s1600/Kopernik-no-flat-map.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Copernicus agreed with Guava guys - no Flat Map!" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLb3f9nmPOZUffjk8PdZwnSBVnxorasvHrlHp0L3Lkw6NbzvmFpuigX-O0eP606FnYFU0TBeNqwxza-CAIFyI_UJddMWoj8COmCUg7IQk_ceiGJ6PPNVcM74Les0fy_yP2EJL8BsZ7DiQ/s1600/Kopernik-no-flat-map.jpg" title="Copernicus agreed with Guava guys - no Flat Map!" /></a></div>
<br />
<br />
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:<br />
<pre class="brush:java">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();
}
};
}
</pre>
<br />
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.<br />
But...<br />
There is more problematic issue with this implementation.<br />
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.<br />
<pre class="brush:java">import com.google.common.base.Optional;
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);
}
}
</pre>
<br />
which brings us the result of:<br />
<br />
<pre>optional = Optional.of(aaa)
Exception in thread "main" java.lang.NullPointerException: the Function passed to Optional.transform() must not return null.
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:226)
at com.google.common.base.Present.transform(Present.java:71)
at options.guava.BrokenGuava.main(BrokenGuava.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
</pre>
<div>
<br /></div>
NullPointerException! The same one that we expected to get eradicated by using Optionals all around our code!<br />
The standard has got it implemented in a much better way:<br />
<br />
<pre class="brush:java">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 = optional.map(x -> null);
System.out.println("mapped = " + transformed);
}
}
</pre>
<br />
this time you can see:<br />
<pre>optional = Optional[aaa]
mapped = Optional.empty
</pre>
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.<br />
So... Price is the same, why whould I choose suboptimal solution? Time to mark Guava's Optional deprecated.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-26741152598885942992016-01-27T01:27:00.000+01:002016-03-22T14:28:58.370+01:00Idea: Ctrl+w considered harmful<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiad8jbSmny68eXTp-279RBfRzVq-RVwHEciz13K1Z0E2fG_4eVnbmu77QHn5hUaaSACaF5ACWraBmkyyqoaaUk-bKCm8pEArKZ1Cap2WuoG-SqIrKzlBCdHULCUu5U7ocH3N_NuiZqSeI/s1600/extend_selection.bmp" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiad8jbSmny68eXTp-279RBfRzVq-RVwHEciz13K1Z0E2fG_4eVnbmu77QHn5hUaaSACaF5ACWraBmkyyqoaaUk-bKCm8pEArKZ1Cap2WuoG-SqIrKzlBCdHULCUu5U7ocH3N_NuiZqSeI/s1600/extend_selection.bmp" /></a></div>
<br />
<br />
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:<br />
- code<br />
- select<br />
- extract variable/method<br />
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.<br />
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.<br />
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.<br />
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.<br />
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.<br />
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.<br />
But situation is even worse: this is not only about other IDE.<br />
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.<br />
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. Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-46065158477821375902015-11-11T11:30:00.001+01:002015-11-11T11:30:44.503+01:00I like lombokfrom
<pre>
public final class UserId {
private final String userId;
public UserId(String userId) {
this.userId = userId;
}
public String getUserId() {
return userId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserId userId1 = (UserId) o;
return !(userId != null ? !userId.equals(userId1.userId) : userId1.userId != null);
}
@Override
public int hashCode() {
return userId != null ? userId.hashCode() : 0;
}
@Override
public String toString() {
return "UserId{" + userId + '}';
}
}
</pre>
to
<pre>
import lombok.Data;
@Data
public final class UserId {
private final String userId;
}
</pre>
feels almost like scala...Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-44151148652722305162015-06-04T01:33:00.002+02:002016-03-22T14:27:41.814+01:00using edHaving a moment of spare time I decided to go back to <a href="https://github.com/konopski/99_scala_problems">my approach to 99 scala problems</a>. When I started I have used pure scala scripts, so I needed eg. to call them like this:
<br />
<pre class="brush:shell">scala -i p05.scala -i p04.scala -i p03.scala p06.scala
</pre>
Now I've learnt that it may be easier to go on using
<br />
<pre class="brush:shell">sbt console
</pre>
However my code was not sbt-friendly, as it caused complaints regarding missing object or class definition. You cannot just define methods like in REPL. So I ended up with urgent neccessity to include my functions into some nice objects. As I am currently playing with <a href="http://www.bananapi.org/">rather small machine</a> full IDE like IntelliJ is not an option. So basically I needed to use my command line to:
<br />
<li>add object definition line before content</li>
<li>add closing brace after content</li>
where the latter is trivial append to file, usually
<br />
<pre class="brush:shell">echo "}" >> P01.scala
</pre>
How to append a line of text at beggining of file?
Enter ed.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://ironmaiden-bg.com/en/images/stories/eddie.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://ironmaiden-bg.com/en/images/stories/eddie.jpg" /></a></div>
Ed is an editor with tradition, used to scarry out younger programmers in team. I have read <a href="http://blog.sanctum.geek.nz/actually-using-ed/">a fantastic intro to ed </a>not so long ago. This is the ed script for making the changes with line by line explanation what it is doing (note ed will not get this comment):
<br />
<pre class="brush:java">
1 //goto first line
i //start inserting
package konopski.skala.ninety.nine { //actual text
object PP00 { //more text
. //single dote
//ends writing
$ //goto last line
a //append
} //some
} //text
. //ok, that's enough
w //wq seems familiar
q //have you left any program this way?
</pre>
After that it took one line in <a href="http://fishshell.com/">shell I use</a> to complete the task:
<br />
<pre class="brush:shell">
for p in p*.scala; cat edme | sed -e s/PP00/$p -e s/\.scala// | ed $p ; end
</pre>
Note I have used ed's famous cousin - sed to replace placeholder value PP00 to actual file name without extension. That's it, the massive work is done and I have not used copy/paste or even any vim macro. I must say it was amusing equally to playing with scala, however seems to be even more practical than next way to reverse a list ;>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-82176264386435985342015-04-15T16:55:00.001+02:002016-03-22T14:27:28.102+01:00jq one more time - see only what really mattersSometimes you can find lot of information noise.
Say I want to see only document id and it's content.
Check this:
<br />
<pre class="brush:java">
curl -XPOST "http://es1.grey:9200/settings/d/_search?limit=50" -d'
{"query": { "match_all": {}}}' | jq ".hits.hits[] | [ ._id, ._source ]"
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-56565588590556960962015-01-23T10:57:00.003+01:002016-03-22T14:30:28.403+01:00new favourite commandA must have for console addicted git users:
<br />
<pre>git checkout -
</pre>
This jumps back and forward between two last branches. Really awesome.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-43960826995410386782015-01-08T23:25:00.002+01:002016-03-22T14:25:37.293+01:00more hints regarding OptionalsInstead of
<br />
<pre class="brush:java"> Optional<Camera> camera = getCameraByMac(cameras, mac);
if (camera.isPresent()) {
return Optional.of( camera.get().getIp() );
} else {
return Optional.absent();
}
</pre>
use
<br />
<pre class="brush:java">
Optional<Camera> camera = getCameraByMac(cameras, mac);
return camera.transform(getIpFunction);
static final Function<Camera, String> getIpFunction = new Function<Camera, String>() {
@Nullable @Override
public String apply(Camera camera) {
return camera.getIP();
}
};
</pre>
instead of
<br />
<pre class="brush:java">
List<Event> result = new LinkedList<>();
for (Optional<Event> transformedEvent : someEvents) {
if (transformedEvent.isPresent()) {
result.add(transformedEvent.get());
}
}
return result;
</pre>
use
<br />
<pre class="brush:java">
return Optional.presentInstances(events);
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-686318329264275242014-12-18T16:01:00.002+01:002016-03-22T14:27:05.468+01:00Using jq to talk with elasticsearchI've recently found a new tool, quite useful, if you often talk to json services. It's named <a href="http://stedolan.github.io/jq/">jq</a>, please do not confuse it with jQuery.
Eg. let's take Elasticsearch. I want to know which JVM it runs within. So I need to ask like this:<br />
<code>curl -XGET es1.grey:9200/_cluster/stats</code>
<br />
so here's the output:<br />
<pre class="brush:javascript">{"timestamp":1418913590962,"cluster_name":"gc-pb-grey","status":"green","indices":{"count":31,"shards":{"total":252,"primaries":126,"replication":1.0,"index":{"shards":{"min":4,"max":10,"avg":8.129032258064516},"primaries":{"min":2,"max":5,"avg":4.064516129032258},"replication":{"min":1.0,"max":1.0,"avg":1.0}}},"docs":{"count":162713289,"deleted":188051},"store":{"size":"44.2gb","size_in_bytes":47543046975,"throttle_time":"1.9d","throttle_time_in_millis":172301216},"fielddata":{"memory_size":"2.6gb","memory_size_in_bytes":2858909795,"evictions":0},"filter_cache":{"memory_size":"4.8gb","memory_size_in_bytes":5161692177,"evictions":504563},"id_cache":{"memory_size":"0b","memory_size_in_bytes":0},"completion":{"size":"0b","size_in_bytes":0},"segments":{"count":2000,"memory":"2.9gb","memory_in_bytes":3169080575}},"nodes":{"count":{"total":8,"master_only":0,"data_only":0,"master_data":8,"client":0},"versions":["0.90.12"],"os":{"available_processors":32,"mem":{"total":"188.7gb","total_in_bytes":202616012800},"cpu":[{"vendor":"AMD","model":"Opteron","mhz":2599,"total_cores":4,"total_sockets":4,"cores_per_socket":1,"cache_size":"512b","cache_size_in_bytes":512,"count":8}]},"process":{"cpu":{"percent":115},"open_file_descriptors":{"min":1356,"max":1537,"avg":1429}},"jvm":{"max_uptime":"8d","max_uptime_in_millis":693602733,"versions":[{"version":"1.6.0_30","vm_name":"OpenJDK 64-Bit Server VM","vm_version":"23.25-b01","vm_vendor":"Sun Microsystems Inc.","count":8}],"mem":{"heap_used":"59.5gb","heap_used_in_bytes":63949850024,"heap_max":"127.7gb","heap_max_in_bytes":137160032256},"threads":621},"fs":{"total":"94.4gb","total_in_bytes":101461655552,"free":"48.9gb","free_in_bytes":52530081792,"available":"44.1gb","available_in_bytes":47376134144,"disk_reads":570224,"disk_writes":164405664,"disk_io_op":164975888,"disk_read_size":"16.1gb","disk_read_size_in_bytes":17347735552,"disk_write_size":"612.6gb","disk_write_size_in_bytes":657792794624,"disk_io_size":"628.7gb","disk_io_size_in_bytes":675140530176,"disk_queue":"0","disk_service_time":"0.9"},"plugins":[{"name":"bigdesk","description":"No description found for bigdesk.","url":"/_plugin/bigdesk/","jvm":false,"site":true},{"name":"hq","description":"No description found for hq.","url":"/_plugin/hq/","jvm":false,"site":true},{"name":"head","description":"No description found for head.","url":"/_plugin/head/","jvm":false,"site":true}]}}
</pre>
Quite human unreadable. Let's try now with jq:<br />
<code>curl -XGET es1.grey:9200/_cluster/stats | jq "."</code>
<br />
Seems more elegant now:<br />
<pre class="brush:javascript">{
"nodes": {
"plugins": [
{
"site": true,
"jvm": false,
"url": "/_plugin/bigdesk/",
"description": "No description found for bigdesk.",
"name": "bigdesk"
},
{
"site": true,
"jvm": false,
"url": "/_plugin/hq/",
"description": "No description found for hq.",
"name": "hq"
},
{
"site": true,
"jvm": false,
"url": "/_plugin/head/",
"description": "No description found for head.",
"name": "head"
}
],
"fs": {
"disk_service_time": "0.3",
"disk_writes": 164465520,
"disk_reads": 570266,
"available_in_bytes": 47369240576,
"available": "44.1gb",
"free_in_bytes": 52523188224,
"free": "48.9gb",
"total_in_bytes": 101461655552,
"total": "94.4gb",
"disk_io_op": 165035786,
"disk_read_size": "16.1gb",
"disk_read_size_in_bytes": 17348456448,
"disk_write_size": "612.8gb",
"disk_write_size_in_bytes": 658024804352,
"disk_io_size": "628.9gb",
"disk_io_size_in_bytes": 675373260800,
"disk_queue": "8.3E-5"
},
"jvm": {
"threads": 621,
"mem": {
"heap_max_in_bytes": 137160032256,
"heap_max": "127.7gb",
"heap_used_in_bytes": 53713885664,
"heap_used": "50gb"
},
"versions": [
{
"count": 8,
"vm_vendor": "Sun Microsystems Inc.",
"vm_version": "23.25-b01",
"vm_name": "OpenJDK 64-Bit Server VM",
"version": "1.6.0_30"
}
],
"max_uptime_in_millis": 694176092,
"max_uptime": "8d"
},
"process": {
"open_file_descriptors": {
"avg": 1432,
"max": 1546,
"min": 1355
},
"cpu": {
"percent": 134
}
},
"os": {
"cpu": [
{
"count": 8,
"vendor": "AMD",
"model": "Opteron",
"mhz": 2599,
"total_cores": 4,
"total_sockets": 4,
"cores_per_socket": 1,
"cache_size": "512b",
"cache_size_in_bytes": 512
}
],
"mem": {
"total_in_bytes": 202616012800,
"total": "188.7gb"
},
"available_processors": 32
},
"versions": [
"0.90.12"
],
"count": {
"client": 0,
"master_data": 8,
"data_only": 0,
"master_only": 0,
"total": 8
}
},
"indices": {
"segments": {
"memory_in_bytes": 3169089995,
"memory": "2.9gb",
"count": 2023
},
"count": 31,
"shards": {
"index": {
"replication": {
"avg": 1,
"max": 1,
"min": 1
},
"primaries": {
"avg": 4.064516129032258,
"max": 5,
"min": 2
},
"shards": {
"avg": 8.129032258064516,
"max": 10,
"min": 4
}
},
"replication": 1,
"primaries": 126,
"total": 252
},
"docs": {
"deleted": 188053,
"count": 162713334
},
"store": {
"throttle_time_in_millis": 172306131,
"throttle_time": "1.9d",
"size_in_bytes": 47552519067,
"size": "44.2gb"
},
"fielddata": {
"evictions": 0,
"memory_size_in_bytes": 2858939869,
"memory_size": "2.6gb"
},
"filter_cache": {
"evictions": 504563,
"memory_size_in_bytes": 5181806342,
"memory_size": "4.8gb"
},
"id_cache": {
"memory_size_in_bytes": 0,
"memory_size": "0b"
},
"completion": {
"size_in_bytes": 0,
"size": "0b"
}
},
"status": "green",
"cluster_name": "gc-pb-grey",
"timestamp": 1418914164326
}
</pre>
Ok, this does not changes much however, it's easy to get json formatted. But try this:
<code>curl -XGET es1.grey:9200/_cluster/stats | jq ".nodes.jvm"</code>
and we get:
<br />
<pre class="brush:javascript">{
"threads": 619,
"mem": {
"heap_max_in_bytes": 137160032256,
"heap_max": "127.7gb",
"heap_used_in_bytes": 54125025648,
"heap_used": "50.4gb"
},
"versions": [
{
"count": 8,
"vm_vendor": "Sun Microsystems Inc.",
"vm_version": "23.25-b01",
"vm_name": "OpenJDK 64-Bit Server VM",
"version": "1.6.0_30"
}
],
"max_uptime_in_millis": 694408309,
"max_uptime": "8d"
}
</pre>
I took the outer object by first dot, 'nodes' property, and from inside it 'jvm' property.
It is now trivial to get actual jvm version:
<code>curl -XGET es1.grey:9200/_cluster/stats | jq ".nodes.jvm.versions[0].version" </code>
Tadam:
<br />
<pre class="brush:javascript">"1.6.0_30"</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5976997740601760926.post-83257888917750085832014-01-22T22:29:00.000+01:002014-01-22T22:30:35.604+01:00can your language talk json?Recently I discovered Python.
It's really amazing that the language is that flexible so it can treat json literals as it's usual code. Think about constructing all objects in Java with any JSON library.
Is this flexibility specific to dynamic languages?
Btw I have found an example that well known and loved ;> C++ also is flexible enough to handle JSON:
<pre class="brush:java">
std::string json_cxx = {
key: "value",
number: 53
};
</pre>
This will compile.
But... don't be fooled by compiler letting pass that code!
The result is not what javascript developer could expect :/ Unknownnoreply@blogger.com0