<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jacek &quot;vircung&quot; Nakonieczny</title>
    <description>Quality content of my own with target audience of myself created by Me, I and Myself.
</description>
    <link>http://www.vircung.com/</link>
    <atom:link href="http://www.vircung.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 17 Oct 2017 10:55:09 +0000</pubDate>
    <lastBuildDate>Tue, 17 Oct 2017 10:55:09 +0000</lastBuildDate>
    <generator>Jekyll v3.5.2</generator>
    
      <item>
        <title>Technical decisions about my blog</title>
        <description>&lt;p&gt;Another thing that I was thinking about while deciding that I will bet back to writing was how this should be hosted. There was few possibilities that I was considering. One of them was self-hosted Wordpress. This would give most possibilities of configuration and integrating already created solutions and plugins if needed. And I know this would eat up a lot of time for me to set up everything before I write some articles.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;bloging-services&quot;&gt;Bloging services&lt;/h2&gt;

&lt;p&gt;Another possibility would be those some services like &lt;a href=&quot;https://medium.com/@vircung&quot;&gt;Medium&lt;/a&gt; that gives hassle-free writing experience together with good looking layout. Flip side of this approach is lack of possibility of configuring it to my needs and taste. And I don’t like it that way. Similar thing is about other ones that are widely used by newcomers like &lt;a href=&quot;https://wordpress.org&quot;&gt;Wordpress.org&lt;/a&gt; or &lt;a href=&quot;https://blogspot.com/&quot;&gt;Blogspot&lt;/a&gt; that I’ve at least tried once. They are good for starters that want to try if writing is for them and that’s good.&lt;/p&gt;

&lt;p&gt;I like to have full control of my creations and ownership of them. Which is not fully possible with any non-self-hosted service. None of them gives that ability because all of them can remove content that I’ve created for any reason and they also want to have ownership of if. I don’t like it so I won’t choose them. Time to move on to more “advanced” solutions.&lt;/p&gt;

&lt;h2 id=&quot;self-hosted-things&quot;&gt;Self-hosted things&lt;/h2&gt;

&lt;p&gt;For self-hosted solutions I was trying to decide between another two, &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; or &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt; hosted on &lt;a href=&quot;https://pages.github.com&quot;&gt;Github Pages&lt;/a&gt;. Ghost is pretty much simply solution, pleasing for an eye to look at and there is possibility for extending it functionalities as needed. On the other had it’s pretty early for it as a project and development of it slowed pretty much which is not conforming me that much.&lt;/p&gt;

&lt;p&gt;Whats more it requires full server running and to be maintained in case of any downtimes or breaking in. Of course possibility of someone trying to hack in on the server is small. Having experience with server running only &lt;a href=&quot;https://github.com/vircung/docker-znc&quot;&gt;IRC bounceer&lt;/a&gt; and being shut down due to suspiciously large traffic is nothing that I want to rely on my blog right now. Probably in future when my needs will become more demanding.&lt;/p&gt;

&lt;h2 id=&quot;chosen-solution&quot;&gt;Chosen solution&lt;/h2&gt;

&lt;p&gt;Given that above I decided to still stay with Jekyll. It’s static web site generator that works with Github. For me currently is good compromise between complexity of full fledged solutions like Wordpress, simplicity of bloging services and having control over content and whole site. As a bonus feature anyone can contribute to those articles and page itself if there are any typos, inconsistencies, improvements to be made, mistakes or I was just wrong.&lt;/p&gt;

&lt;p&gt;Of course hosting it as Github Page reduces possibilities which gives Jekyll but on other hand moving it to other hosting solution like FTP or AWS S3 bucket is pretty much simple. For that reason I generate backup of whole page ready to quickly switch target solution.&lt;/p&gt;
</description>
        <pubDate>Sun, 02 Jul 2017 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/technical-decisions-about-my-blog</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/technical-decisions-about-my-blog</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>What has happened over last year</title>
        <description>&lt;p&gt;Hello again. Long time no see. More like one year, because previous post is about having some break in writing so it doesn’t count for me as a proper one! As you can guess already, I’ve lost some interests in writing technical stuff. There is really no good reason for it but laziness and lack of motivation. I would like to change that.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;hackerspace&quot;&gt;Hackerspace!&lt;/h2&gt;

&lt;p&gt;Over the last year I have participated in local community of makers and hackers in &lt;a href=&quot;http://hackerspace-lbn.pl&quot;&gt;Hackerspace Lublin&lt;/a&gt; foundation. We had some problems with financing ourselves. That’s because we solely depend on donations from our community. That community consists of me, I, myself, Marcin, Łukasz and Kamil. As you can see it’s a lot of folks to manage, push them to make donations and try to push them to progress in their projects.&lt;/p&gt;

&lt;p&gt;Additionally we had to change our space to cheaper one because of obvious reasons, we had no money to pay for it. Currently we live in basement near &lt;a href=&quot;http://www.pollub.pl&quot;&gt;Lublin University of Technology&lt;/a&gt; with costs that are more suitable for our possibilities. Next issues to solve are: lack of spare time to donate to Hackerspace, more projects to start and finish (more probably stall, drop, or forget about), try to lure some college students to us and inspire them to stay longer with us.&lt;/p&gt;

&lt;p&gt;It doesn’t seems much but for sure it will be stretched in time because of getting involved in Hackerspace is our spare time activity. And believe or not we have life to manage :)&lt;/p&gt;

&lt;h2 id=&quot;get-noticed&quot;&gt;Get Noticed!&lt;/h2&gt;
&lt;p&gt;In weekend 2 weeks ago there was end of bloging competition for polish developers called &lt;a href=&quot;http://dajsiepoznac.pl&quot;&gt;Get Noticed&lt;/a&gt; or “Daj się poznać” (or DSP in short) if you know polish language. It’s great opportunity to get some traction in our ongoing pet projects or start a pet project and in addition to start writing blog. This year was 3rd edition of this project and there was around 1000 blogs that were registered for DSP2017. Full list of participants and their blogs and projects is available at &lt;a href=&quot;http://uczestnicy.dajsiepoznac.pl/lista&quot;&gt;http://uczestnicy.dajsiepoznac.pl/lista&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I didn’t took part in this years edition because of reasons that I don’t know about. Just did not. In opposition to that I took part in Final Gala as spectator and I was inspired. Almost of all finalists started their own blogs because of this competition. Selected few of them had an opportunity to give talk about their projects, about their experience of writing blog, or any other topic that was important to them during that time. It was like triple- or event quad-win for them. Start a project, start blog, give talk and get noticed in community! I was amazed of how much success you can achieve in such short period of time. Of course with a little push of &lt;a href=&quot;http://devstyle.pl&quot;&gt;Maciej Aniserowicz&lt;/a&gt;, who’s becoming a celebrity of polish developers.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;pl&quot; dir=&quot;ltr&quot;&gt;Ja tylko lekko nacisnąłem klamkę, a WY wykopaliście drzwi z półobrotu! :) &lt;a href=&quot;https://t.co/CjOrHkjlt6&quot;&gt;https://t.co/CjOrHkjlt6&lt;/a&gt;&lt;/p&gt;&amp;mdash; Maciej Aniserowicz💻 (@maniserowicz) &lt;a href=&quot;https://twitter.com/maniserowicz/status/877446019461644288&quot;&gt;June 21, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;So after that event and talks with participants of DSP I’ve decided to reactivate this place. Start writing some articles regardless if they will be technical or not. Just get them written and published. Just get this post published in consistent manner.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;pl&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/hashtag/blogged?src=hash&quot;&gt;#blogged&lt;/a&gt; A może by tak dać się poznać &lt;a href=&quot;https://twitter.com/hashtag/dajsiepoznac?src=hash&quot;&gt;#dajsiepoznac&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/dsp?src=hash&quot;&gt;#dsp&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/dsp2017?src=hash&quot;&gt;#dsp2017&lt;/a&gt; &lt;a href=&quot;https://twitter.com/MediumPolska&quot;&gt;@MediumPolska&lt;/a&gt; &lt;a href=&quot;https://twitter.com/maniserowicz&quot;&gt;@maniserowicz&lt;/a&gt; &lt;a href=&quot;https://t.co/akaDlgtF7g&quot;&gt;https://t.co/akaDlgtF7g&lt;/a&gt;&lt;/p&gt;&amp;mdash; Mr J. (@vircung) &lt;a href=&quot;https://twitter.com/vircung/status/877191363971952640&quot;&gt;June 20, 2017&lt;/a&gt;&lt;/blockquote&gt;

