<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Vithun's Blog</title>
 <link href="https://www.vithun.com/atom.xml" rel="self"/>
 <link href="https://www.vithun.com/"/>
 <updated>2026-05-20T06:55:32+01:00</updated>
 <id>https://www.vithun.com</id>
 <author>
   <name>Vithun Gajendra</name>
   <email></email>
 </author>

 
 <entry>
   <title>50 Years of Apple</title>
   <link href="https://www.vithun.com/posts/50-years-of-apple/"/>
   <updated>2026-04-24T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/50-years-of-apple</id>
   <content type="html">&lt;p&gt;As Apple celebrated 50 years of existence this month, here are 5 things (amongst many more) that I have picked up and imbibed deeply in how I go about my work.&lt;/p&gt;

&lt;h2 id=&quot;look-forward-not-back&quot;&gt;Look Forward, Not Back&lt;/h2&gt;

&lt;p&gt;Apple is famous for not celebrating the past too much (although 50 years is a valid exception!). Such celebrations are just are not worth the time. There is more of the future yet to be invented that there is no point to sit on the laurels of the past.&lt;/p&gt;

&lt;p&gt;I’ve realised this is a useful personal mantra too. You can always get too attached to a project to the point where you think it’s your baby and you can’t let it go. Truth is, whether it was an absolute success or an absolute failure, it does not define you. Those are just a moment in time. Resetting to zero as soon as you can is always a super-power. It keeps you hungry for what’s next.&lt;/p&gt;

&lt;p&gt;As I write this, I have just completed 5 years at Maersk. What I have done in 5 years is irrelevant, it’s now in the past. I reset to zero and start fresh again tomorrow.&lt;/p&gt;

&lt;h2 id=&quot;work-backwards-to-the-technology&quot;&gt;Work Backwards to the Technology&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=oeqPrUmVz-o&quot;&gt;Steve Jobs in 1997&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One of the things I’ve always found is that you’ve got to start with the customer experience and work backwards to the technology. You can’t start with the technology and try to figure out where you’re going to try to sell it. And I’ve made this mistake probably more than anybody else in this room. And I got the scar tissue to prove it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Such a simple and obvious idea. Equally hard to implement and scale across teams on a continuous basis because: on the one-hand you don’t want to get blind-sided and not allow room for new technological discoveries; and on the other hand, you always want to be able to tie something back to making life better for our users. I try my best to maintain the balance, and when I have a bias it’s towards the user experience.&lt;/p&gt;

&lt;h2 id=&quot;innovation-does-not-happen-overnight&quot;&gt;Innovation Does Not Happen Overnight&lt;/h2&gt;

&lt;p&gt;From &lt;a href=&quot;https://daringfireball.net/2010/05/this_is_how_apple_rolls&quot;&gt;Daring Fireball&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is how the designers and engineers at Apple roll: They roll.&lt;/p&gt;

  &lt;p&gt;They take something small, simple, and painstakingly well considered. They ruthlessly cut features to derive the absolute minimum core product they can start with. They polish those features to a shiny intensity. At an anticipated media event, Apple reveals this core product as its Next Big Thing, and explains — no, wait, it simply shows — how painstakingly thoughtful and well designed this core product is. The company releases the product for sale.&lt;/p&gt;

  &lt;p&gt;Then everyone goes back to Cupertino and rolls. As in, they start with a few tightly packed snowballs and then roll them in more snow to pick up mass until they’ve got a snowman. That’s how Apple builds its platforms. It’s a slow and steady process of continuous iterative improvement—so slow, in fact, that the process is easy to overlook if you’re observing it in real time. Only in hindsight is it obvious just how remarkable Apple’s platform development process is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There’s a lot of hype and buzz created in the name of innovation and showing shiny, new things. They start off great, but soon the makers lose interest and go pursue the next shiny thing. Apple doesn’t typically work that way. They never seem to be in a hurry to show something that everyone else is doing. They take time and do it their own way. And once they bring that take to the market, pretty often you can trust them to keep iterating on it. And gradually it grows from strength and strength into perfection in a few years time. Being patient and focused for those few years is the key!&lt;/p&gt;

&lt;p&gt;Every time we build something, I tell myself the same: Not worth celebrating yet, there’s a lot more to be done. Time to put the heads down again.&lt;/p&gt;

&lt;h2 id=&quot;the-work-is-your-brand&quot;&gt;The Work is Your Brand&lt;/h2&gt;

&lt;p&gt;Mobile phones in the 90s used to look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/photos/motorola.jpg&quot; alt=&quot;Motorola&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;By © Raimond Spekking / CC BY-SA 4.0, via &lt;a href=&quot;https://commons.wikimedia.org/w/index.php?curid=162514478&quot;&gt;Wikimedia Commons&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/photos/nokia.jpg&quot; alt=&quot;Nokia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Soltys0, CC BY-SA 2.5, via &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/2.5&quot;&gt;Wikimedia Commons&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Here’s how the iPhone looked when it launched:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/photos/apple-iphone.jpg&quot; alt=&quot;Apple iPhone&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Rafael Fernandez, CC BY-SA 4.0, via &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/4.0&quot;&gt;Wikimedia Commons&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Notice the difference. There is no word “Apple” front and center on the iPhone. All the focus instead is on the user experience. But everyone knows it is built by Apple.&lt;/p&gt;

&lt;p&gt;When you build something insanely great, the product you build becomes the brand. It’s a handy reminder everyday in a world where I have sometimes seen feature announcements where the list of credits is longer than the description of the feature itself!&lt;/p&gt;

&lt;h2 id=&quot;team-first-and-a-long-term-view-on-people&quot;&gt;Team First and a Long Term View on People&lt;/h2&gt;

&lt;p&gt;And finally to the builders who make it all happen!&lt;/p&gt;

&lt;p&gt;Lone geniuses can only go so far. Insanely great work can happen only when you have a bunch of people gelling together such that they force each other to punch above their weight. And to recruit such people and create that team culture, you need to invest deliberately and it takes time, sometimes longer than you expect. But once it starts bearing fruit, the magic unfolds. I have experienced this first-hand multiple times.&lt;/p&gt;

&lt;p&gt;Nobody explains this as well as &lt;a href=&quot;https://www.youtube.com/watch?v=LUm76QQevPA&quot;&gt;Steve Jobs himself&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/LUm76QQevPA?si=fdNEQNqdx8zS9b-V&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</content>
 </entry>
 
 <entry>
   <title>180 Degrees</title>
   <link href="https://www.vithun.com/posts/180-degrees/"/>
   <updated>2023-09-13T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/180-degrees</id>
   <content type="html">&lt;figure&gt;
  &lt;img src=&quot;/public/photos/180-degrees.jpg&quot; alt=&quot;A batsman going after a delivery in Cricket&quot; /&gt;
  &lt;figcaption&gt;
    Photo by &lt;a href=&quot;https://unsplash.com/@jluebke?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Justin Luebke&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/BkkVcWUgwEk?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://book.stevejobsarchive.com&quot;&gt;Make Something Wonderful&lt;/a&gt; puts together many of Steve Jobs’s notes and messages in his own words. One thing that stayed with me was an email exchange between him and Andy Grove, in which over the course of a mail thread Steve Jobs ends up completely changing his mind.&lt;/p&gt;

&lt;p&gt;Below is the relevant part of the mail thread with most other text redacted. Click through &lt;a href=&quot;https://book.stevejobsarchive.com&quot;&gt;this link&lt;/a&gt; and search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;180 degrees&lt;/code&gt; in the content to read the relevant thread in whole.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;From: Steve Jobs
To: Andy Grove
Subject: Re[2]: Pixar-3D graphics
Date: October 1, 1995, 3:50 p.m.

Andy,

[redacted]

Therefore, I have changed my position 180 degrees - [redacted].
Thanks for the clearer perspective.

Steve
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As strong-minded as Steve Jobs, his strength is also demonstrated in the openness and humility to change his mind 180 degrees when faced with a reasoning to do so. Many good leaders exhibit this quality…&lt;/p&gt;

