26 Nov 2016
It takes time to understand a problem, because before you can fully understand it, you need to also understand its context. As a code base grows, depending on how well the code is structured, the context in which you need to understand the problem can (and often will) grow.
When a problem or its context is misunderstood there is a tendency to oversimplify the problem. I’m all for finding a simple and elegant solution but not at the cost of correctness. Oversimplified solutions will not be able to handle all special cases, and special cases lead to crashes or data corruption… or both. This in turn leads to maintenance and clean up by the programmer which I would much rather have coding on this next big thing.
The available time to implement a solution is not only challenged by a push for quick deliveries but also a lack of respect that creating software is actually hard. I’ve experience this lack of respect from all involved parties (including the programmer).
Even though I strive to “do things right”, I also think it is okay and often necessary no to. But it should be a conscious decision.
I.e. making sure to handle two use cases (corner cases) will increase development time but at the same time those a very unlikely to happen or if they happen they are very easy to correct manually. If someone makes a conscious decision that these cases should be handled outside the software, then it is okay.
It is NOT okay (and very short sighted) when the pressure doesn’t allow collecting the necessary information to make that decision.
So by all means cut corners - but only do so together with proper risk assessment.
08 Oct 2016
Having been given a new area of responsibility as team lead inspired me to think about aspects of coding beyond just typing it.
I’ve experienced we where chasing our own tail. Trying to close issues “fast” and hurry on to the next in line. But something wasn’t working. Every time we changed a comma in one end, something in the other end would break horribly. Bug fixing was feeling like killing a hydra. I started blaming the “fast” way of doing things.
I needed to figure out what was wrong with our approach and transition into one that would result in “making stable software”. My gut feeling told me that we needed to become better at “decoupling” and “breaking the code into smaller pieces”.
But I was missing the direct link between my gut feeling and how it would translate into “stable software” until I saw a tweet which brought the things together:
one of the most important quality parameters for stable code is that it not change too much - apart from the essential bugs of course #hint
Okay I could easily follow the logic: Code that doesn’t change much, is usually a sign of stable code (why change it, if it works - right?).
The solution would be to write code that doesn’t need to be changed in the first place, and when “decoupling” and “breaking code into smaller pieces” are done correctly, it does exactly that. Code impacted by changes is greatly reduced.
Imagine a piece of software consisting of a single function. Now every time a change is made (a bug is fixed or a feature is implemented) in that function 100% of the system is changed. If instead it was possible to split this function up into 3 functions then having to change a function would only mean that 33% of the system was changed.
33% beats 100% every time.
And before someone says it I would like to entertain the possibility that the exact same code from the 3 functions was gathered in 1 function. What would be the difference?
The computational results of the two pieces of code right then and there would of course be the same. But the fact that the code isn’t already split up is in my experience a sign of too tightly coupled code. Also having the code split up usually makes it both easier to test and reason about (win/win).
Having to change a long chain of functions to fix a bug or implement a new feature is usually ALSO a sign of too tightly coupled code. Just to point out that having a lot of functions doesn’t necessarily decouple the code :-)
Anyways… for identifying both what and how to “decouple” and “break down” code, I use my “hands on” experience from functional programming and async systems. Also reading about S.O.L.I.D. principles is i good source of inspiration, though nothing beats “hands on”.
16 May 2015
When learning something new (in this case Laravel and it’s ORM Eloquent) it is always nice to be able to “look behind the curtains” to see what actually happens. This both help you understand the internals of the things you are using and can sometime make bug squashing a lot easier.
I wanted to be able to see the SQL that Eloquents query builder was producing, because SQL is something I’m fairly proficient with.
I found several questions and answers on different approaches on StackOverflow but one approach stood out for me: Using Laravels internal events.
Every time Laravel does anything through a database connection an event i fired with the prepared statement and its bindings. But creating SQL queries from this still required some manual labor because I needed to replace all the question marks with the binding in order.
So to close this gab further I had the prepared SQL and bindings crunched by
sprintf before writing it to a log file or stdout, like so:
function($query, $params, $time, $conn)
$sql = str_replace('?', '%s', $query);
$preppedSql = call_user_func_array('sprintf', array_merge([$sql], $params));
echo $preppedSql . "\n"; // or write it to a log file
28 Apr 2015
I had a problem where I needed to partition a collection when ever a specific element occurred.
The data I was working with wasn’t numbers but for the sake of making an example lets imagine something like the following where
1 indicates a new partition:
(def coll [1 2 3 4 5 1 2 3 1 2 3 4])
I started looking a partition-by which resulted in:
> (partition-by #(= 1 %) coll)
((1) (2 3 4 5) (1) (2 3) (1) (2 3 4))
After a short while I came to the conclusion that non of the existing core functions
split-with did what I needed. The closest function I could think of was
clojure.string/split but I wasn’t working with a string and also the “splitter” needed to be kept.
I needed an end result like the following:
((1 2 3 4 5) (1 2 3) (1 2 3 4))
I went down several mental paths trying to find a solution that didn’t feel clumpsy. Suddenly realize that
partition-by actually wasn’t that far off.
I got the following working and named my function
(map (fn [[a b]] (concat a b))
(partition-all 2 (partition-by f coll))))
I didn’t like the above anonymous function which led me to the followin end result:
"Like partition-by except it splits every other time f returns a new value."
(map #(apply concat %) (partition-all 2 (partition-by f coll))))
I haven’t tested the performance of it compared a loop-recur solution, but I’m pretty happy about the readability of it. I find my self time and again solving a problem in one way, just to realize that there is a better (often shorter aka. more readable and resource effecient) way.
I don’t think Clojure will ever stop amaze me with the endless compositions of core functions.
07 Jan 2015
Around 5 years ago a colleague of mine tried to spark some interest for Clojure. He described it using terms like functional, higher order functions, pure functions, composable, immutable data, lazy evaluated, code is data and vice versa, macros, concurrency etc. None of which I truly understood at the time but instead felt like buzzwords.
So instead of making me jump on the bandwagon, he left me with the question:
What’s so cool about Clojure?
His enthusiasm and a little 15 minute REPL session showing off some data structures and concurrency made an impression I couldn’t shake. It felt awesome and I couldn’t explain why… I still didn’t have an answer to my question, only a feeling!
After 3 years of naively waiting for Eureka, I realized that I needed to get out of my narrow comfort zone and commit to the learning process. So I decided to take the plunge and I felt good about it. After all I knew I still had a lot to learn - in retrospect that was an understatement.
The more you know, the more you know you don’t know. - Aristotle
There was a gap in my knowledge about programming, sometimes entire concepts was unfamiliar other times I had “invented” similar concepts myself without knowing that it was “text book stuff” and it already had a name. To close this gap I needed to start out on familiar ground with something I could relate to and work my way up from there.
I now see that my journey to answer my own question has actually been more about programming in a broad sense than about Clojure as a programming language. The “buzzwords” is starting to make sense and it has got me thinking about how I would have introduced these to my not-knowing-self a few years back. Lately specifically “Lazy sequences”.
I have some notes which might become a blog post in the near future… so stay tuned if you want to know what all the fuzz is about.