&lt;h2 id=&quot;whoami&quot;&gt;Whoami&lt;/h2&gt;
&lt;p&gt;If I want to do this properly I need to be consistent. For over a decade I get used to one word which for whatever, unknown for me now, reason has stuck with me. This nickname is companion of my from mid-school and I use it wherever and whenever I want to mark my ground. I use it as my handle almost everywhere, IRC, Twitter, Instagram, forums, etc. Event if I’m not currently active at some place in the internet.&lt;/p&gt;

&lt;p&gt;Why not use it as my domain. (Right now I’m a little bit struggling with domain and Github to behave nicely but it’ll be solved!) As my place in vast internet. Why not. Let’s do this.&lt;/p&gt;

&lt;p&gt;I’ll try to reserve this word as login, username or nickname for reasons. Mostly because it’s mine and only mine :) My little precious :) Wherever you see someone who call himself “vircung” you have almost 100% guarantee that’s me!&lt;/p&gt;
</description>
        <pubDate>Mon, 26 Jun 2017 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/what-has-happened-over-last-year</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/what-has-happened-over-last-year</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Places i write to</title>
        <description>&lt;p&gt;Once in a while there is a break down. At least i have it from time to time. I had few more or less successful attempts to write a blog. By looking at the dates you can see that there’s another gap in posts. To break the charm i’ll tell you about places that my articles.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;beginners-dump&quot;&gt;Beginner’s “Dump”&lt;/h2&gt;

&lt;p&gt;It was quite a while ago, 7th May 2012 to be exact. I was in the middle of Bachelor’s degree and obviously i had too much time and almost nothing to do. This place was mostly brain dump storage. I placed there some informations about my &lt;a href=&quot;https://nawypasie.wordpress.com/tag/opengl/&quot;&gt;Bachelors thesis&lt;/a&gt;, some &lt;a href=&quot;https://nawypasie.wordpress.com/tag/wino/&quot;&gt;side projects&lt;/a&gt; and some random &lt;a href=&quot;https://nawypasie.wordpress.com/tag/gamedev/&quot;&gt;bits&lt;/a&gt; and &lt;a href=&quot;https://nawypasie.wordpress.com/category/random/&quot;&gt;pieces&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This place is mostly abandoned. Courtesy of Wordpress platform is still hosted and served to the world. And surprisingly it’s visited on average once a day. Perhaps it’s because it’s in polish? Regardless yay for me :D&lt;/p&gt;

&lt;h2 id=&quot;current-dump&quot;&gt;Current “Dump”&lt;/h2&gt;

&lt;p&gt;As time goes by after leaving previous blog in the void of internet i thought that i can write again. And this place happened. And as i wrote in first post i’ll try to challenge myself and write in english. As you can see it has more tech and IT related articles as previous one.&lt;/p&gt;

&lt;p&gt;In here you can find things related to IT projects that are planned, work in progress or voided (stored in &lt;code class=&quot;highlighter-rouge&quot;&gt;/dev/null&lt;/code&gt; if you’re more tech savvy). In my plans this blog will be updated from time to time. Original assumption that i’ll write here once a month isn’t fulfilled that i would like to. But hey, nothing is lost in this regard.&lt;/p&gt;

&lt;h2 id=&quot;business-dump&quot;&gt;Business “Dump”&lt;/h2&gt;

&lt;p&gt;Few months ago company that i’m currently working for decided to start &lt;a href=&quot;http://blogersii.pl/&quot;&gt;own blog&lt;/a&gt;. And i decided that i can have some win-win situation. I thought that i’ll be motivated to &lt;a href=&quot;http://blogersii.pl/author/jacek-nakonieczny/&quot;&gt;write for them&lt;/a&gt; and i’ll reuse those writings and place them here. As you can imagine posts are published only on company
s blog because of my laziness.&lt;/p&gt;

&lt;p&gt;Out there i write for business analysis section. Can you imagine that mostly back-end developer is writing for BA? Ok let’s agree on something. It’s more  It came to me out of the blue and i managed to write a few times. Hopefully i’ll find more topic and continue to write there.&lt;/p&gt;

&lt;h2 id=&quot;whats-more&quot;&gt;What’s more?&lt;/h2&gt;

&lt;p&gt;Knowing that my first blog still has some views it’s tempting for me to try to revive it. Or take it’s idea and have a place to keep all non-IT articles in there. Or i’ll utilize this lovely platform and become &lt;a href=&quot;https://medium.com/@vircung&quot;&gt;medium&lt;/a&gt; :) Who knows?&lt;/p&gt;

</description>
        <pubDate>Mon, 18 Apr 2016 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/places-i-write-to</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/places-i-write-to</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Offline DIY fun</title>
        <description>&lt;p&gt;How much fun is buying new gadget? Just go to shop, pick something that you definitely don’t need but want and buy it. But did you ever wonder how much fun do you get from making such thing? Like RC model? Like flying multirotor (common name is drone)? No? So “Stay Awhile and Listen”.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;this-started-at-youtube&quot;&gt;This started at Youtube&lt;/h2&gt;

&lt;p&gt;This think is like Wikipedia, you start at some randomly suggested video, start clicking and then you watch some crazy videos about things that you’d never search for. And that’s how i found about drones and stuff. I watched some videos taken by drones, about building drones, from drones racing and from drones crashing. The last ones is fun for obvious reasons :) And that was pretty much it. O’ve got fascinated and few days later forgot about the topic for some time.&lt;/p&gt;

&lt;h2 id=&quot;theres-alywas-someone-who-&quot;&gt;There’s alywas someone who …&lt;/h2&gt;

&lt;p&gt;Few months ago on business meetings with client after new product release this topic came out. While one of “bio breaks” testers and BO Reporting guy (Kuba) ended up watching some videos about drones on Youtube. And then i found out that Kuba flies RC models (quadcopters and helicopters).&lt;/p&gt;

&lt;p&gt;After few talks with hin on other “bio breaks” about how he started, kinds of models, parts, competitions, model assembling and stuff i thought “hey, this sounds like fun, let’s give a shot”. After few days i ended up spending money on things that i don’t need but want to have. I bought drone parts that requires soldering, assembling and configuring.&lt;/p&gt;