&lt;p&gt;A few years ago, in a previous job, I had the good fortune of participating in one of the orientation days &lt;a href=&quot;https://twitter.com/sh0kunin&quot;&gt;Aman Bhutani&lt;/a&gt; used to run for the engineering organisation he led. Aman used to have a list of principles he used to talk about. While many of those stayed with me, the one relevant to this post is “Strong opinions, loosely held”. While investing in the team culture, Aman encouraged us to have strong opinions and be vocal about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strong Opinions&lt;/strong&gt;: Being meek about one’s ideas or opinions means those ideas would be discarded at the earliest challenge, whether it’s from a louder colleague, or a boss, or one with a fancier title. And that’s not a great way to foster the growth of ideas, especially when they are freshly-formed or brittle. To build a culture brimming with more ideas, and an environment where these ideas get strengthened by sharing widely and being challenged openly, it becomes imperative to encourage having these strong opinions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loosely Held&lt;/strong&gt;: As strong as the opinions are, holding onto them dearly (especially based on the ego that it originated from you) invariably ends up creating friction that comes in the way of collaboration and progress. This is where good leaders (“lead” as in “lead the way forward”; nothing to do with job titles) are open to changing their mind 180 degrees. This is because they do not attach the idea to themselves or any person, but they think of it as a hypothesis that is bound to change if evidence suggests otherwise. Being able to change one’s mind (or &lt;a href=&quot;https://en.wikipedia.org/wiki/Disagree_and_commit&quot;&gt;disagree and commit&lt;/a&gt;) helps get onto the same page with one’s collaborators and move ahead with the sort of cohesion that can’t be created otherwise.&lt;/p&gt;

&lt;p&gt;Teams/organisations where this principle is not effectively practiced can run into one of two problems:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;People can’t get along, and any friction stays open coming in the way of collaboration. While this isn’t great for the organisation, the symptoms are at least clear for a leader to recognise this and step in sooner to address the issue.&lt;/li&gt;
  &lt;li&gt;People try to avoid conversations on such hard topics, and try to stay diplomatic. Compromise solutions are found where possible to keep everyone happy (usually not a great idea: the best way to split a five-dollar bill is not by tearing it into two and giving each party one piece). These symptoms don’t show up as early as the previous one, and can lead to late and sudden discovery of problems after a prolonged period of everything appearing hunky dory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, practice having strong opinions but hold them loosely. Encourage this in the people around you. Be comfortable changing your views 180 degrees. Try your best to be right. But celebrate being wrong, because it’s a step towards being right. Ultimately, this all boils down to a scientific way of thinking. As Adam Grant says in his book &lt;a href=&quot;https://adamgrant.net/book/think-again/&quot;&gt;Think Again&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’ve noticed a great paradox in great scientists and superforecasters: the reason they are so comfortable being wrong is that they’re terrified of being wrong. What sets them apart is the time horizon. They’re determined to reach the correct answer in the long run, and they know that means they have to be open to stumbling, backtracking, and rerouting in the short run. They shun rose-colored glasses in favor of a sturdy mirror.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>
 
 <entry>
   <title>Playing the Long Game</title>
   <link href="https://www.vithun.com/posts/playing-the-long-game/"/>
   <updated>2022-11-09T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/playing-the-long-game</id>
   <content type="html">&lt;figure&gt;
  &lt;img src=&quot;/public/photos/cricket-batting.jpg&quot; alt=&quot;A batsman going after a delivery in Cricket&quot; /&gt;
  &lt;figcaption&gt;
    Photo by &lt;a href=&quot;https://unsplash.com/@bushmush?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;michael weir&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/cricket?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I love sport analogies. Taking a mental model from a particular sport and applying it to different areas of life is always an interesting mental exercise. This post describes one that I keep coming back to.&lt;/p&gt;

&lt;p&gt;I was once in a heated situation at work and responding to someone when another colleague told me something profound. He said: “Do you know you don’t have to react to everything?”. This stayed with me for a while. It sounded familiar to something I had heard about a decade before that experience. I was in my teens and playing Cricket in the nets, and batting against the leather ball for the first time. I kept edging a lot of deliveries. The coach came up to me and said something along the lines of: “Do you know you don’t have to hit every ball?”.&lt;/p&gt;

&lt;p&gt;As Cricket itself has evolved into different formats, I keep thinking about this analogy. Test Cricket, which is considered to be the purest form, is played over the longest timespan. As a batsman, success in no other format beats what one achieves in Test Cricket. But success here is hard-earned. One has to be prepared to let a lot of deliveries go, and be very choosy about which deliveries to score off of. This is in stark contrast to T20 Cricket, which has a way shorter timespan, where the norm is more and more to look to maximise each delivery while placing a smaller premium on one’s wicket. So “letting a delivery go” is out of fashion here.&lt;/p&gt;

&lt;p&gt;What the above tells me is that the longer the game one is in, the more they have got to be able to let something go. And not just let it go, but take it off their mind and start from blank for the next thing coming their way. Reacting to everything is something one does when having a shorter-term mindset.&lt;/p&gt;

&lt;p&gt;A thing to note is that taking any model to the extreme is usually counter-productive. Just like leaving every delivery in Test Cricket and never scoring much becomes pointless after a while (and gets one dropped from the team), so is never reacting to anything. The trick is always choosing just the right things to react to and let most of the other things alone. Easier said than done, of course.&lt;/p&gt;

&lt;p&gt;Related resource: &lt;a href=&quot;https://www.amazon.co.uk/dp/0241295599/&quot;&gt;The Infinite Game&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Building Resilience within Constraints</title>
   <link href="https://www.vithun.com/posts/building-resilience-within-constraints/"/>
   <updated>2022-08-12T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/building-resilience-within-constraints</id>
   <content type="html">&lt;p&gt;The constraints that life has placed at different phases have helped build a certain resilience that make me not take the eventual absence of constraints for granted. Instead I’m in a more balanced state to deal with the positive changes, while mindful that both success and failure are never permanent.&lt;/p&gt;

&lt;p&gt;As Rudyard Kipling says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you can meet success and failure and treat them both as impostors, then you are a balanced man, my son.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;money&quot;&gt;Money&lt;/h2&gt;

&lt;p&gt;I grew up in the middle class Bangalore of the 90’s. In my formative years, there were phases where my parents could just about make ends meet. I remember in my early college days, my daily allowance would exactly afford me my bus charge to college and back. With my college being close to a commercial hub, I’d longingly look at the shops, wishing that one day I could buy all the gadgets, clothes, and food I wanted to.&lt;/p&gt;

&lt;p&gt;About a decade and a half later, as I visited the same place, I could now afford to buy any of those. But I no longer wanted to buy everything anymore. I had learnt to live my life within limits.&lt;/p&gt;

&lt;h2 id=&quot;job&quot;&gt;Job&lt;/h2&gt;

&lt;p&gt;I worked at a company for close to 7 years in my late 20’s and early 30’s. The company sponsored my visa to live in the UK. Like any job, it had its ups and downs. During the days with downs, I wanted to quit and join another company. But I had to grin and bare as the hassle with shifting visa sponsorship was too high. I’d longingly look at job advertisements wishing that one day I could apply and go work wherever I wanted to.&lt;/p&gt;

&lt;p&gt;A few years later, when I got granted permanent residence in the UK, I no longer depended on the company for my visa. I could afford to join any other company I wanted. But by then I had learnt to work through hard times. I no longer wanted to leave simply because of some hard days. I ended up staying on for a while after.&lt;/p&gt;

&lt;h2 id=&quot;title&quot;&gt;Title&lt;/h2&gt;

&lt;p&gt;Working my way into my career, I used to think that my lack of seniority and title comes in the way of sometimes taking opinionated decisions and pushing through with them. I used to think that one day I would have the title where I could simply tell people what to do and they’d listen.&lt;/p&gt;

&lt;p&gt;And then when I got the titles and the power that comes with it, I no longer wanted to indiscriminately use it with people. I would rely more on influencing through building trust, relationships, rationale and narratives, the way I had learnt to over all the years without such titles.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Know the Bigger Picture</title>
   <link href="https://www.vithun.com/posts/know-the-bigger-picture/"/>
   <updated>2022-04-13T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/know-the-bigger-picture</id>
   <content type="html">&lt;p&gt;The automatic rising arm at the entrance of my gym’s parking lot has been broken for the last few weeks. Everyday when I get in, I see the bit that is left of the arm (can I call it the shoulder?) still doing its job dutifully.&lt;/p&gt;

