Saturday, October 22, 2016

Clojure Plan, Map and Courage

This is one of those moments when the computer says NO!

Let's look at the interesting nature of Clojure's map function.

(defn foo[filenames]
    (map #(touchFile (str "/tmp/" %)) filenames))

Suppose we have a pre-existing function called touchFile that creates an empty file.

This foo function never created any files when called. I must have made a mistake with the directory path or perhaps my filesystem ran out of space or perhaps a bug somewhere in my touchFile function or perhaps...

Hang on, my test code for touchFile passes without any problem!

An attempt to prove something is wrong with the map call....

(defn foo[filenames]
    (map #(println (str "/tmp/" %)) filenames))

And nothing was printed out on my screen!

Something really sinister is going on here...

All you need is the plan, the road map, and the courage to press on to your destination.


After going back to the docs, it mentioned that "map returns a lazy sequence of...". Did you just hear the penny dropped?

So, the fix here is to invoke doall to force the map to evaluate each items immediately.

(defn foo[filenames]
    (doall (map #(touchFile (str "/tmp/" %)) filenames)))

Yay it worked!



Looking at a simple problem at 2 in the morning doesn't help a lot. It's probably time for me to hit the Zs.


Friday, October 14, 2016

In Search For A Better CI/CD

This is going to be an exciting time!

Imagine me, writing me first Clojure app!

I'm halfway through writing my first Clojure program called "relman", short for "Release Manager".
It's a simple CLI application to help me deploy specific WAR files to a dockerised Tomcat. 

The recipe here is a simple pull deployment (unless I've hit unforeseen issues - fingers crossed).

Firstly, I've configured my Jenkins build to rename any successful elwood-parent builds to <feature>-<issue number>-<issue description>-<#build number>.war and copy this to a mounted volume shared with Tomcat.

Secondly, running relman on host to copy the war file as ROOT to the designated Tomcat directory mounted as "/webapp".

Thirdly, umm.. I think that's it. Trying to keep the solution simple.

This POC worked by manually copying the file across directories, so technically this idea should work!

Furthermore, I think this recipe is universal and applicable when I use different Git branches whenever Jenkins kicks in.

Elwood Continuous Integration and Delivery

As with relman in Clojure, this is a work in progress but I think I'm not far off from my end goal.

In summary, this is my first step to get CI/CD working and it's by no means an end to this exciting journey!

And the quest for CI/CD continues... (Clojure included)

Wednesday, October 5, 2016

Clojure Exercise #1: Bend My Mind With MapSet

Write a function, mapset, that works like map except the return value is a set:
(mapset inc [1 1 2 2])
;=> #{2 3}


Answer:

(defn mapset [fn elements]
(let [uniq (into #{} elements)]
(set (map fn uniq))))



How can I write a piece of code without a unit test?

(deftest mapset-test
(is (= #{ 2 3 } (mapset inc [1 1 2 2]))))



Invoking mapset:

(mapset inc [1 1 2 2])
;=> #{3 2}

Tuesday, October 4, 2016

I Keep Coming Back to the Land Of Lisp

Don't ask me why. For some reason, I keep coming back to the Land of Lisp.

A few weeks ago, I was reading a few chapters about Common Lisp before I went to bed.
I remember vividly on one particular night, my mind was mumbling about the cryptic CAR, CDR, CDAR, CADR operations repeatedly, while looking at an unknown rectangular block chopped off from the top.

Well, the good thing is - this isn't one of Freddy Krueger's episode.


Lisp has been around for quite some time and to think about this old language coming back to life in the modern times or as an incarnation is exciting.

Welcome Clojure!


I hear people complained about the excessive (((((parenthesis))))) that comes with it. True, but has anyone complained about excessive semis;colons;and;{braces{around{blocks}}} from other programming languages? (No Visual Basic 6 please)


Though quite new to Clojure, I thought of trying a few simple things to see how it tastes like.

To compute for an extended price of an imaginary item (I was told that I should use a map to represent the properties of an item):

(defn line-extended [{qty :qty price :price discount :discount}]
   (* (- price discount) qty))

Simple enough.


Next is what I find Clojure interesting.

Suppose I need to sum all quantity, price and discount:

(defn line-items-summary [items]
   (apply merge-with + (for [item items]
   select-keys item [:qty :price :discount]))))

The code performs a loop for each item, add the quantity, price and discount and returns the sum of these properties.

So invoking this function as follows:

(line-items-summary [
    {:qty 1 :price 10 :discount 2}
    {:qty 2 :price 1000 :discount 200}])
Returns:
{:qty 3, :price 1010, :discount 202}


The syntax looks simple, elegant and most of all appealing. 

To sum up the three adjectives - it's POWERFUL!


Saturday, September 24, 2016

♕ Keep Calm We're Moving To Gitflow GitFlow + Maven = No Joy ☹

I've have my own custom Jenkins that contains some basic configuration to build a tiny library called lyeung-common-test.

I've been trying to get GitFlow to work as a proof of concept.

I've played around with different plugins but to get GitFlow and Maven to work together proves more challenging than I initially thought.

The fundamental problem seems to be the pom version. Maven standard practice requires the version number to be defined upfront. However, when GitFlow comes in and starts merging branches, I get merge conflicts on version numbers.

Little Johnny is not a happy boy...

Tuesday, July 12, 2016

♔ Don't Panic See You In GitHub

After a few months on Hosted Redmine/Bitbucket, I've decided to pull all Elwood developments/wiki/issue tracker into one spot - GitHub. There's nothing wrong with Hosted Redmine and Bitbucket, they both provided me absolutely great services at $0.

It all boils down to splitting projects into personal and public projects. You see, I own 2 Git accounts: Bitbucket and GitHub. My overall intention was to keep all things private in Bitbucket and the rest publicly in GitHub. Elwood was suppose to be just a thought, a result of N-number of days day dreaming about writing a personal CI server. I was expecting this thought to vaporise as days go on, hence a private repository for late night coding activity.

Happy GitHubbing everyone!

♕ Keep Calm We're Moving To Gitflow

I'm evaluating Elwood development with Gitflow. One thing I like about Gitflow is that it gives the ability to better track changes, releases and bug fixes. It also allows me to stay focus in writing one feature at a time. You see, there is an adrenaline rush in me that I sometimes find myself shoving unrelated changes to my timeline. I could commit one large snowball of unrelated codes that may stretch the completion time to 1.5 times longer if I'm lucky or 3 times longer if I'm not-so-lucky.

This definitely contradicts the spirit of agile with the emphasis of delivering in small increments. (Ahhh, agile that starts with a lower case... How pragmatic do I sound?)

I did ask myself if this could be too much of an overhead for a lone developer like me?

Well, time will tell...