&lt;h2 id=&quot;assembling&quot;&gt;Assembling&lt;/h2&gt;

&lt;p&gt;After couple of days waiting for parts to arrive mostly from china i went to Kuba’s to assemble them. And it wasn’t that complicated. He pre-soldered most of things and after few hours quadcopter was ready to flight. We tuned flight controller and did test flights and that’s it. I had my first mini quadcopter (250mm)&lt;/p&gt;

&lt;p&gt;I can tell that flying this thing is a lot of fun. Even for some inexperienced pilot like me to learn and feel the machine. After some time and few dozens of broken propellers i wanted more. I wanted to get better perspective, first person view (FPV).&lt;/p&gt;

&lt;h2 id=&quot;real-fun-just-started&quot;&gt;Real fun just started&lt;/h2&gt;

&lt;p&gt;So i bought FPV camera, transmitter, receiver and goggles! And guess what. I had to disassemble quadcopter, fix wiring, resolder almost everything and assemble it again. It took me over 2 days and it works! I got place at local &lt;a href=&quot;http://makerspace-lbn.pl/&quot;&gt;Makerspace&lt;/a&gt; where i could borrow tools. All i can say is that everything works as expected. It was damn rewarding to upgrade drone all by myself. What’s most important FPV is amazing even when you “fly” holding camera in one hand.&lt;/p&gt;

&lt;p&gt;But it’s not finished. Few things is duct taped and needs proper fixing. So my next plan is to 3D print few (of course in Makerspace, because there i can “borrow” printers) parts like camera mount because i couldn’t &lt;a href=&quot;http://www.thingiverse.com/search?q=FPV+camera&quot;&gt;found&lt;/a&gt; good one.&lt;/p&gt;

&lt;p&gt;And there is this idea to print whole quadcopter. Not racing one (250mm) but bigger 450mm or some for other things than proximity flying.&lt;/p&gt;

</description>
        <pubDate>Mon, 24 Aug 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/offline-diy-fun</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/offline-diy-fun</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Rails Sandbox Take 2: The Docker</title>
        <description>&lt;p&gt;Few posts ago i wrote about &lt;a href=&quot;/posts/rails-sandbox&quot;&gt;rails sandbox&lt;/a&gt; and isolated &lt;a href=&quot;/posts/your-development-environment&quot;&gt;development environment&lt;/a&gt; using Vagrant and Chef Solo. But there’s more options available. One of them is gets more and more traction and gains popularity. It’s the Docker.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;the-docker&quot;&gt;The Docker&lt;/h2&gt;

&lt;p&gt;Docker in it’s concept is similar to Vagrant but yet different. It also wrap your software in separated environment called container as Vagrant does with Virtual Machine. But the difference is that containers doesn’t posses it’s own OS but it’s share kernel with other containers. They run in isolated userspace on the host operating system.&lt;/p&gt;

&lt;h2 id=&quot;the-tutorial&quot;&gt;The Tutorial&lt;/h2&gt;

&lt;p&gt;If you haven’t worked with Docker before you should go through &lt;a href=&quot;http://docs.docker.com/mac/started/&quot;&gt;Docker tutorial&lt;/a&gt;. It explains all basic concepts of working with Docker.&lt;/p&gt;

&lt;h2 id=&quot;the-configuration&quot;&gt;The Configuration&lt;/h2&gt;

&lt;p&gt;Container configuration in concept is similar to Vagrant it sits in single file &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;. So let’s say we want to prepare container to work with Ruby on Rails.&lt;/p&gt;

&lt;p&gt;Not digging into further details let’s describe what we’ll need to run rails application on Ubuntu machine&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;basic development tools (build-essential package)&lt;/li&gt;
  &lt;li&gt;javascript runtime (nodejs package)&lt;/li&gt;
  &lt;li&gt;nokogiri dependencies (libxml2-dev libxslt1-dev)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The we need add our application to container, install all necessary gems and we’re ready to go.&lt;/p&gt;

&lt;p&gt;Let’s roll up sleeves define the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;FROM ruby:2.2.2

RUN apt-get update -qq &amp;amp;&amp;amp; apt-get install -y build-essential

# for js
RUN apt-get install -y nodejs

# for nokogiri
RUN apt-get install -y libxml2-dev libxslt1-dev

# create folder for application
ENV APP_HOME /app/rails_application
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# add Gemfile and Gemfile.lock
ADD Gemfile* $APP_HOME/
RUN bundle install

# copy over application
ADD . $APP_HOME&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we need to build this image and it’ll be ready to use. &lt;code class=&quot;highlighter-rouge&quot;&gt;docker build -t image_name .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To run rails application we need to issue command &lt;code class=&quot;highlighter-rouge&quot;&gt;docker run image_name rails server&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-but&quot;&gt;The But&lt;/h2&gt;

&lt;p&gt;But there are some problems. Code is embedded into image, we don’t know what ip has container and we cannot go through firewall at standard rails port 3000.&lt;/p&gt;

&lt;h2 id=&quot;the-work&quot;&gt;The Work&lt;/h2&gt;

&lt;p&gt;Docker client takes numerous of parameters but right now only few of them are needed.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-v /host/path:/container/path&lt;/code&gt; will mount path from host system into container&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-p host_port:container_port&lt;/code&gt; will expose ports to host&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we need to run &lt;code class=&quot;highlighter-rouge&quot;&gt;docker run -p 3000:3000 -v ~/code/docker/rails-app:/app/rails_application image_name rails s -b 0.0.0.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will start rails application as you usually do but in docker container.&lt;/p&gt;

&lt;p&gt;YAY! We could quote “That’s all folks!” but what if …&lt;/p&gt;

&lt;h2 id=&quot;the-orchestration&quot;&gt;The Orchestration&lt;/h2&gt;

&lt;p&gt;… what if we want to be more complex, have separate container for different parts of application. Let’s say we need separate containers for PostgreSQL and Redis. How to handle this?&lt;/p&gt;

&lt;p&gt;I say we could use &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose&lt;/code&gt; tool. All what it needs is another file that will hold whole configuration, &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt;. But we need adjust out &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; first and install packages for postgres client.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;FROM ruby:2.2.2

RUN apt-get update -qq &amp;amp;&amp;amp; apt-get install -y build-essential

# for js
RUN apt-get install -y nodejs

# for nokogiri
RUN apt-get install -y libxml2-dev libxslt1-dev

# for postgres
RUN apt-get install -y libpq-dev postgresql-client

# create folder for application
ENV APP_HOME /app/rails_application
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# add Gemfile and Gemfile.lock
ADD Gemfile* $APP_HOME/
RUN bundle install

# nifty trick to clean pid leftovers
RUN test -f $APP_HOME/tmp/pids/server.pid &amp;amp;&amp;amp; rf $APP_HOME/tmp/pids/server.pid; true

# copy over application
ADD . $APP_HOME&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Having that we can take care of &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;s&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;postgres:9.4.4&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis:3.0.2&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rails s -b 0.0.0.0 -p 3000&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.:/app/rails_application&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;localhost:3000:3000'&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Each top level section defines separate container. 2nd level are docker parameters so for &lt;code class=&quot;highlighter-rouge&quot;&gt;web&lt;/code&gt; container we specify command to issue, mount volume, expose port (bonus points for being able to specify hostname/ip) and link with other containers.&lt;/p&gt;