&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; src=&quot;/public/videos/parking-barrier-rising-arm.mp4&quot;&gt;
  &lt;img src=&quot;/public/photos/parking-barrier-rising-arm.png&quot; alt=&quot;Broken rising arm of parking barrier&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;It was a good reminder that we can sometimes focus too much on doing our part of the job well and lose sight of whether the things around it are functioning as well.&lt;/p&gt;

&lt;p&gt;We might think: “Hey, I’ve been tilting up to let the car through and reverting back down when it’s done and that is exactly what I was supposed to do”. But we forget that the actual job to be done was controlling the cars getting through, and that job is no longer being done.&lt;/p&gt;

&lt;p&gt;Related thought: &lt;a href=&quot;https://www.youtube.com/watch?v=u4ZoJKF_VuA&quot;&gt;Start with Why&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Approach as an Interviewer</title>
   <link href="https://www.vithun.com/posts/approach-as-an-interviewer/"/>
   <updated>2021-05-22T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/approach-as-an-interviewer</id>
   <content type="html">&lt;p&gt;I have conducted many interviews over the last few years. I have also been on the other side recently interviewing for a new role. Both these perspectives have helped shape two simple guiding principles I follow for when I’m interviewing a candidate for a role.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Principle 1: Create a positive value add for the team hiring the role&lt;/li&gt;
  &lt;li&gt;Principle 2: Facilitate the candidate landing their next role&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;principle-1-create-a-positive-value-add-for-the-team-hiring-the-role&quot;&gt;Principle 1: Create a positive value add for the team hiring the role&lt;/h2&gt;

&lt;p&gt;This principle might sound obvious. But to do it well, it is necessary to understand the gaps in the team. While this is easier when I’m interviewing for my immediate team, it needs some due diligence when stepping in to interview candidates for other/wider teams. In those instances, in addition to the job description, I try to dig into a bit more detail with the hiring manager about the sort of work that the person joining the team would be doing. This is especially important when some job descriptions list so many things as ideal that it is really hard to find a candidate who checks all the boxes. Having a priority stack in mind of what are actually required, and what are nice-to-haves helps focus on key areas.&lt;/p&gt;