&lt;p&gt;As you can see if we remove new parts (linking and other containers) we are pretty much doing same things like command from previous section.&lt;/p&gt;

&lt;p&gt;To spin up this configuration all we need is to execute &lt;code class=&quot;highlighter-rouge&quot;&gt;docker-compose up&lt;/code&gt; and off we go because&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;if there is no image present locally composer will download it&lt;/li&gt;
  &lt;li&gt;if there was changes in images composer will update them&lt;/li&gt;
  &lt;li&gt;it there was changes in &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; composer will rebuild it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/docker-compose-in-action.png&quot; alt=&quot;Docker compose in action&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;the-another-but&quot;&gt;The Another But&lt;/h1&gt;

&lt;p&gt;Of course there will be some issues. There is always something. So things worth considering:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;is data persistent&lt;/li&gt;
  &lt;li&gt;how to scale this solution&lt;/li&gt;
  &lt;li&gt;deployment process&lt;/li&gt;
  &lt;li&gt;what will happen when images will be updated&lt;/li&gt;
  &lt;li&gt;configuration for multiple host OS (is this needed?)&lt;/li&gt;
  &lt;li&gt;duplication of environment variables and how to reuse them&lt;/li&gt;
  &lt;li&gt;gems caching (rails specific)&lt;/li&gt;
  &lt;li&gt;testing and automation (rails specific, guard)&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 02 Jul 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/rails-sandbox-take-2-the-docker</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/rails-sandbox-take-2-the-docker</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Lets talk about Salesforce</title>
        <description>&lt;p&gt;As we know all languages has thier quirks and odd/unexpected/undefined behaviours. &lt;a href=&quot;https://twitter.com/GaryBernhardt&quot;&gt;Gary Bernhardt&lt;/a&gt; pointed out some of those in his &lt;a href=&quot;https://www.destroyallsoftware.com/talks/wat&quot;&gt;lighting talk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As i’m currently tided up to &lt;s&gt;Slaveforce&lt;/s&gt; &lt;a href=&quot;http://www.salesforce.com/&quot;&gt;Salesforce&lt;/a&gt; and in my opinion there is lots things to fix and improve. I’ll put here some of inconsistances in code and it’s behaviour. If you know more of them, give me a shout.&lt;/p&gt;

&lt;p&gt;“Lest talk about salesforce” :)&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;img src=&quot;/assets/wat.png&quot; alt=&quot;WAT&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;pagereference-comparision&quot;&gt;PageReference comparision&lt;/h2&gt;

&lt;p&gt;While wrtiting tests for software we assume a lot of things. Most basic assumption is that objects are properly compared. In test i belive object should be compared by it’s content and it works most of the time. But when you want to assert equality of PageReference the magic happens :)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;PageReference&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference1&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;PageReference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_page&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PageReference&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference2&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;PageReference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_page&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reference1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In my opinion this should execute nicely and let the test pass but hey, it’s Salesforce :)&lt;/p&gt;

&lt;pre&gt;
32.0 APEX_CODE,DEBUG
Execute Anonymous: PageReference reference1 = new PageReference('/apex/some_page');
Execute Anonymous: PageReference reference2 = new PageReference('/apex/some_page');
Execute Anonymous:
Execute Anonymous: System.assertEquals(reference1, reference2);
14:40:42.037 (37207059)|EXECUTION_STARTED
14:40:42.037 (37218368)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
14:40:42.038 (38306527)|EXCEPTION_THROWN|[4]|System.AssertException: Assertion Failed: Expected: System.PageReference[/apex/some_page], Actual: System.PageReference[/apex/some_page]
14:40:42.038 (38457751)|FATAL_ERROR|System.AssertException: Assertion Failed: Expected: System.PageReference[/apex/some_page], Actual: System.PageReference[/apex/some_page]

AnonymousBlock: line 4, column 1
14:40:42.038 (38502059)|CODE_UNIT_FINISHED|execute_anonymous_apex
14:40:42.039 (39853255)|EXECUTION_FINISHED
&lt;/pre&gt;

&lt;p&gt;Of course there is workaround. But it should work out of the box.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;PageReference&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference1&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;PageReference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_page&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PageReference&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference2&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;PageReference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some_page&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reference1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;standardsetcontroller-pagination&quot;&gt;StandardSetController pagination&lt;/h2&gt;

&lt;p&gt;Let’s say we have component for StandardSetController pagination. Component’s page is simple and it’s similar to standard pagination used by Salesforce. Controller for this component contains few methods to traverse it’s records collection. Also it has additional feature to handle collection with edited objects.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sharing&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StandardSetPaginationController&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;n&quot;&gt;ApexPages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;StandardSetController&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&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;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&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;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;first&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;last&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;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;last&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;next&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;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;next&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;previous&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;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;previous&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Looks legit, right? And it works flawlessly except one case. When you save controller traversal methods doesn’t works as excepted. What i noticed and as i understand is that after save methos is executed set controller reset it’s current page number to 1 and you can view only 1 and 2 pages.&lt;/p&gt;

&lt;p&gt;Why? I do not know.&lt;/p&gt;

&lt;p&gt;How to deal with this? I’ve got workaround solution. I had to get one. You have to switch page manually. And this woks like a charm.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sharing&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StandardSetPaginationController&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;n&quot;&gt;ApexPages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;StandardSetController&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&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;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&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;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentPageStart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&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;currentPage&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;n&quot;&gt;pageSize&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentPageEnd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&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;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getResultSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentPage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pageSize&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentPage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&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;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getPageNumber&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;totalPages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&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;Integer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Decimal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getResultSize&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;n&quot;&gt;Decimal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pageSize&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pageSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;get&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;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getPageSize&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasPreviousPage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&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;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHasPrevious&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasNextPage&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&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;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHasNext&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first&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;goToPage&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;last&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;goToPage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;totalPages&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;next&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;goToPage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentPage&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;previous&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;goToPage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currentPage&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;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;goToPage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pageNumer&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;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;needUpdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;setController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setPageNumber&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pageNumer&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And here it is component itself. Neat, right? :)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;apex:component&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;controller=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;StandardSetPaginationController&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;allowDML=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&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;apex:attribute&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;standardSetController&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ApexPages.StandardSetController&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;description=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Paginated controller&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;assignTo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!setController}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;required=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&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;apex:attribute&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rerenderComponents&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;String&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;description=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Id of components to be rerendered on parent's page&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;required=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&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;apex:attribute&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;updateBeforePageChange&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Boolean&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;description=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;If controller needs to save records before page change&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;assignTo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!needUpdate}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;required=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;default=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&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;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bottomNav&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;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;paginator&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;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;left&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;apex:outputlabel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!currentPageStart} - {!currentPageEnd} of {!setController.resultsize}&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;/span&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prevNextLinks&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;apex:outputPanel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rendered=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!hasPreviousPage}&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;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prevNext&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;apex:commandlink&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!first}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rerender=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!rerenderComponents}&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;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/s.gif&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;first&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;/apex:commandlink&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prevNext&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;apex:commandlink&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!previous}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rerender=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!rerenderComponents}&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;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/s.gif&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prev&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
                            Previous
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/apex:commandlink&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/apex:outputPanel&amp;gt;&lt;/span&gt;

                &lt;span class=&quot;nt&quot;&gt;&amp;lt;apex:outputPanel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rendered=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!hasNextPage}&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;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prevNext&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;apex:commandlink&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!next}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rerender=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!rerenderComponents}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                            Next
                            &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/s.gif&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;next&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;/apex:commandlink&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prevNext&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;apex:commandlink&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!last}&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rerender=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{!rerenderComponents}&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;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/s.gif&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;last&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;/apex:commandlink&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/apex:outputPanel&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;right&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;apex:outputlabel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Page {!currentPage} of {!totalPages}&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;/span&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/apex:component&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;input-field-focus&quot;&gt;Input field focus&lt;/h2&gt;

&lt;p&gt;Have you ever wondered how Salesforce is focusing input fields? Or with displayed popup page jumped to first input field out of the sudden? Yeah, that was VisualForce page focusing on input field. Of course you can disable this behaviour with little trick. Actually it’s a onelined JavaScript.&lt;/p&gt;

&lt;p&gt;Yes. JavaScript. Why? I don’t know.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setFocusOnLoad&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;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And you’re done. No more autofocus on this VF page.&lt;/p&gt;

&lt;h2 id=&quot;this-is-not-the-end&quot;&gt;This is not the end&lt;/h2&gt;

&lt;p&gt;This post is going to be published ‘rolling release’ manner. So there will be updates for sure. Keep in touch :)&lt;/p&gt;

</description>
        <pubDate>Fri, 15 May 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/lets-talk-about-salesforce</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/lets-talk-about-salesforce</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Rails support for UUID</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://github.com/search?l=ruby&amp;amp;q=gem+pg&amp;amp;ref=searchresults&amp;amp;type=Code&amp;amp;utf8=%E2%9C%93&quot;&gt;PostgreSQL&lt;/a&gt; is almost popular as &lt;a href=&quot;https://github.com/search?l=ruby&amp;amp;q=gem+sqlite3&amp;amp;ref=searchresults&amp;amp;type=Code&amp;amp;utf8=%E2%9C%93&quot;&gt;SQLite&lt;/a&gt; as a database backend for Rails applications. Some of them uses &lt;a href=&quot;https://github.com/search?utf8=%E2%9C%93&amp;amp;q=enable_extension+uuid-ossp&amp;amp;type=Code&quot;&gt;uuid-ossp&lt;/a&gt; extension to change type of column &lt;code class=&quot;highlighter-rouge&quot;&gt;id&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;uuid&lt;/code&gt;. It’s common knowledge that &lt;code class=&quot;highlighter-rouge&quot;&gt;uuid&lt;/code&gt; breaks &lt;code class=&quot;highlighter-rouge&quot;&gt;references&lt;/code&gt; column type when you want to reflect table relations in migration files. Actually it’s not.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;missing-knowledge&quot;&gt;Missing knowledge&lt;/h2&gt;

&lt;p&gt;When you &lt;a href=&quot;https://www.google.pl/search?q=rails+uuid+primary+key&quot;&gt;search&lt;/a&gt; for articles that are about integrating &lt;code class=&quot;highlighter-rouge&quot;&gt;uuid&lt;/code&gt; type into &lt;code class=&quot;highlighter-rouge&quot;&gt;id&lt;/code&gt; column. &lt;a href=&quot;http://blog.arkency.com/2014/10/how-to-start-using-uuid-in-activerecord-with-postgresql/&quot;&gt;Almost&lt;/a&gt; every &lt;a href=&quot;http://labria.github.io/2013/04/28/rails-4-postgres-uuid-pk-guide/&quot;&gt;one&lt;/a&gt; of &lt;a href=&quot;http://rny.io/rails/postgresql/2013/07/27/use-uuids-in-rails-4-with-postgresql.html&quot;&gt;them&lt;/a&gt; either say that this will break &lt;code class=&quot;highlighter-rouge&quot;&gt;references&lt;/code&gt; column type in migrations or says nothing about it.&lt;/p&gt;

&lt;p&gt;There’s workaround to use &lt;code class=&quot;highlighter-rouge&quot;&gt;t.uuid :something_else_id&lt;/code&gt; thing. And it’s working great. I don’t mind. I even used it in my code. But the brilliant idea came to mi that i might fix it in Rails code. And i started digging.&lt;/p&gt;

&lt;h2 id=&quot;actually-it-works&quot;&gt;Actually it works&lt;/h2&gt;

&lt;p&gt;I started to go through Rails code to search The Place. It’s hard to navigate though it. Especially when you go into large codebase for first time. So i stumbled upon migration tests and found this &lt;a href=&quot;https://github.com/rails/rails/blob/master/activerecord/test/cases/adapters/postgresql/uuid_test.rb#L268&quot;&gt;little gem&lt;/a&gt;. It works! But even Rails documentation says nothing about this. But hopefully it’s going to be &lt;a href=&quot;https://github.com/rails/rails/pull/19806&quot;&gt;fixed&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;Therefore you can fix &lt;code class=&quot;highlighter-rouge&quot;&gt;t.references :something&lt;/code&gt; to work with &lt;code class=&quot;highlighter-rouge&quot;&gt;uuid&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# db/migrate/20150418012400_create_blog.rb&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;change&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;create_table&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id: :uuid&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;create_table&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;id: :uuid&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# t.belongs_to :post, type: :uuid&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;references&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;type: :uuid&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# app/models/post.rb&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:comments&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# app/models/comment.rb&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Comment&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It would be lovely that migration mechanism would detect referenced column type automatically. I think i can be done. Just need to find proper place to start hacking things.&lt;/p&gt;

</description>
        <pubDate>Sat, 18 Apr 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/rails-support-for-uuid</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/rails-support-for-uuid</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Slightly advanced deployment workflow</title>
        <description>&lt;p&gt;Over 5 years ago &lt;a href=&quot;https://twitter.com/nvie&quot;&gt;Vincent Driessen&lt;/a&gt; shared with us his well established &lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;git workflow&lt;/a&gt;. It’s very robust and simple (when you wrap your head around it). It almost perfectly fits into agile methodologies. In one of my past projects it was easy to drop in along with migrating from svn to git, and include it to existing &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;Continuous Integration&lt;/a&gt; system. And everyone was happy. How about more recent one? Happily not so easy. That’s good i like challenges.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;whats-wrong&quot;&gt;What’s wrong?&lt;/h3&gt;

&lt;p&gt;Over last 6 months i wanted to adopt it to one of projects in my job (and migrate from filthy svn to git). Of course it’s not so easy because of internal political reasons, policies, produces and tons of documents that has to be signed by millions of people. Hopefully i received information that this can be possible in Q3 or Q4 of 2015’s. So let’s roll up sleeves and prepare some flow charts and graphs.&lt;/p&gt;

&lt;h2 id=&quot;current-repository-situation&quot;&gt;Current repository situation&lt;/h2&gt;