&lt;p&gt;(Ideally the job description itself clearly distinguishes this, but I still run into many that don’t. That’s a whole different topic though, and I can refer the reader to check &lt;a href=&quot;https://www.linkedin.com/business/talent/blog/talent-acquisition/must-dos-for-writing-inclusive-job-descriptions&quot;&gt;this article&lt;/a&gt; out.)&lt;/p&gt;

&lt;h2 id=&quot;principle-2-facilitate-the-candidate-landing-their-next-role&quot;&gt;Principle 2: Facilitate the candidate landing their next role&lt;/h2&gt;

&lt;p&gt;This principle keeps me in the mindset of looking for reasons to hire rather than looking for reasons not to. When the candidate demonstrates enough skills/qualities that I’m convinced will add value to the team, the decision is simple: I recommend we hire them. But where this principle really makes a difference is when I’m convinced that the candidate is not a good fit. Rather than ending with a plain rejection, I make sure to write specific feedback. When doing so, I ask myself if the candidate was interviewing elsewhere in the near future, what are the small list of specific things they can work on which will increase their odds of success. They might not end up working for my company in this instance, but I feel I owe it to the time they have put in to help them along their journey.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The Kuchcha House</title>
   <link href="https://www.vithun.com/posts/the-kuchcha-house/"/>
   <updated>2021-01-17T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/the-kuchcha-house</id>
   <content type="html">&lt;p&gt;It was a summer afternoon. This meant it was the season of mangoes. Every year, around this time, we would have a plastic tub at home that seemed to always be filled with mangoes. This year was no different.&lt;/p&gt;

&lt;p&gt;I was around 6 or 7 years at the time. It was summer vacations at school, so I was mostly at home. I finished my lunch and took two mangoes from the tub. I had to have lunch first. The grownups used to say: “Have a jackfruit on an empty stomach, and have a mango on a full one”. If the grownups said it, they were probably right.&lt;/p&gt;

&lt;p&gt;I ate my mangoes fully, except for the skin and the seeds of course. They were ripe and sweet, and I remember thinking that nothing else comes close to how happy it made me feel. I then went and threw the mango skin and seeds out of our rear balcony.&lt;/p&gt;

&lt;p&gt;Our house was a two-storey building. We lived on the first floor. We had a balcony on the back which faced an empty “site” – a plot of land allotted to build a house. Houses had already been built on either sides of this site. Whoever owned this site probably had no plans of building a house there yet. So it was in a pretty unkempt state housing a lot of weeds that wanted to grow there, the main one being parthenium. Us, as well as people from the houses on either sides of the site used to throw out garbage and food waste into the site.&lt;/p&gt;

&lt;p&gt;I used to imagine this site as a “peninsula”. In school I had learnt that a peninsula is covered on three sides by water and one side by land. I equated this site being covered on three sides by houses (one of it our own) and one side by the road in front of it to being a peninsula. Our schooling then was limited to what we saw in text books. This was before computers and internet became commonplace. So to think beyond what we saw in a text book, one’s imagination was the only way. You can see why I imagined the site as a peninsula – I couldn’t really go see an actual peninsula.&lt;/p&gt;

&lt;p&gt;One morning a few days later, when I went to throw some waste away, I was pleasantly surprised by something else that had cropped up in the site pretty much overnight. This was another thing I had learnt in school, and only seen in the text books – a hut. I had learnt that there were two types of houses: pucca houses and kuchcha houses. Pucca houses were built strongly in a way that would withstand the weather and other challenges well. Kuchcha houses, on the other hand, could not withstand these well as they were built of weak materials like straws, hay, and other materials like a dried old coconut tree’s leaves. I knew we lived in a pucca house, but I had never seen a kuchcha house. Until that day.&lt;/p&gt;

&lt;p&gt;I stood staring there in amazement. It looked like a family of four – a couple and two kids – were living inside. One kid was very young, probably less than two years old. The other one was around my age. I wondered if he went to school like me. His mother seemed to dress in a manner that was similar to the maid who used to come clean our home everyday. Our maid used to bring her kid with her who used to just sit in a corner while the mother finished the chores. I wondered if this kid in the site behind also just tagged along with his mother on her everyday work. I was envious of him, because I had to get ready and go to school on time. He appeared to be free.&lt;/p&gt;

&lt;p&gt;I came back inside excitedly and told everyone that there is a kuchcha house behind our house. I opened my textbook and saw the picture in it. This hut looked so similar. I couldn’t wait to go to school and share this news with my friends. However, to my astonishment, I did not get the reaction I expected from the grownups. They didn’t seem to share my excitement. They went to the rear balcony. Folks living on the either sides of the site had also come out. They were enquiring the family who had moved into the hut – “Who are you?”, “Where are you from?”, “Why have you built this hut here?”. The tone of questioning didn’t seem friendly or enthusiastic.&lt;/p&gt;

&lt;p&gt;I headed to school and shared the story of the magical kuchcha house that had been built overnight with my friends. I pointed to the picture in our textbook and told them it looked exactly like in the picture. I promised I’d show it to them if they visited my place.&lt;/p&gt;

&lt;p&gt;On getting home in the evening, I rushed to the balcony. The hut wasn’t there anymore. I was confused and disappointed. I asked folks at home about it. They told me the hut wasn’t supposed to be there. That the people in the hut did not own the site. Folks of all the houses around the site had opposed to them being there and had forced them to move out. The grownups told me it was for the good of everyone. They told me that the folks in the kuchcha house would have littered the site if they had been allowed to stay for long. If the grownups said it, they were probably right.&lt;/p&gt;

&lt;p&gt;Slowly, I washed my face and had my dinner. I followed it up with two mangoes. I then went and threw the mango skin and seeds out into the site behind.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/photos/kuchcha-house-sketch.jpg&quot; alt=&quot;Sketch of a Kuchcha house&quot; /&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>If All You Have Is A Hammer&hellip;</title>
   <link href="https://www.vithun.com/posts/if-all-you-have-a-hammer/"/>
   <updated>2020-12-18T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/if-all-you-have-a-hammer</id>
   <content type="html">&lt;p&gt;Over the last few years in my work, I have come across situations where a particular technology has been sold as a silver bullet. This is usually by people who have seen those technologies succeed for them under a certain context, who then push for adopting the same in wider contexts.&lt;/p&gt;

&lt;p&gt;I have seen this tendency result in a push for using an event-driven way (and use Kafka) in cases where a traditional request-response mechanism would have been simpler. I have seen folks building an in-house framework for isomorphic rendering and evangelise its adoption when &lt;a href=&quot;https://developers.google.com/web/updates/2019/02/rendering-on-the-web&quot;&gt;common sense suggests to pick a rendering approach based on specific needs&lt;/a&gt;. And most recently, I have had to contend with folks pushing to use React to construct email content.&lt;/p&gt;

&lt;p&gt;A good consequence of going through this experience repeatedly means now I am able to clearly articulate a thought process to counter such silver bullet tool/technology prescriptions. It starts with two questions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Does using the recommended tool/technology drastically simplify solving the problem at hand?&lt;/li&gt;
  &lt;li&gt;Do the people on the team have the skill in (or the appetite to learn) this new tool/technology?&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;If the answer to the first question is “No”, then there is not enough of a reason to adopt something new. And this becomes especially true if the answer to the second question is also a “No”.&lt;/li&gt;
  &lt;li&gt;If the answer to the first question is “Yes”, then it is worth pushing for it a bit even if the answer to the second question is “No”. But ultimately the success of adopting the new approach will be dependent on how well the team buys in.&lt;/li&gt;
  &lt;li&gt;Needless to say, two “Yes”-es is the ideal situation to use something new.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me now walk through applying this thought process for the “use React to construct email content” argument. The people recommending to use React were developers who had used it successfully to build interactive web components (and some folks who had not really used React but had drank the kool-aid).&lt;/p&gt;

&lt;p&gt;The first question now became: “Does using React make generating HTML content for email simpler?”. My first answer is “No”. Let me elaborate…&lt;/p&gt;

&lt;p&gt;The main difference between the general web (where React shines) and email is that the latter does not really have the concept of JavaScript executing on the client-side. React is a JavaScript library for building user interfaces (and it especially shines for its declarative nature of building interactive UI on the client). Putting these two statements together logically leads to the observation that using React is not really a first-pick for constructing email content.&lt;/p&gt;

&lt;p&gt;But I still wanted to entertain the counter-point. I tried to think what could make the answer to “Does using React make generating HTML content for email simpler?” a “Yes”. And one situation where that can happen is if a team is already super-comfortable using React and have already built a library of components in a way that those components can be reused as is within email (Note: this is a huge leap of faith because building for email is in some cases trickier/hackier than building for the browsers). And this brought me to the second question…&lt;/p&gt;

&lt;p&gt;“Are people in the team already familiar with React?”. The answer was a “No”. The team was mostly made of folks who were very familiar building email content using HTML (via a templating language) and CSS for years. It made no sense to suddenly make all of them learn JavaScript (and React specifically) just because some developers who built web components using the same felt we ought to give it a try.&lt;/p&gt;

&lt;p&gt;As the answers to both questions were a “No” for our context, the decision became obvious.&lt;/p&gt;

&lt;h2 id=&quot;related-thought&quot;&gt;Related Thought&lt;/h2&gt;

&lt;p&gt;I think with respect to learning a new technology, people can go through these phases in order:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Reluctance to use the technology as they don’t know it&lt;/li&gt;
  &lt;li&gt;Appetite to experiment with the technology&lt;/li&gt;
  &lt;li&gt;Familiarity with the technology and a tendency to advocate for its use anywhere and everywhere&lt;/li&gt;
  &lt;li&gt;Wisdom about the technology – knowledge when to use it, and more importantly when NOT to&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When someone advocates for a technology, try to figure out if they are in 3 or 4. If they are in 3, beware and take what they say with a pinch of salt.&lt;/p&gt;

&lt;h2 id=&quot;another-related-thought&quot;&gt;Another Related Thought&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://daringfireball.net/2014/02/working_backwards&quot;&gt;Working Backwards to the Technology&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Context We See People In</title>
   <link href="https://www.vithun.com/posts/context-we-see-people-in/"/>
   <updated>2020-09-13T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/context-we-see-people-in</id>
   <content type="html">&lt;p&gt;If you have ten shirts and uniformly spread out wearing them, you would repeat a shirt every two weeks (assuming a 5-day working week).&lt;/p&gt;

&lt;p&gt;If you have a recurring meeting with someone everyday, they would come across the variation and probably not spend too much attention on one single shirt. At the other end, if you are meeting them once every two weeks at regular intervals, they might think you only have one shirt you always wear.&lt;/p&gt;

&lt;p&gt;In most cases, our randomness in shirt selection probably addresses this, but that’s not the point of this post. The point is extending this thought to beyond fashion: one thing to ask yourself when pigeonholing someone is if you always see them in the same context. Maybe you’d encounter a different picture if you occasionally saw them on a Thursday rather than a Monday.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Better Define Work-Life Boundary While Using Things</title>
   <link href="https://www.vithun.com/posts/work-life-boundary-while-using-things/"/>
   <updated>2020-07-16T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/work-life-boundary-while-using-things</id>
   <content type="html">&lt;p&gt;Working from home became the norm this year. While many people expected a drop in work productivity, the inverse turned out to be a dark horse. In the beginning, I easily kept sliding back to work even after my typical work hours. Got a Slack ping from someone in the US my night time (I’m based in UK), no problem – my work laptop is one room away. Unsurprisingly, soon all boundaries between work and home were blurred.&lt;/p&gt;

&lt;p&gt;I knew this behavior wouldn’t be sustainable for the long run. I had to design a way to make that boundary more clearly defined again. I removed all work-related apps from my phone. I didn’t really need to have Slack or work email in my hand/pocket anymore. If I badly needed to check on something, I was never going to be far from my work laptop anyway. And I tried to be disciplined about not returning to open my work laptop at crazy hours.&lt;/p&gt;

&lt;p&gt;This worked well. But there was one problem. I use &lt;a href=&quot;https://culturedcode.com/things/&quot;&gt;Things&lt;/a&gt; as my GTD system of choice. Up until now, I had one Things account and I’d capture all work tasks under a separate Area of Responsibility in Things. As I kept using Things this way, I realized this system still did not have the boundary between work and life that I was trying to achieve. Having work-related tasks visible in my Inbox, for example, would again trigger the urge sometimes to go action on it immediately on my work laptop. I had to break clean. The solution was simple: I created a separate Things account.&lt;/p&gt;

&lt;p&gt;That’s where the story should have ended. But it’s not that simple. Ideas can come anywhere, and Things was my trusted system to capture those. Now, if late at night, I suddenly got an idea about work I couldn’t put it in Things because my personal devices only had my personal Things account. I didn’t want to go and open my work laptop again. I wanted a fire-and-forget way of sending a quick idea/task to my work Things account without really having to go and open my work Things.&lt;/p&gt;

&lt;p&gt;And I did exactly that using Things’ &lt;em&gt;Mail to Things&lt;/em&gt; feature and a nifty shortcut in iOS.&lt;/p&gt;

&lt;p&gt;First, I enabled &lt;em&gt;Mail to Things&lt;/em&gt;. The instructions are documented &lt;a href=&quot;https://culturedcode.com/things/blog/2017/12/mail-to-things/&quot;&gt;here&lt;/a&gt;. This provides an auto-generated email address which I copied over.&lt;/p&gt;

&lt;p&gt;I then set up a workflow in Shortcuts. If you do not have Shortcuts installed, get it &lt;a href=&quot;https://apps.apple.com/gb/app/shortcuts/id915249334&quot;&gt;here&lt;/a&gt; (it can make your life simpler in various ways beyond what this blog post covers!). When the workflow is run, it prompts me to enter some text representing the task/idea I want to capture. It then sends this over as an email to my Mail to Things address. I can then immediately take my mind off it knowing I’ll find it safe in my work Things Inbox the next morning.&lt;/p&gt;

&lt;picture&gt;
    &lt;source srcset=&quot;/public/screenshots/work-task-workflow-dark.jpg&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
    &lt;img width=&quot;320&quot; src=&quot;/public/screenshots/work-task-workflow-light.jpg&quot; alt=&quot;Workflow: Step 1 ask input; Step 2 send email;&quot; /&gt;
&lt;/picture&gt;

&lt;picture&gt;
    &lt;source srcset=&quot;/public/screenshots/work-task-widget-checkbox-dark.jpg&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
    &lt;img width=&quot;320&quot; src=&quot;/public/screenshots/work-task-widget-checkbox-light.jpg&quot; alt=&quot;Show in Widget checkbox selected&quot; /&gt;
&lt;/picture&gt;

&lt;p&gt;By checking the box to show this workflow in the iOS Widget, I can now trigger this directly from the widget screen making the whole process of capturing a task almost absent of any cognitive load, which is exactly how it should be.&lt;/p&gt;

&lt;picture&gt;
    &lt;source srcset=&quot;/public/screenshots/work-task-widget-trigger-dark.jpg&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
    &lt;img width=&quot;320&quot; src=&quot;/public/screenshots/work-task-widget-trigger-light.jpg&quot; alt=&quot;Trigger available on iOS Widget screen&quot; /&gt;
&lt;/picture&gt;
</content>
 </entry>
 
 <entry>
   <title>Docker and Kubernetes Learning Resources</title>
   <link href="https://www.vithun.com/posts/docker-kubernetes-learning-resources/"/>
   <updated>2020-04-27T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/docker-kubernetes-learning-resources</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/photos/docker-k8s-vscode.png&quot; alt=&quot;Icons of Docker, Kubernetes, and Visual Studio Code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In 2018, I was new to Docker. In 2019, I was new to Kubernetes. Over the last year, I have been working a lot with both.&lt;/p&gt;

&lt;p&gt;While I believe the best way to learn any new technology is to use it continuously, there are usually some resources that help start off with a technology simpler than otherwise. In this post, I list the ones which made Docker and Kubernetes easy for me.&lt;/p&gt;

&lt;h3 id=&quot;docker--from-the-beginning&quot;&gt;Docker – From the Beginning&lt;/h3&gt;

&lt;p&gt;This series of blog posts from &lt;a href=&quot;http://twitter.com/chris_noring&quot;&gt;Chris Noring&lt;/a&gt; was completely accessible to me as a newbie, and helped me start with a good foundation.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/docker---from-the-beginning-part-i-28c6&quot;&gt;Part 1: Images and Containers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/softchris/docker-from-the-beginning---part-ii-5g8n&quot;&gt;Part 2: Volumes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/docker-from-the-beginningpart-iii-2h51&quot;&gt;Part 3: Databases and Linking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/docker-from-the-beginning-partiv-mi6&quot;&gt;Part 4: Docker Compose Basics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/dockerfrom-the-beginning-part-v-n2c&quot;&gt;Part 5: Docker Compose, Variables, Volumes, Networks and Databases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;kubernetes-basics&quot;&gt;Kubernetes Basics&lt;/h3&gt;

&lt;p&gt;As I was looking for something similarly accessible like the above, this series by &lt;a href=&quot;https://twitter.com/DanSanche21&quot;&gt;Daniel Sanche&lt;/a&gt; fit the bill.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/google-cloud/kubernetes-101-pods-nodes-containers-and-clusters-c1509e409e16&quot;&gt;Kubernetes 101&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/google-cloud/kubernetes-110-your-first-deployment-bf123c1d3f8&quot;&gt;Kubernetes 110&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/google-cloud/kubernetes-120-networking-basics-3b903f13093a&quot;&gt;Kubernetes 120&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;kubernetes--from-the-beginning&quot;&gt;Kubernetes – From the Beginning&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I have not gone through this series because by the time it was published, I was already comfortable with Kubernetes. I list this here simply because it is from the same author as the Docker series above, and so I expect this to be a beginner-friendly resource.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/kubernetes-from-the-beginning-part-i-4ifd&quot;&gt;Part 1: Basics, Deployment and Minikube&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/kubernetes-part-ii-revisiting-pods-and-nodes-and-introducing-services-and-labeling-5fi7&quot;&gt;Part 2: Pods, Nodes and Services&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/kubernetes-part-iii-scaling-1mmi&quot;&gt;Part 3: Scaling My App&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/azure/kubernetes-from-the-beginning-part-iv-autoscaling-54l6&quot;&gt;Part 4: Autoscaling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;visual-studio-code-kubernetes-extension&quot;&gt;Visual Studio Code Kubernetes Extension&lt;/h3&gt;

&lt;p&gt;If you are not a &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VS Code&lt;/a&gt; user, I would recommend you still install it just for this. And within VS Code, install the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools&quot;&gt;Kubernetes extension&lt;/a&gt;. This extension gives you a clickable way to explore all the Kubernetes concepts within your cluster.&lt;/p&gt;

&lt;p&gt;If you click on the Kubernetes icon on the sidebar, you will have your clusters listed. Once you choose a cluster, you will get a tree structure that you can click to expand/collapse and explore.&lt;/p&gt;

&lt;picture&gt;
    &lt;source srcset=&quot;/public/screenshots/vscode-k8s-sidebar-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
    &lt;img src=&quot;/public/screenshots/vscode-k8s-sidebar-light.png&quot; alt=&quot;Screenshot of VS Code Kubernetes extension&apos;s sidebar&quot; /&gt;
&lt;/picture&gt;

&lt;p&gt;You can then click on any of the leaf items, pods for example, and it’ll open up its YAML definition which you can study.&lt;/p&gt;

&lt;picture&gt;
    &lt;source srcset=&quot;/public/screenshots/vscode-k8s-pod-details-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
    &lt;img src=&quot;/public/screenshots/vscode-k8s-pod-details-light.png&quot; alt=&quot;Screenshot of VS Code Kubernetes extension showing pod YAML definition&quot; /&gt;
&lt;/picture&gt;

&lt;p&gt;You can also right-click on these items, and get a context-menu to launch further actions like following logs.&lt;/p&gt;

&lt;picture&gt;
    &lt;source srcset=&quot;/public/screenshots/vscode-k8s-pod-actions-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
    &lt;img src=&quot;/public/screenshots/vscode-k8s-pod-actions-light.png&quot; alt=&quot;Screenshot of VS Code Kubernetes extension&apos;s right-click context menu&quot; /&gt;
&lt;/picture&gt;

&lt;p&gt;All of these are, of course, possible by using the &lt;a href=&quot;https://kubectl.docs.kubernetes.io&quot;&gt;kubectl&lt;/a&gt; command-line. But I found mastering those commands not easy to begin with. Using the VS Code extension’s GUI, and visually organizing the concepts in my mind first helped me later when I started using the command-line more.&lt;/p&gt;

&lt;h3 id=&quot;kubernetes--up-and-running&quot;&gt;Kubernetes – Up and Running&lt;/h3&gt;

&lt;p&gt;A few days into working with Kubernetes, I got a copy of &lt;a href=&quot;https://www.amazon.co.uk/dp/1491935677&quot;&gt;Kubernetes Up &amp;amp; Running&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/kelseyhightower&quot;&gt;Kelsey Hightower&lt;/a&gt;. Reading through it, and connecting the concepts to my everyday usage helped solidify the learnings.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Gamifying Continuous Integration</title>
   <link href="https://www.vithun.com/posts/gamifying-continuous-integration/"/>
   <updated>2016-11-21T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/gamifying-continuous-integration</id>
   <content type="html">&lt;p&gt;Originally posted on &lt;a href=&quot;https://medium.com/expedia-engineering/gamifying-continuous-integration-de3808d7cbe1&quot;&gt;Expedia’s Tech Blog&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;For the last couple of years we’ve been moving applications from our data centers into the cloud. One of the advantages of moving to the cloud was that we could host our applications in different geographical regions bringing them closer to the user. Also each team working on an application gets the chance to easily have their app hosted on multiple environments (test/stress/integration/production). Having multiple versions of an application running at the same time across multiple regions and environments brought its own challenge of visibility. It was not straight-forward to know what’s running where and when.&lt;/p&gt;

&lt;p&gt;To solve this problem we started collecting data (based on events) about everything that happens in terms of our applications getting built, deployed, and deleted. This helped power dashboards that improved the visibility over what’s hosted where. Over months of collecting data, we started realising more usages for this data. One of the other characteristics of our team is that we are a very diverse group of engineers all over the world using a range of technologies. We’re always interested in ways to help spread and share great ways of working. With that in mind, one of the usages of this data we’re trying is a little game we created called Primer Go — “Primer” for the internal name we have for our CI/CD system, and “Go” inspired by Pokemon Go (it was over coffee talking about Pokemon Go which lead to a couple of us to think that we should create a game of some sort around our CI/CD).&lt;/p&gt;

&lt;p&gt;Primer Go is a monthly league. The scores get reset at the beginning of the month, and at the end of each month we have the application at the top of the league being declared a winner. The participants in the league are the huge number (over two thousand on last count) of different applications we have running. There are some minimum criteria that an application has to meet to be eligible to be on the league in a month; for example: they should have at least 3 new versions released to production. Each eligible application is scored (on a scale from 1 to 100) in multiple categories, and then the average across all categories is taken. As of this writing, there are 4 scoring categories:&lt;/p&gt;

&lt;h3 id=&quot;repository-information&quot;&gt;Repository Information&lt;/h3&gt;

&lt;p&gt;Within the company, we encourage having an open-source model of working. This means that any team can contribute to any project by just building the new feature they want and opening a pull request. For this to be effective, it is important that everyone make their repository more accessible. This means having high quality and up-to-date README file, contribution guidelines and notes about testing. We have a category in Primer Go that scores applications based on the above information being present, and on how recently they were updated.&lt;/p&gt;

&lt;h3 id=&quot;small-changes&quot;&gt;Small Changes&lt;/h3&gt;

&lt;p&gt;We encourage people to have a higher number of smaller pull requests, rather than one (or very few) huge pull request. This helps build stuff incrementally, makes it easier to isolate and roll back specific issues, and is also easier to review (increasing the chances of the code review being of a higher quality). This category within the game awards points based on the number of pull requests merged into the application in the month. The number of active developers on that application in the month is also taken into consideration to ensure that team sizes don’t heavily influence the scoring in this category.&lt;/p&gt;

&lt;h3 id=&quot;release-frequency&quot;&gt;Release Frequency&lt;/h3&gt;

&lt;p&gt;How frequently we are able to get new changes out for our users in a main factor that determines how well we are doing Continuous Delivery, and our game has a category to measure just that. We check how many new versions of the application were released to production in the month, and then divide that by the total number of versions (pull requests) merged into the code base. Teams that are closer to 100% in this category are the ones that are releasing each change in isolation into production before further changes are merged on top of it.&lt;/p&gt;

&lt;h3 id=&quot;release-speed&quot;&gt;Release Speed&lt;/h3&gt;

&lt;p&gt;This category measures how long it takes from the moment a change is merged into the main branch to the moment that change is released into production. The faster this is, the greater the score. This category makes people think more about their build pipelines (parallelising effectively), testing architecture, and the CI/CD infrastructure itself.&lt;/p&gt;

&lt;p&gt;Every month, the league helps us:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Recognise applications that are doing well. This also means that teams thus identified have a platform to share their best practices across the company.&lt;/li&gt;
  &lt;li&gt;Recognise areas of improvement for each application.&lt;/li&gt;
  &lt;li&gt;Have some fun :smile:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re constantly tuning and updating the criteria based on feedback from the community and data we’re seeing in the wild. Development metrics are great informers but if you rely on them exclusively or too heavily it is easy to accidentally encourage the wrong behaviors. So far we’ve found this sort of friendly competition is a great way promote how we want to work across a large audience.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Grails Multi-Tenant Plugin &amp; Spring Security Filter</title>
   <link href="https://www.vithun.com/posts/grails-multitenant-plugin-and-spring-security-filter/"/>
   <updated>2011-12-05T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/grails-multitenant-plugin-and-spring-security-filter</id>
   <content type="html">&lt;p&gt;We had a long-standing issue in our &lt;a href=&quot;http://grails.org/&quot;&gt;Grails&lt;/a&gt; project, where the “remember me” functionality was not working as we expected it to. It was behaving very inconsistently. Sometimes the user would be remembered, and sometimes not.&lt;/p&gt;

&lt;p&gt;Our application uses the &lt;a href=&quot;http://grails.org/plugin/spring-security-core&quot;&gt;spring-security&lt;/a&gt; plugin for authentication, and I initially wondered that there might be a bug in the “remember me” functionality of the plugin. On further investigation, I noticed that the problem was not actually in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-security&lt;/code&gt; plugin.&lt;/p&gt;

&lt;p&gt;Our application also uses the &lt;a href=&quot;http://grails.org/plugin/multi-tenant-core&quot;&gt;multi-tenant-core plugin&lt;/a&gt;, which resolves the tenant based on the request. The problem was that sometimes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multi-tenant-core&lt;/code&gt; plugin was not resolving the tenant (returning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; instead) when called within the authentication code of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-security&lt;/code&gt; plugin. Therefore, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-security&lt;/code&gt; was not finding a user by the respective username within the tenant represented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; (as such a tenant did not exist).&lt;/p&gt;

&lt;p&gt;The reason this was happening was because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multi-tenant-core&lt;/code&gt; plugin has a &lt;a href=&quot;http://www.grails.org/doc/1.3.x/guide/single.html#6.6%20Filters&quot;&gt;filter&lt;/a&gt; which calculates the current tenant and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-security&lt;/code&gt; has its own set of filters. The application was behaving as expected when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multi-tenant-core&lt;/code&gt;’s filter executed before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-security&lt;/code&gt;’s remember me filter, and erroneously otherwise. To fix this problem, we had to make sure that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multi-tenant-core&lt;/code&gt; plugin’s filter would &lt;strong&gt;always&lt;/strong&gt; execute before the spring-security filters.&lt;/p&gt;

&lt;p&gt;Adding a line to our application’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BootStrap.groovy&lt;/code&gt; did the trick:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.codehaus.groovy.grails.plugins.springsecurity.SecurityFilterPosition&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BootStrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;servletContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// To make sure it executes before all authentication filters&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SpringSecurityUtils&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clientRegisterFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;multiTenantFilter&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SecurityFilterPosition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PRE_AUTH_FILTER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Hibernate &amp; MySQL Spatial Index</title>
   <link href="https://www.vithun.com/posts/hibernate-and-mysql-spatial-index/"/>
   <updated>2011-11-30T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/hibernate-and-mysql-spatial-index</id>
   <content type="html">&lt;p&gt;While working on a Grails application which required spatial queries, I came across a problem. I had to make use of the &lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/relations-on-geometry-mbr.html#function_mbrcontains&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MBRContains&lt;/code&gt;&lt;/a&gt; function in MySQL. Since I was using &lt;a href=&quot;http://grails.org/&quot;&gt;Grails&lt;/a&gt; which in turn uses &lt;a href=&quot;http://www.hibernate.org/&quot;&gt;Hibernate&lt;/a&gt;, the &lt;a href=&quot;http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html&quot;&gt;HQL&lt;/a&gt; query I would write had to support these spatial functions.&lt;/p&gt;

&lt;p&gt;I used an extension of Hibernate Spatial dialect for the application’s data source dialect which I have explained in &lt;a href=&quot;/posts/combining-mysql-fulltext-and-spatial-search-grails/&quot;&gt;the previous post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few days after writing the code to perform some complex queries (which included spatial clauses in it), we noticed that the site’s performance was getting slower. While investigating, I found that for some reason, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MBRContainsfunction&lt;/code&gt; was not making use of the spatial index we had added on a column. This was a bit strange.&lt;/p&gt;

&lt;p&gt;I then obtained the SQL query that was being generated from the HQL query. We had the following as part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where&lt;/code&gt; clause in HQL query:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mbrcontains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeomFromText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;boundary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As expected, this was generating an SQL query in this form:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MBRContains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeomFromText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When I tested the above generated SQL query using &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/explain.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXPLAIN&lt;/code&gt;&lt;/a&gt;, I found that the spatial index was not being used by the query. A quick search on Google &lt;a href=&quot;http://stackoverflow.com/questions/3894994/mysql-spatial-index-doesnt-work-when-equating-mbrcontains-to-true&quot;&gt;showed me&lt;/a&gt; that I was not the only one with this problem. The problem here was the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;= 1&lt;/code&gt;” being generated in the SQL query because of the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;= true&lt;/code&gt;” in the HQL query. This, for some reason, was preventing the spatial index from being used. If I removed the “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;= true&lt;/code&gt;” in HQL query, it was resulting in some Unexpected AST node exception in Hibernate.&lt;/p&gt;

&lt;p&gt;I couldn’t find a proper solution for the problem anywhere on the net, and ironically XKCD published &lt;a href=&quot;http://xkcd.com/979/&quot;&gt;this cartoon&lt;/a&gt; on the very same day. We finally decided to rewrite the whole complex query in plain SQL to overcome this problem.&lt;/p&gt;

&lt;p&gt;About a week later, when it was time to start rewriting the query, I still felt a bit lazy about it. If only there was a simple way to solve the above problem, it would prevent me from having to sit for the next 2 to 3 days and rewrite a pretty complex query and test it thoroughly. And then I realised there was actually a way. It was quite simple actually, and sometimes it is the simpler things we tend to miss.&lt;/p&gt;

&lt;p&gt;All I did was register a new function with a tiny bit of hack in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MySQLDialect&lt;/code&gt; of our application:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;registerFunction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mbr_contains&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SQLFunctionTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Hibernate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;BOOLEAN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;MBRContains(?1, ?2) and 1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then I used this function in the HQL query. The query now became something like this:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mbr_contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeomFromText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(:&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;boundaryVariable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which is valid HQL, and also generates SQL which makes use of the spatial index:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MBRContains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeomFromText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Combining MySQL Full-Text &amp; Spatial Search In Grails</title>
   <link href="https://www.vithun.com/posts/combining-mysql-fulltext-and-spatial-search-grails/"/>
   <updated>2011-11-02T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/combining-mysql-fulltext-and-spatial-search-grails</id>
   <content type="html">&lt;p&gt;In the Grails &lt;a href=&quot;http://philevents.org/&quot;&gt;project I’m currently working on&lt;/a&gt;, we were required to have a search functionality which would take into account, among other things, location data (spatial query) and keywords (full-text query). For this we required our Hibernate queries to support the relevant features. This would be possible by using an appropriate MySQLDialect.
For spatial queries, we could use this dialect: &lt;a href=&quot;http://www.hibernatespatial.org/javadoc/4.0/org/hibernate/spatial/dialect/mysql/MySQLSpatialDialect.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.hibernatespatial.mysql.MySQLSpatialDialect&lt;/code&gt;&lt;/a&gt;. However, we also wanted Hibernate to support full-text queries. So I extended this dialect and wrote a custom dialect for our application. In this case, our custom dialect looked something like this:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.philevents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.hibernate.Hibernate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.hibernate.dialect.function.SQLFunctionTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MySQLDialect&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;hibernatespatial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;mysql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MySQLSpatialDialect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MySQLDialect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;registerFunction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;match_against&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SQLFunctionTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Hibernate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;BOOLEAN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;match ?1 against (?2 in boolean mode)&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;match_against&lt;/code&gt; function available in Hibernate. This takes two arguments (represented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?1&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?2&lt;/code&gt;) and performs the full-text search using MySQL’s &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html#function_match&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;match...against&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we have to make sure that our Grails application uses the above dialect class. This is done by configuring the dialect of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataSource&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/grails-app/conf/DataSource.groovy&lt;/code&gt;. Since I was using different data sources for different environments, my configuration looked something like this:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;environments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dataSource&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;dialect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;philevents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MySQLDialect&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dataSource&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;dialect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;philevents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MySQLDialect&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;production&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dataSource&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;dialect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;philevents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;MySQLDialect&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now a full-text query can be executed by something like this: Let us assume we have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Book&lt;/code&gt; domain class which has a field called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;abstract&lt;/code&gt;. We now have to search this field based on some given keywords. This is done by:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;executeQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;from Book b where match_against((abstract), ?) &amp;lt;&amp;gt; 0&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keywords&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Spatial queries can be executed by the features provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HibernateSpatialDialect&lt;/code&gt; class, and are available in our application as our custom dialect is a subset of it. Details of how we used spatial queries in our application will be provided in &lt;a href=&quot;/posts/hibernate-and-mysql-spatial-index/&quot;&gt;a future post&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Grails Image Crop Using Jcrop</title>
   <link href="https://www.vithun.com/posts/grails-image-crop-using-jcrop/"/>
   <updated>2011-05-31T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/grails-image-crop-using-jcrop</id>
   <content type="html">&lt;p&gt;You might have seen many websites nowadays have a profile picture. And when you upload a profile picture, you are usually prompted to crop the picture (sometimes with certain forced resolution), and it is this cropped picture that is used from then onwards. I was required to implement a similar functionality in the Grails &lt;a href=&quot;http://philevents.org/&quot;&gt;project I’m working on&lt;/a&gt;. I decided to use &lt;a href=&quot;http://deepliquid.com/content/Jcrop.html&quot;&gt;Jcrop&lt;/a&gt; for the JavaScript side of the cropping mechanism as it was based on &lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt; and we were already using jQuery in our application. Here, I illustrate how I did the job.&lt;/p&gt;

&lt;p&gt;I first downloaded Jcrop from &lt;a href=&quot;http://deepliquid.com/content/Jcrop_Download.html&quot;&gt;here&lt;/a&gt;. The downloaded zip file contains, among other things, two folders: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/css&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/js&lt;/code&gt;. I copied the contents of these two folders into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/web-app/css&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/web-app/js/jcrop&lt;/code&gt; directories (respectively) of my grails application.&lt;/p&gt;

&lt;p&gt;Now I have the required tools for cropping. I had previously saved the image uploaded by a user (see here to read about file uploads in grails). In my gsp (view), I first render this image and give it an id.&lt;/p&gt;

&lt;div class=&quot;language-jsp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;picture&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;${resource(file: imageSource)}&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I then added the following within a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script&lt;/code&gt; tag in the same gsp to initialize Jcrop:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nf&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#picture&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Jcrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;aspectRatio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;setSelect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;minSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;onSelect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateCoords&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since I use Jcrop (and in turn jQuery), the required javascript and css files should be included. So, I added the following lines within the head section of the gsp:&lt;/p&gt;

&lt;div class=&quot;language-jsp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;${resource(dir:&apos;css&apos;,file:&apos;jquery.Jcrop.css&apos;)}&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;g:javascript &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;plugin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jquery&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;g:javascript &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jcrop/jquery.Jcrop.min.js&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now if you look back at the script to initialize Jcrop, you can see that I have mentioned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updateCoords&lt;/code&gt; as the method to be called on selecting or changing the cropper element. So we should now provide the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updateCoords&lt;/code&gt; method. I added this within a script tag in the head section of my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gsp&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;updateCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#x1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#y1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#x2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#y2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y2&lt;/code&gt; above are ids of hidden fields that will save the co-ordinates of the crop layout. This is how I have included them in my gsp within a form:&lt;/p&gt;

&lt;div class=&quot;language-jsp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;g:form &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;savePicture&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;g:hiddenField &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x1&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt; value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;g:hiddenField &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;y1&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt; value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;g:hiddenField &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x2&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt; value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;100&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;g:hiddenField &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;y2&quot;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt; value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;100&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;g:submitButton &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Crop and Save&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/g:form&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, when the user adjusts the cropper and presses the submit button, the co-ordinates of this cropped layout will be available to the controller method. Using this we can crop the image in our controller (using various ways) and save it. This is one way to do it:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;savePicture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tempPicture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/path/to/original/file&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tempPicture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;croppedImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getSubimage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profilePicture&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/path/to/new/cropped/file&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ImageIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;croppedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;jpg&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;profilePicture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;deleteQuietly&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tempPicture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: The fully qualified names of classes used above are &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/java/io/File.html&quot;&gt;java.io.File&lt;/a&gt;, &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/java/awt/image/BufferedImage.html&quot;&gt;java.awt.image.BufferedImage&lt;/a&gt;, &lt;a href=&quot;http://download.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html&quot;&gt;javax.imageio.ImageIO&lt;/a&gt; and &lt;a href=&quot;http://commons.apache.org/io/apidocs/org/apache/commons/io/FileUtils.html&quot;&gt;org.apache.commons.io.FileUtils&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Custom Password Encoder For Grails Spring-Security Plugin</title>
   <link href="https://www.vithun.com/posts/custom-password-encoder-for-grails-spring-security-plugin/"/>
   <updated>2011-05-31T00:00:00+01:00</updated>
   <id>https://www.vithun.com/posts/custom-password-encoder-for-grails-spring-security-plugin</id>
   <content type="html">&lt;p&gt;The spring-security (core and others) plugin is very handy for incorporating user (and role) based functionalities for a grails application. The plugin comes with a lot of features out-of-the-box. And more often than not, some of the basic features can be used as is. However, there are occasions when a little bit of customization might be required.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;http://philevents.org/&quot;&gt;my current project&lt;/a&gt;, I was required to use a custom password encryption algorithm. The spring-security plugin uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHA-256&lt;/code&gt; algorithm by default. This can be changed to use other standard algorithms (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MD2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MD5&lt;/code&gt; etc.) by adding the following lines (if, for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MD5&lt;/code&gt; encoding is required) in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/grails-app/conf/Config.groovy&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;grails.plugins.springsecurity.password.algorithm = &quot;MD5&quot;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But what I wanted was to use a custom algorithm of our own, not the standard ones. Fortunately, this is again, very easy. Because of Spring’s dependency injection, we can easily create our own password encoder and inject it. I have outlined how I did this below.&lt;/p&gt;

&lt;p&gt;I first created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PasswordEncoder&lt;/code&gt; class which implemented Spring’s &lt;a href=&quot;http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/authentication/encoding/PasswordEncoder.html&quot;&gt;PasswordEncoder&lt;/a&gt; interface. I then overrode the methods of the interface according to our requirements.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PasswordEncoder&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;springframework&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;security&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;authentication&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PasswordEncoder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;encodePassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encodedPassword&lt;/span&gt;
        &lt;span class=&quot;cm&quot;&gt;/* TODO Encode the password using a custom algorithm */&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encodedPassword&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isPasswordValid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encodedPassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rawPassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encodedPassword&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encodePassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rawPassword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once this is done, I just injected the PasswordEncoder as a bean in the application context. In grails, this can be done by declaring the bean in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/grails-app/conf/spring/resources.groovy&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;beans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;passwordEncoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;packagename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;PasswordEncoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And that’s it! The plugin will now use this custom password encoder for encryption.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Eureka Moment in Software Engineering</title>
   <link href="https://www.vithun.com/posts/my-eureka-moment-in-software-engineering/"/>
   <updated>2011-02-14T00:00:00+00:00</updated>
   <id>https://www.vithun.com/posts/my-eureka-moment-in-software-engineering</id>
   <content type="html">&lt;p&gt;Originally posted on the &lt;a href=&quot;https://graduatedevelopercommunity.wordpress.com/2011/02/14/my-eureka-moment-in-software-by-vithun-kumar-gajendra/&quot;&gt;Graduate Developer Community Blog&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;My name is Vithun Kumar Gajendra. I am originally from India, and completed a Master’s course in UK under a student visa. Before coming to UK, I worked as a Software Engineer for about 15 months, and I was very much in the thick of action. This work experience would also go on to help me to understand the stuff I studied in the Master’s course even better. My experience here was like a typical recent graduate who enjoyed doing quick programming tasks at college level. I used to solve problems very quickly (I used to be the quickest in my batch at office!), and would go on accomplishing a lot of things within these 15 months. I worked on problems and mini-projects in fields ranging across Shell scripts, CSS, JSP, Servlets, Oracle PL-SQL, SOAP Web Services, a bit of Spring etc. I had a good time working as part of a team making use of tools like CVS, Bugzilla etc. I also got introduced to how tools like Eclipse, Maven, Ant, Hudson etc. were being used in a development environment (I had no idea about the existence of some of these tools before!). In short, this was a period where I was a really good jack of all trades, but unfortunately the master of none. I now look back at that time, and feel that my speed was actually a curse. I did not have the patience to stop and look in detail at some of the things I had done and understand them in depth. I just thought I could do anything and did not worry about how I did it.&lt;/p&gt;

&lt;p&gt;I then came over to the UK to do my Master’s course. I did an MSc in Advanced Web Engineering in the University of Essex. It was here that I had my first “eureka” moment. I had this module called “Software Design and Architecture”. In this module, I was formally introduced to the concept of “coupling” in software engineering. And I suddenly realised that I had never thought about writing code in a clean way before. All that I focussed on before was to write code that would get the job done. Now I suddenly realised that there was a good (“artistic” if you might) way to write code. I suddenly realised what a fool I had been! And all of a sudden, I began realising the role of concepts like refactoring and design patterns. (I had been part of a “refactoring” team in my previous work experience without having this knowledge). And now, I turned wise. I realised there is always much more to learn (and apply).&lt;/p&gt;

&lt;p&gt;Once I completed my Master’s, I had to wait a few months. I could not find a job as I was still under student visa. And I wouldn’t get my work visa until I got my degree results. So it was in this period that I decided to have a look at Spring. You might ask: Why Spring? I had been introduced to Spring at Mformation. I was required to rewrite existing DAOs using Spring templates and thereby eliminate boilerplate code. I just followed the instructions of my team lead: “Rewrite the code using Spring methods. Declare something in some XMLs and it would work.” It did work, and I did not care at that time how it worked. For some reason, after my Master’s, I thought I’ll have a look at how this worked. And then another eureka moment struck me. Spring was not something that just helped in simplifying DAOs. It was LOTS more than that. I began studying it in detail from the basics(Dependency Injection, Aspect Oriented Programming). The more I read about it, the more I started getting excited.&lt;/p&gt;

&lt;p&gt;By this time, I got an internship offer. They required someone with HTML and MySQL skills, and although I wanted to work with Java, I tried to keep myself occupied until I got my work visa. But my interview here went rather well, which in turn made them think about my position as being somewhat permanent and not just an intern. However I joined on a temporary contract (as I still had just a student visa). I was given an in-house problem (of reasonable complexity) to solve. I came up with a concept, which I thought would work. I wrote a proposal, and my manager suggested me to implement it using PHP. I requested him if I could do it in Java, and after a bit of reluctance (because PHP was used mainly for development within the company) he agreed. I now got the platform to use my Spring knowledge (gained mainly by reading and doing small examples). I developed a proof-of-concept within 7 days. Through this course, I made use of Spring, Hibernate, Maven and Eclipse. I created a well-structured and organized code-base. My manager was impressed with the solution and the speed at which I implemented it. He considered it an “elegant” solution to the problem. And this time I was satisfied that my speed had not come at the cost of learning. I understood more about Spring and my interest in Spring has increased even more. I informed the management that I did not intend to take up a permanent position (because they were looking for someone who would do more with PHP, and I did not want to give up Java and Spring, and I also wanted to relocate to London). So towards the end of my tenure, I had to explain the application I had created to a colleague who had a good understanding of Java, but no knowledge of Spring/Hibernate. Within the next couple of days, I managed to impress her with what all Spring had to offer. She was also able to easily pick up the code I had written (and the best practices I had followed). She also decided to use my proof-of-concept as the base and extend it to completely satisfy the requirements. I left the place with a very good feeling and a sense of accomplishment, and with good relationships forged.&lt;/p&gt;
</content>
 </entry>
 

</feed>