&lt;p&gt;If repository has not received any thought beforehand and was managed in free-style way there is no other possibility that it is/was mess. When i heard the story i was amazed. Long story short. At the beginning everything was kept in &lt;code class=&quot;highlighter-rouge&quot;&gt;root&lt;/code&gt; folder. Then &lt;code class=&quot;highlighter-rouge&quot;&gt;src&lt;/code&gt; folder appeared. After some time some real structure came into being with folders like &lt;code class=&quot;highlighter-rouge&quot;&gt;trunk&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;branches&lt;/code&gt; and other. Each release is a new branch which is left alone even if new release is published. Each production bugfix is implemented in &lt;code class=&quot;highlighter-rouge&quot;&gt;trunk&lt;/code&gt; and current release &lt;code class=&quot;highlighter-rouge&quot;&gt;branch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/im-not-even-mad.jpg&quot; alt=&quot;I was amazed&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;deployment-flow&quot;&gt;Deployment flow&lt;/h2&gt;

&lt;p&gt;At the end of the day internal policies (which i always rant about) became an ally. Hopefully deployment process is well managed and streamlined. I like that there are separate stages for both &lt;a href=&quot;http://en.wikipedia.org/wiki/System_testing&quot;&gt;SAT&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Acceptance_testing#User_acceptance_testing&quot;&gt;UAT&lt;/a&gt;. That gives us, developers, after completing scheduled User Stories time to go through Technical Chances. Sadly the client is more interested in new features that technical and internal improvements but who can blame hit for this? So here is release stages breakdown and deployment flow. As you can see each stage has own isolated environment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/current-deployment.svg&quot; alt=&quot;Deployemnt workflow&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;adopting-git-flow&quot;&gt;Adopting git-flow&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/release-workflow.svg&quot; alt=&quot;Release flow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Adjusting standard release workflow was not that big issue. As meeting went along i had to be agile and make some slight changes to well known nvie’s workflow. As you can see on current workflow i had to split &lt;code class=&quot;highlighter-rouge&quot;&gt;release-*&lt;/code&gt; branch in two.&lt;/p&gt;

&lt;p&gt;When new release cycle is started development code is freezed and no new features are added and SAT cycle begins. New branch &lt;code class=&quot;highlighter-rouge&quot;&gt;sat-*&lt;/code&gt; is created with &lt;code class=&quot;highlighter-rouge&quot;&gt;develop&lt;/code&gt; as a base and deployed to it’s own env. When all found bugs are fixed and verified on &lt;code class=&quot;highlighter-rouge&quot;&gt;development&lt;/code&gt; env new SAT iteration begins along with deployment and retesting on SAT env.&lt;/p&gt;

&lt;p&gt;When no new bugs were found UAT cycle begins. Old &lt;code class=&quot;highlighter-rouge&quot;&gt;sat-*&lt;/code&gt; branch is changed to &lt;code class=&quot;highlighter-rouge&quot;&gt;uat-*&lt;/code&gt; and deployed on it’s own env. If any bug is found it have to be fixed and deployed as soon as possible. If all bugs are fixed and all fine and dandy &lt;code class=&quot;highlighter-rouge&quot;&gt;sat-*&lt;/code&gt; branch is merged to &lt;code class=&quot;highlighter-rouge&quot;&gt;develop&lt;/code&gt; to include all bugfixes and also it’s merged &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; and deployed to production.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/hotfix-workflow.svg&quot; alt=&quot;Hotfix flow&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If critical bug is found on production new branch &lt;code class=&quot;highlighter-rouge&quot;&gt;hotfix-*&lt;/code&gt; is created with &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; as a base and deployed on it’s own env. If it’s fixed and &lt;code class=&quot;highlighter-rouge&quot;&gt;hotix-*&lt;/code&gt; is changed to &lt;code class=&quot;highlighter-rouge&quot;&gt;uat-*&lt;/code&gt; and UAT cycle begins. If it’s all ok &lt;code class=&quot;highlighter-rouge&quot;&gt;hotfix-*&lt;/code&gt; is merged back to &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; and deployed to production. It’s also merged to &lt;code class=&quot;highlighter-rouge&quot;&gt;develop&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Changes made are minor and right now obvious. But back then i gave it fair amount of thought to do it in cleaver way. Benefits from migration to this approach and git are significant to me. For example better changes isolation, repository performance boost, ability to manipulate commit history before push them to server, less hassle for CI configuration for each release.&lt;/p&gt;

&lt;p&gt;I hope this approach will be accepted and possibly spread among other projects. Also i found that solving this problem and preparing myself to explain changes proposed by me gave me much satisfaction. Maybe this is the point to think again about my career path as a software developer :)&lt;/p&gt;

&lt;h2 id=&quot;fun-facts&quot;&gt;Fun facts&lt;/h2&gt;

&lt;p&gt;I did &lt;a href=&quot;http://en.wikipedia.org/wiki/Proof_of_concept&quot;&gt;PoC&lt;/a&gt; for myself that repository can be migrated. The answer is &lt;strong&gt;yes&lt;/strong&gt;. But.&lt;/p&gt;

&lt;p&gt;It took about &lt;strong&gt;4 hours&lt;/strong&gt; to convert svn into git repository. I did wrong the configuration because folder with branches is named &lt;code class=&quot;highlighter-rouge&quot;&gt;branches&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;branch&lt;/code&gt; so i migrated only half of repo.&lt;/p&gt;

&lt;p&gt;When i fixed it (i don’t know exactly how much time it took to fix it along with test fetches) i managed to migrate whole repo in about &lt;strong&gt;9 hours&lt;/strong&gt; (over 8k commits). I wonder if it’s a network configuration issue or just it takes so much time for every larger svn repo or this particular svn server.&lt;/p&gt;

&lt;p&gt;Sadly i didn’t stored any statistics about previous migration mentioned at the very beginning. It would be interesting to compare&lt;/p&gt;

</description>
        <pubDate>Mon, 13 Apr 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/slightly-advanced-deployment-workflow</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/slightly-advanced-deployment-workflow</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Title goes here</title>
        <description>&lt;p&gt;Yeah, that’s pretty much it when you try to find topic to speak about. Especially when you try to find it by yourself. But hey, you’re not lonely island. It’s ok to snag an idea or two from someone’s else blog. That’s because you’ll use different point of view on the topic. It’s called inspiration. And that’s how i came up with this subject that i’ll try to push to few places.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;thoughts-of-inexerienced-person-about-experience&quot;&gt;Thoughts of inexerienced person about experience&lt;/h2&gt;

&lt;p&gt;This came to me after reading some blog posts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.maciejaniserowicz.com/2015/03/09/o-pet-projects/&quot;&gt;about pet projects&lt;/a&gt; which gave me direction to think about gaining experience&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.maciejaniserowicz.com/2015/03/23/inspiruj-i-czerp-inspiracje/&quot;&gt;inspire and get inspired&lt;/a&gt; that gave me some courage to search for conferences with CFP&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.mihcall.com/2015/01/18/Why-You-Should-Speak-At-Meetups-And-Conferences/&quot;&gt;why you should speak at meetups andconferences&lt;/a&gt; that actually forced me to send those submissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions that started going back and forth my mind are not so trivial:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;what’s wrong with ‘xyz years of experience in …’ that is seen in job offers&lt;/li&gt;
  &lt;li&gt;why (sometimes) ‘5 years of experience’ is not what it sounds like&lt;/li&gt;
  &lt;li&gt;when do you really get experience&lt;/li&gt;
  &lt;li&gt;can you ‘store’ experience and how to do it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;… and so on and so forth. You can multiple this kind of questions.&lt;/p&gt;

&lt;h2 id=&quot;where-it-comes-from&quot;&gt;Where it comes from&lt;/h2&gt;

&lt;p&gt;In my opinion definitely not from your day job. Dayjob is outcome of your experience, i’ll talk about it later. The real source is passion and fun. If you’re passionate about something you’re eager to learn about it, play with it and gather information. I can bet on that there were numerous situations that you would rather search for information about new library that you found than spend time on tasks that are boring to you.&lt;/p&gt;

&lt;p&gt;There is (at least in my opinion) big difference between ‘i need to know’ and ‘i want to know’. Let’s give an simple example: kids. They way more prefer to play their favourite game (digital or manual) or even watch that someone’s plays it over doing boring homework. Of course there are exceptions that just enjoy school activities. Same is with you and me and everyone else. We are like kids. And this won’t change.&lt;/p&gt;

&lt;p&gt;What about dayjob? It’s not so much source of experience. It’s about that difference  between ‘you need to’ and ‘you want to’. It’s different kind of traction that pushes you forward. Sometimes direction that you’re going is not what you want. Fun goes away and more and more distractions shows up. But still everything that you learn in this way is not useless.  It’s like this thing with a car. You can choose car that gives you most fun but beside it looks cool it’s unpractical. On the other hand You can choose a car that handles your family the best.&lt;/p&gt;

&lt;p&gt;If we’re in topic of dayjob what’s about that ‘years experience is not what it looks like’? Let’s say there is this project which is finished. Money goes from hand to hand. Everybody is happy and project goes to maintenance mode. For sake of argument you’re going to maintain it and it goes for like 3 years. There are some minor issues and bugs and you fix them. New releases with bugfixes are published around each quarter of year. So do you have 3 years of experience from this project? In my opinion nope. There is no new things that you could learn in there. Everything is already set up in ‘do not even dare touch anything’ state. Probably in first year of maintenance you problably automated most of tasks to state of ‘fire and forget’. So again, does it brings any major knowledge?&lt;/p&gt;

&lt;h2 id=&quot;the-experience-source&quot;&gt;The experience source&lt;/h2&gt;

&lt;p&gt;Now you might wonder ‘ok then, where you learn the most?’. I’ll be clever and answer ‘it depends’ :) It depends what you want to learn. You can ask boss to move you to new project which is more research than development. If the answer to this is no then you can change company because your current one doesn’t give a damn about developers. You can try to pair programing or mentor newcomers in company. After hours you can build wonder-application-that-everyones-needs aka pet project. Or you can contribute to existing libraries and frameworks. Possibilities are limitless.&lt;/p&gt;

&lt;p&gt;Just one note about pet projects. Please do not put them in a drawer. Make them real. Make them public. Let them shine. I (and everyone else who is doung so) can tell that there is going to be something interesting and really nice out of them. Just give them a try. As a example i can give you my person. I started this project called &lt;a href=&quot;https://github.com/vircung/yamem&quot;&gt;YAMEM&lt;/a&gt; and at some strange coincidence i get in touch with &lt;a href=&quot;https://twitter.com/mihcall&quot;&gt;@mihcall&lt;/a&gt;. And now i’ve got enough courage to try to speak at conference about topic that you right now read about. At this point i want to say to both of them &lt;a href=&quot;https://twitter.com/polyconfhq&quot;&gt;@polyconf&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/oredev&quot;&gt;@oredev&lt;/a&gt; and hope they won’t reject my submission :D&lt;/p&gt;

&lt;h2 id=&quot;the-experience-store&quot;&gt;The experience store&lt;/h2&gt;

&lt;p&gt;Is it even possible to store experience somehow? Yes but not in the strict way :) If we agree that giving someones an advice is storing own experience then yes. Just share your knowledge. You can do this in numerous ways. Start a blog. Write an article. Record podcast or videocast. Go to conference, meetup or user group and speak. Actually you can do anything and everything that you will do will benefit in future. And for the most you’ll grow your skills and experience by meeting new people, sharing ideas, starting new projects together. Or even go to conference and speak about what you have done.&lt;/p&gt;

</description>
        <pubDate>Mon, 30 Mar 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/title-goes-here</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/title-goes-here</guid>
        
        <category>en</category>
        
        
      </item>
    
      <item>
        <title>Rails Sandbox</title>
        <description>&lt;p&gt;In previous post i scratched the topic of managing and sharing your development environment. By using Vagrant to manage virtual machines and one of provision tools you can setup configurable environment. Furthermore you can setup your production machine to match this configuration. Lets roll up our sleeves and set it up.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;vagrant-setup&quot;&gt;Vagrant setup&lt;/h2&gt;

&lt;p&gt;You need to install few things: &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt;, VM manager (i’ll choose &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;VirtualBox&lt;/a&gt;) and &lt;a href=&quot;https://www.ruby-lang.org/&quot;&gt;ruby&lt;/a&gt;. Also as a base linux distribution i’ll use Ubuntu.&lt;/p&gt;

&lt;p&gt;First step is to prepare Vagrant configuration so execute &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant init&lt;/code&gt; command. This will generate sample &lt;code class=&quot;highlighter-rouge&quot;&gt;Vagrantfile&lt;/code&gt; with lots of helpfull comments, for now you can delete them to keep configuration clean and tidy. As a box name use &lt;code class=&quot;highlighter-rouge&quot;&gt;ubuntu/trusty64&lt;/code&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/1c11e0671c057716ce150a1b3ad374527b2f8a3e.js?file=Vagrantfile&quot;&gt; &lt;/script&gt;

&lt;p&gt;Now each time when you execute &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; vagrant will search for box with this name. If doesn’t find it in imported boxes will search his &lt;a href=&quot;https://atlas.hashicorp.com/boxes/search&quot;&gt;online catalog&lt;/a&gt; and download it for you. You can also safely &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant destroy&lt;/code&gt; if needed (for sure we will use it later).&lt;/p&gt;

&lt;h2 id=&quot;provisioning&quot;&gt;Provisioning&lt;/h2&gt;

&lt;p&gt;Vagrant has built in functionality to &lt;a href=&quot;https://docs.vagrantup.com/v2/provisioning/index.html&quot;&gt;provision&lt;/a&gt; box while creating it. What it means is that you can execute custom scripts that will install and configure software for you. There are some tools that support this kind of operations which i mentioned in previous post. For now i will use &lt;a href=&quot;https://docs.vagrantup.com/v2/provisioning/chef_solo.html&quot;&gt;chef solo&lt;/a&gt; provisioner.&lt;/p&gt;

&lt;p&gt;In short Chef provisioning uses sets of instructions (called recipes) to setup virtual machine. Recipes can be configured with attributes use templates and be separated in several files. All of those can be combined into Cookbook. There are many configured cookbooks and can be found on &lt;a href=&quot;https://supermarket.chef.io/&quot;&gt;Supermarket&lt;/a&gt;. Some of them are fine tuned and can be found on [GitHub][github-site].&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/1c11e0671c057716ce150a1b3ad374527b2f8a3e.js?file=Cheffile&quot;&gt; &lt;/script&gt;

&lt;p&gt;To easily use and manage existing cookbooks install &lt;a href=&quot;https://rubygems.org/gems/librarian-chef&quot;&gt;librarian-chef&lt;/a&gt; ruby gem &lt;code class=&quot;highlighter-rouge&quot;&gt;gem install librarian-chef&lt;/code&gt; and initialize it &lt;code class=&quot;highlighter-rouge&quot;&gt;librarian-chef init&lt;/code&gt; in folder with &lt;code class=&quot;highlighter-rouge&quot;&gt;Vagrantfile&lt;/code&gt;. Chef configuration file &lt;code class=&quot;highlighter-rouge&quot;&gt;Cheffile&lt;/code&gt; will contain commented out examples delete them to keep it clean and tidy.&lt;/p&gt;

&lt;p&gt;You can group and tune cookbooks into roles. Most often they are grouped into functional groups, for example if your environment is split into 2 VMs (database server and application server) you will end up with 2 roles: database and application. Let’s create one role to keep Chef configuration out of &lt;code class=&quot;highlighter-rouge&quot;&gt;Vagrantfile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create folder &lt;code class=&quot;highlighter-rouge&quot;&gt;roles&lt;/code&gt; and inside of it ruby script &lt;code class=&quot;highlighter-rouge&quot;&gt;base.rb&lt;/code&gt;. Role scripts needs to have name so add &lt;code class=&quot;highlighter-rouge&quot;&gt;name 'base'&lt;/code&gt;. We will add more to it when we add some cookbooks.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/78740962f915f44084a196434bebbea39fbd5310.js?file=base.rb&quot;&gt; &lt;/script&gt;

&lt;p&gt;Now we need to tell Vagrant where is should search for cookbooks and roles. Also add this role to actual vagrant box.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/78740962f915f44084a196434bebbea39fbd5310.js?file=Vagrantfile&quot;&gt; &lt;/script&gt;

&lt;h2 id=&quot;cooking-ruby&quot;&gt;Cooking ruby&lt;/h2&gt;

&lt;p&gt;Now lets add first cookbook to install &lt;a href=&quot;https://rvm.io/&quot;&gt;RVM&lt;/a&gt; and configure it to install newest ruby version (2.2.0). Add &lt;code class=&quot;highlighter-rouge&quot;&gt;cookbook 'rvm', '~&amp;gt; 0.9.2'&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;Cheffile&lt;/code&gt; and execute &lt;code class=&quot;highlighter-rouge&quot;&gt;librarian-chef install&lt;/code&gt;. Cookbook for rvm and all it’s dependencies will be places in &lt;code class=&quot;highlighter-rouge&quot;&gt;cookbooks&lt;/code&gt; folder which will be searched by Vagrant provisioning.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/dff06e9ebb111ab55d5a2fbfffa2b96b85c6d7cb.js?file=Cheffile&quot;&gt; &lt;/script&gt;

&lt;p&gt;Next step is to adjust &lt;code class=&quot;highlighter-rouge&quot;&gt;base&lt;/code&gt; role to install rvm and ruby. To install rvm system-wide accordingly to &lt;a href=&quot;https://supermarket.chef.io/cookbooks/rvm&quot;&gt;README&lt;/a&gt; we need to add &lt;code class=&quot;highlighter-rouge&quot;&gt;recipe[rvm::system]&lt;/code&gt; recipe to run list.&lt;/p&gt;

&lt;p&gt;Now lets adjust attributes to install ruby 2.2.0, use it as a default and  gem &lt;code class=&quot;highlighter-rouge&quot;&gt;bundler&lt;/code&gt;. Also to give user &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant&lt;/code&gt; ability to install gems we need to add it to &lt;code class=&quot;highlighter-rouge&quot;&gt;rvm&lt;/code&gt; group.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/dff06e9ebb111ab55d5a2fbfffa2b96b85c6d7cb.js?file=base.rb&quot;&gt; &lt;/script&gt;

&lt;p&gt;Now lets execute &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant reload&lt;/code&gt; to refresh synchronized folders and &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant provision&lt;/code&gt; to make use of installed cookbooks and set role. It can take a few minutes to complete. When finished you can &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant ssh&lt;/code&gt; into machine and check version &lt;code class=&quot;highlighter-rouge&quot;&gt;ruby -v&lt;/code&gt; and installation folder of ruby &lt;code class=&quot;highlighter-rouge&quot;&gt;which ruby&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every time when you execute &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant destroy&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; you will end up with VM configure exactly same way.&lt;/p&gt;

&lt;h2 id=&quot;cooking-postgresql&quot;&gt;Cooking postgresql&lt;/h2&gt;

&lt;p&gt;As a database backend PostgreSQL is used frequently if application is either self hosted on VPS or on Heroku. In second case PostgreSQL if forced by hosting provider. So having it configured in development enviornment is helpful. Let’s add required cookbook and adjust our role.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/8253a79ca628cabb6f825326d87da4d14a39b220.js?file=Cheffile&quot;&gt; &lt;/script&gt;

&lt;p&gt;Don’t forget to execute &lt;code class=&quot;highlighter-rouge&quot;&gt;librarian-chef install&lt;/code&gt; to actually install new cookbook.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/8253a79ca628cabb6f825326d87da4d14a39b220.js?file=base.rb&quot;&gt; &lt;/script&gt;

&lt;p&gt;If we are using standalone version of chef (other option is that chef recipies are managed by dedicated server) there is a need to setup password for &lt;code class=&quot;highlighter-rouge&quot;&gt;postgres&lt;/code&gt; user. Another catch is that to allow &lt;code class=&quot;highlighter-rouge&quot;&gt;postgres&lt;/code&gt; user to be authenticated by password. That is why we set &lt;code class=&quot;highlighter-rouge&quot;&gt;pg_hba&lt;/code&gt; variables which are reflected in configuration with same name. I took value of this attribute from original recipe and changed authentication method from &lt;code class=&quot;highlighter-rouge&quot;&gt;ident&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;md5&lt;/code&gt; for &lt;code class=&quot;highlighter-rouge&quot;&gt;postgres&lt;/code&gt; user.&lt;/p&gt;

&lt;h2 id=&quot;last-touches&quot;&gt;Last touches&lt;/h2&gt;

&lt;p&gt;Last things to setup in vagrant is to expose port that is used by rails to host machine. Current folder is mounted in &lt;code class=&quot;highlighter-rouge&quot;&gt;/vagrant&lt;/code&gt; path by default. If project is kept in different folder than folder with Vagrantfile you need to explicit setup it to be mounted in VM. Let’s do this and we will be able to create new project!&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/9d535d659d116aec00e6/13572e1ae1d77e66b26842b2a305063260d82f23.js?file=Vagrantfile&quot;&gt; &lt;/script&gt;

&lt;p&gt;All you need now is to &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; then &lt;code class=&quot;highlighter-rouge&quot;&gt;vagrant ssh&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;cd /path/to/project/in/vm&lt;/code&gt; to be in your development sandbox. Your default machine won’t be cluttered with many per project configurations. You can easily experiment with different setups and event split your application into many dedicated servers. Most important it is OS agnostic, easily replicable, configuration consistent and can be shared with everyone.&lt;/p&gt;

&lt;p&gt;Please be warned to keep password for production database safe and secure. This Chef configuration is written for development environment not production.&lt;/p&gt;

</description>
        <pubDate>Sun, 08 Mar 2015 00:00:00 +0000</pubDate>
        <link>http://www.vircung.com/posts/rails-sandbox</link>
        <guid isPermaLink="true">http://www.vircung.com/posts/rails-sandbox</guid>
        
        <category>en</category>
        
        
      </item>
    
  </channel>
</rss>
