<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Ana Balica</title>
  <id>http://ana-balica.github.io</id>
  <link href="http://ana-balica.github.io" />
  <link href="http://ana-balica.github.io/atom.xml" rel="self" />
  <updated>2025-02-21T21:58:20+00:00</updated>
  <rights>Copyright 2014, Ana</rights>
  <author>
    <name>Ana</name>
  </author>
  
    <entry>
      <title>Right time, right place</title>
      <link href="http://ana-balica.github.io/2020/10/15/right-time-right-place/" />
      <summary type="html">&lt;p&gt;I started reading &lt;a href=&quot;https://www.amazon.com/Outliers-Story-Success-Malcolm-Gladwell/dp/0316017930&quot;&gt;Outliers by Malcolm Gladwell&lt;/a&gt;. Believe it or not, this is the first book I picked up by him.&lt;/p&gt;

&lt;p&gt;I’ve been pleasantly surprised how entertaining the book themes are - everybody likes a good story tied in with social science research. For me personally though, the first few chapters clarified why I feel so lucky.&lt;/p&gt;

&lt;p&gt;Even since I saw this &lt;a href=&quot;https://www.youtube.com/watch?v=BUmV6fsZegs&quot;&gt;talk by Saron Yitbarek&lt;/a&gt;, I tried to understand what made me so fortunate. Because, well, I feel pretty fortunate. It’s a good life phylosophy, but the issue is that I believed that every single event and circumstance was a blessing (in retrospect, of course). Now I can single out one aspect that is more important than others.&lt;/p&gt;

&lt;p&gt;I was born in 1990 in Moldova, as the Soviet Union was about to collapse. By the time I was in my early 20s, the borders were open enough to travel, study and live abroad.&lt;/p&gt;

&lt;p&gt;Would I have been born too early (I’m thinking 20-30 years earlier), it might have been challenging to part ways with the old world and build a new life. I probably wouldn’t have had the same resources or need to learn foreign languages. I wouldn’t have traveled to Europe for fun. I wouldn’t have stumbled upon software engineering or had the opportunity to pursue a fruitful career in this domain. If I were to be born later, no idea what would have happened, as the history is still unfolding.&lt;/p&gt;

&lt;p&gt;I’m not an outlier, I’m ok with a local maxima. But given the place, I showed up at a pretty good time.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I know that ‘60-70s would have been a perfect time for some, but given my business ignorance, I probably would have missed the opportunity.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2020/10/15/right-time-right-place/</id>
      <updated>2020-10-15T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>How to feedback</title>
      <link href="http://ana-balica.github.io/2020/10/06/how-to-feedback/" />
      <summary type="html">&lt;p&gt;These are some things I learned over the years about feedback.&lt;/p&gt;

&lt;h2 id=&quot;why&quot;&gt;Why&lt;/h2&gt;

&lt;p&gt;Never loose focus on why we give and receive feedback. We do that because &lt;strong&gt;we want to help others excel and to better ourselves&lt;/strong&gt;. 
Further below I break it down into 2 parts: giving via Situation-Behaviour-Impact model and receiving via Listen-Explore-Echo (not a coined term, sort of my interpretation).&lt;/p&gt;

&lt;h2 id=&quot;situation-behaviour-impact&quot;&gt;Situation-Behaviour-Impact&lt;/h2&gt;

&lt;p&gt;It only works if the feedback is heard and understood by the receiver. So it matters what you say and how you deliver it. 
I like SBI, because it’s simple, effective and it reduces bias.&lt;/p&gt;

&lt;p&gt;SBI breaks down the feedback into 3 components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Situation&lt;/em&gt; - this is something that happened at a certain time and at a specific location. Normally both the giver and the receiver can agree on it as a fact. Example: “During the team meeting last Monday we were discussing the project X plan for the next quarter.”&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Behaviour&lt;/em&gt; - describe the behaviour that you’ve observed. What did the other person do? Avoid your personal interpretations and don’t try to guess their motivation. Example: “When person Y was talking about a design approach, you interrupted them mid-sentence.”&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Impact&lt;/em&gt; - explain how did the behaviour in that particular situation affected you, the team, the organisation. It doesn’t have to be quantifiable impact, you can talk about your emotional state in that situation. Optionally you can offer a solution. Example: “I felt that you didn’t give them a chance to fully express their idea and that might impair their desire to share with the team in the future.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;listen-explore-echo&quot;&gt;Listen-Explore-Echo&lt;/h2&gt;

&lt;p&gt;Giving feedback is damn challenging, receiving - even more so. You have to suppress the natural fight-or-flight response and not get instantly angry or defensive.&lt;/p&gt;

&lt;p&gt;This is my made-up feedback response model:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Listen&lt;/em&gt; - don’t interrupt or start making excuses, give space and time for the other person to share their thoughts. If you can, take notes (albeit might be rude in some situations), because in the current state of mind it’s hard to keep track of everything. Your mind will want to cling to one particular thing and it will loose focus. This is a reason why people often prefer written down feedback, as they can take their time to process it.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Explore&lt;/em&gt; - don’t assume, ask. Feedback comes in all shapes and sizes, so sometimes you need to poke at it a little bit more. Your end goal is to understand what the other person is trying to tell you, so go ahead and ask questions.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Echo&lt;/em&gt; - finally repeat back the feedback and ask if you got it right. This solidifies your mutual understanding of the situation, helps avoid any misinterpretations and sends a positive signal to the other person that they are being heard. If you can, you might start discussing solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h2&gt;

&lt;p&gt;These models are just guidance. Whether it’s face to face (which is my personal preference) or in written form, you can adapt and shape these models accordingly. Do you have a different approach? Let me know!&lt;/p&gt;

&lt;p&gt;Remember, feedback is hard. Change is hard. You’re doing your best. Keep at it!&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2020/10/06/how-to-feedback/</id>
      <updated>2020-10-06T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Shameless reading of notes on stage</title>
      <link href="http://ana-balica.github.io/2018/09/30/shameless-reading-of-notes-on-stage/" />
      <summary type="html">&lt;p&gt;I’ve given &lt;a href=&quot;http://ana-balica.github.io/talks/&quot;&gt;talks&lt;/a&gt; on stage since 2015. With time and practice I found my own style and pace. I learned things that come to me easily and things that I struggle with.&lt;/p&gt;

&lt;p&gt;One of these things is speaking fluently and not making mistakes, which is tricky for someone like me who is not a native English speaker.&lt;/p&gt;

&lt;p&gt;I remember preparing for my first talk and discovering speakers view. I was genuinely astonished to have a separate screen just for myself where I can see the timer, the next build step and, most important, my notes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/stage-notes/speakers-view.png&quot; alt=&quot;Speakers view&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pretty early on I decided my focus is the audience, which meant I want to present well-researched material that is meant to be understood (rather than just skimmed over or be a show-off). To accomplish this I usually need good visuals and a good script.&lt;/p&gt;

&lt;p&gt;Putting aside the complexities of expressing information with visuals, verbal delivery is essential. Here are some of the reasons why:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;keeping the right pace. Usually talks have a limited amount of time. You don’t want to spend extra 3 minutes explaining the part about header compression and then rush over the interesting statistics that you added to your finishing slides.&lt;/li&gt;
  &lt;li&gt;keeping the right content. It’s not unusual to see yourself diverging from a topic.&lt;/li&gt;
  &lt;li&gt;keeping it fluent and concise. I could ramble and say something in 3 sentences with a couple of umm, ehh and pauses to remind myself that word I just forgot. Or I could have a well-formed one sentence written in advance that conveys the same information, but with less overhead.&lt;/li&gt;
  &lt;li&gt;avoid mistakes. Correct grammar and usage of a language will help deliver your message in a non-ambiguous way.&lt;/li&gt;
  &lt;li&gt;never go silent. If you ever do, notes are there to help you pick up where your mind went blank.&lt;/li&gt;
  &lt;li&gt;publishing your talk notes. Like I did with &lt;a href=&quot;http://ana-balica.github.io/2017/05/28/humanizing-among-coders/&quot;&gt;Humanising among coders&lt;/a&gt;. This is helpful, because it’s indexable, scannable and ideal for people with hearing problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can do this without any external aid, I applaud you in the most sincere and mildly jealous way. I can’t. That’s why I use a script. I write everything I want to say from start to end. I usually do it slide by slide. The volume of the content helps me understand if my slide is overloaded with information and I need to split it in 2. When rehearsing I can see the total time talking and be confident that it’s gonna be consistent when I get up on stage.&lt;/p&gt;

&lt;p&gt;With a script in front of me, I managed to give pretty &lt;a href=&quot;https://youtu.be/DtTKF5OcpsU&quot;&gt;bad robotic presentations&lt;/a&gt;. I got sucked into the strict flow that I’ve set for myself and didn’t manage to inspire the audience.&lt;/p&gt;

&lt;p&gt;Meanwhile I’ve given really &lt;a href=&quot;https://www.youtube.com/watch?v=Zo5q48BG8A4&quot;&gt;good and seamless presentations&lt;/a&gt;. The trick there is a well rehearsed script, where you keep track mentally of the broader topic and sentiment that you want your audience to perceive. Read it with understanding and emotion. It will bring you great pleasure when a talk is delivered smoothly with thoughtfulness and care, when it has a quality of a story told by a compelling narrator.&lt;/p&gt;

&lt;p&gt;You choose what works for you: no notes, single-worded notes per slide, rough topics, partial or full scripts, as long as you feel comfortable to present your ideas on stage. There’s no shame in being well prepared, whatever that takes.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2018/09/30/shameless-reading-of-notes-on-stage/</id>
      <updated>2018-09-30T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Empathetic bug report</title>
      <link href="http://ana-balica.github.io/2018/09/08/empathetic-bug-report/" />
      <summary type="html">&lt;p&gt;&lt;em&gt;“Feature X doesn’t work”.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sigh, take a deep breath, pause for a bit… start asking questions:
what exactly doesn’t work,
what do you see on screen,
do you have a URL or screenshots,
what environment are you on, are you logged in,
what permissions your user has, etc.
I get it, sometimes it’s hard to know what additional information is relevant,
especially for people who have had less experience interacting with developers.
But even we (engineers, product owners, designers) make this mistake every so often.&lt;/p&gt;

&lt;p&gt;That’s not the biggest issue though.
What matters more is phrasing.
The assentive tone of the sentence sends a subtle message.
It somewhat implies that the feature X doesn’t work regardless of circumstances,
for all users and the whole team managed to spend a couple days work and ship nothing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Feature X doesn’t work for me”.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By focusing on your personal experience with the app,
it’s possible to approach the bug report in a more humble way,
admitting that it might be “you”, “your settings”, “your machine”
that are causing the app to act in a weird way.
At the end of the day, the quite blunt obvious defect is often a cause of misconfiguration,
wrong environment, misunderstanding of the feature
(which admittedly can be a bug, but should have been caught during early discussions and refinement).&lt;/p&gt;

&lt;p&gt;Next time at work when you’re raging over a feature that doesn’t work, don’t forget to add &lt;em&gt;“for me”&lt;/em&gt;.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2018/09/08/empathetic-bug-report/</id>
      <updated>2018-09-08T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>How to filter by DateRange with django-filters</title>
      <link href="http://ana-balica.github.io/2018/08/12/how-to-filter-by-daterange-with-django-filters/" />
      <summary type="html">&lt;p&gt;Django offers a few fields that are exclusive to Postgres. I recently had to use &lt;a href=&quot;https://docs.djangoproject.com/en/2.1/ref/contrib/postgres/fields/#daterangefield&quot;&gt;DateRangeField&lt;/a&gt; which is an interesting alternative to doing the usual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start_date&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;end_date&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you’re using Django Rest Framework, you are probably familiar with &lt;a href=&quot;https://django-filter.readthedocs.io/en/master/&quot;&gt;django-filters&lt;/a&gt;. It’s a generic system for filtering Django QuerySets, though I’ve mostly used it in combination with DRF.&lt;/p&gt;

&lt;h2 id=&quot;timestamped&quot;&gt;Timestamped&lt;/h2&gt;

&lt;p&gt;Tested with following versions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Django 1.11 (confident this will work with Django 2.1)&lt;/li&gt;
  &lt;li&gt;django-filters 2.0.0 (won’t work with previous versions, because 2.0 release includes a reworked version of RangeWidget)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;

&lt;p&gt;Ranges are composed of lower and upper bounds that operate as a whole value. I want to be able to specify both bounds when filtering and get the objects that satisfy these exact values. By default, Django stores &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateRangeField&lt;/code&gt; in its canonical form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[)&lt;/code&gt; - lower inclusive and upper exclusive. In this case, I’m fine to specify and filter the bounds only in their canonical form. But it should be fairly easy to extend this to support different range types.&lt;/p&gt;

&lt;p&gt;From the &lt;a href=&quot;https://django-filter.readthedocs.io/en/master/ref/filters.html#filters&quot;&gt;filters list&lt;/a&gt; I spot &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateRangeFilter&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateFromToRangeFilter&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateRangeFilter&lt;/code&gt; defines a list of choices to select from (like today, yesterday past week, etc), not exactly what I’m looking for. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateFromToRangeFilter&lt;/code&gt; looks more appealing, as it allows filtering using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_after&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_before&lt;/code&gt; suffixes. It will conveniently convert the passed strings to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateField&lt;/code&gt; and do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gte&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lte&lt;/code&gt; lookups on the field. Still not exactly what I need.&lt;/p&gt;

&lt;h2 id=&quot;show-me-the-code&quot;&gt;Show me the code&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django_filters&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;psycopg2.extras&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateRange&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DateExactRangeWidget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;django_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;widgets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateRangeWidget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Date widget to help filter by *_start and *_end.&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;suffixes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;start&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;end&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DateExactRangeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;django_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateRangeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;widget&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateExactRangeWidget&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_list&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DateExactRangeFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;django_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
    Filter to be used for Postgres specific Django field - DateRangeField.
    https://docs.djangoproject.com/en/2.1/ref/contrib/postgres/fields/#daterangefield
    &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;field_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateExactRangeField&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In your app:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django_filters&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.filters&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateExactRangeFilter&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EventFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;django_filters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rest_framework&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FilterSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;event_dates&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateExactRangeFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Event&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;event_dates&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;explanation&quot;&gt;Explanation&lt;/h2&gt;

&lt;p&gt;Let’s start from the bottom - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateExactRangeFilter&lt;/code&gt;. Since we are doing a regular lookup, we are inheriting directly from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;field_class&lt;/code&gt; here is important, as it converts the raw values to a format and type we need, in this case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateRange&lt;/code&gt; composed of start and end dates. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateExactRangeWidget&lt;/code&gt; lists the available suffixes.&lt;/p&gt;

&lt;p&gt;Now you can do this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/events?event_dates_start=2018-08-07&amp;amp;event_dates_end=2018-08-12&lt;/code&gt; to filter all events that start and end exactly on these dates.&lt;/p&gt;

&lt;h2 id=&quot;warning&quot;&gt;Warning&lt;/h2&gt;

&lt;p&gt;This solution is not ideal, because none of this documented. Django-filters doesn’t provide a guide on how to extend existing classes to add your own filters, fields or widgets. The details of how these objects behave might change with time, hence use this at your own risk.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2018/08/12/how-to-filter-by-daterange-with-django-filters/</id>
      <updated>2018-08-12T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>My parents told me I&apos;m pretty</title>
      <link href="http://ana-balica.github.io/2018/07/21/my-parents-told-me-im-pretty/" />
      <summary type="html">&lt;p&gt;As I child, I hated my skin colour, my name, my boring hair colour, my height, my asymmetrical eyes and lack of lashes on a patch of my left eye. When I say “hate”, this was the literal word I’d use. Probably I’ve been bitter about lots of other things, but I can’t remember them all now. Largely because I believe my parents eradicated most of these insecurities by constantly reminding me that I’m pretty.&lt;/p&gt;

&lt;p&gt;The power lies not in just repeating this like a mantra. It didn’t feel like it was just parent’s blind love - “No matter what others think, we love you anyway”. Nah, wasn’t like that.&lt;/p&gt;

&lt;p&gt;Say, I was bummed out about my darker skin. I know I look white to most, but in my community I was slightly darker than others. My mom would always emphasise how beautiful my olive skin looks and how rare it is. She’d include this in every homework description I had to write about myself. She’d point out how other famous people have similar skin tone - this made me pay attention. Now I’m perfectly fine in my own skin (pun intended).&lt;/p&gt;

&lt;p&gt;It went on and on, picking one thing at a time and making me proud of just how it is. Interestingly I think this didn’t make me narcissistic or obsessed with beauty over values and brains.&lt;/p&gt;

&lt;p&gt;I have no idea if they did this deliberately, but they managed to make me accept who I am.&lt;/p&gt;

&lt;p&gt;So, I guess, tell your close ones they are pretty 💛&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2018/07/21/my-parents-told-me-im-pretty/</id>
      <updated>2018-07-21T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Dealing with disagreements</title>
      <link href="http://ana-balica.github.io/2018/07/03/dealing-with-disagreements/" />
      <summary type="html">&lt;p&gt;You are in an interview. The interviewer across the table asks you: ‘What do you do if you disagree with someone on your team? How do you resolve this situation?’. You pause and take 10 seconds to think about it.&lt;/p&gt;

&lt;p&gt;The tricky part is that there’s probably no right answer. It depends, right? What does it depend on though?&lt;/p&gt;

&lt;p&gt;For me, there’s one core factor: &lt;strong&gt;impact of the decision&lt;/strong&gt;. Sometimes we like to argue for things that are pretty minor and are most probably easy to correct if they go wrong.&lt;/p&gt;

&lt;p&gt;Say, you are arguing for solution A and Kathy is convinced we should go for solution B. You have experience with these things, so you are solid that solution A is the right thing to do. But somehow your wisdom and compelling arguments aren’t reaching Kathy. Stop and assess the impact of going for solution B and imagine what would it take to correct the course. You might find out that this correction is pretty minuscule or at least fairly harmless. Go for solution B! Two reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You want them to &lt;a href=&quot;http://randsinrepose.com/archives/act-last-read-the-room-and-taste-the-soup/&quot;&gt;taste the soup&lt;/a&gt;. They need to try and come to their own conclusions on this topic. The learnings from this will have a stronger effect and will be backed up by real experience.&lt;/li&gt;
  &lt;li&gt;Who knows, maybe you’ll learn something new. It’s useful to introduce a bit of entropy in our lives. &lt;a href=&quot;https://www.youtube.com/watch?v=8qpgL6ndEQU&quot;&gt;Once we are settled in our ways and we “truly see” the world for what it is, we loose any capacity to be flexible and learn.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What if the impact is massive? Everybody in the room agrees we want to land on the best available solution.&lt;/p&gt;

&lt;p&gt;Step away from this and ask yourself &lt;strong&gt;why do all of us disagree?&lt;/strong&gt; Assuming I find myself in a group of well-meaning smart people, I can’t help but wonder what am I missing that I find it hard to accept a different opinion. This is quite profound to think about for me, because it shifts the focus from this isolated case centred around this fixed topic to a wider perspective that sheds light on our core concepts, values, rules and ideas that each one of us settled for. I want to make sure the foundation is same for everyone. I want to know now if I missed something important so that I don’t continue diverging to wrong conclusions. These disagreements can uncover gaps in our shared understanding of the problem. Find this problem and fix it.&lt;/p&gt;

&lt;p&gt;All in all, these pesky disagreements are useful as they teach us to work with others and help us uncover interpretations.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2018/07/03/dealing-with-disagreements/</id>
      <updated>2018-07-03T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>The Cemetery of Ideas or Why I Stopped Writing</title>
      <link href="http://ana-balica.github.io/2018/06/03/the-cemetery-of-ideas/" />
      <summary type="html">&lt;p&gt;My last blogpost was published on &lt;a href=&quot;http://ana-balica.github.io/2017/11/11/python-mutable-vs-immutable/&quot;&gt;November 11th 2017&lt;/a&gt;,
which would make it over half a year old.&lt;/p&gt;

&lt;p&gt;I don’t think the reason for my writing blackout was general busyness of life.
Yes, I did transition into a new role and I’ve taken on new challenges,
but if I wanted to write something, I would have done so regardless of time constraints.&lt;/p&gt;

&lt;p&gt;Truth is I have a backlog of article ideas. I look over them every Sunday during the review of my TODO list.
Something stops me from elaborating on any of them and uploading them here.&lt;/p&gt;

&lt;p&gt;A recent short discussion made me think should one post for the sake of keeping themselves going
or should one filter and invest in writing only when there’s something worth of sharing.&lt;/p&gt;

&lt;p&gt;What I struggle with most is that if it’s not something that I have wrestled with, and
spend a lot of time on it, or invested myself directly into it, I don’t feel like I have
the permission to talk about it.&lt;/p&gt;

&lt;p&gt;There are different types of posts. I could write more stuff about Python and Django,
very specific technologies that I have experience with, but because I swim in this day by day,
I don’t find any of it all that interesting or innovative to talk about.
Moreover considering there are so many other excellent resources on the internet,
I’m gonna be yet another lost voice repeating the stuff that’s already known.&lt;/p&gt;

&lt;p&gt;Then there’s the stuff I have spent more time on, for example my posts about Datastore indexes
(&lt;a href=&quot;http://ana-balica.github.io/2016/11/20/datastore-indexes-basics/&quot;&gt;[1]&lt;/a&gt; &amp;amp; &lt;a href=&quot;http://ana-balica.github.io/2016/11/28/intricacies-and-optimization-of-datastore-indexes/&quot;&gt;[2]&lt;/a&gt;).
I honestly don’t think anyone will ever read this, because it’s such a niche thing.
But because I paved my own path to understanding and figuring out some tips and tricks by myself,
I feel like I’m genuine when I talk about it.&lt;/p&gt;

&lt;p&gt;I thought I want to write about the nature of bugs in software.
Working titles: “Embrace your bugs”, “We all have bugs”, “Bugs: let them be”.
I can trace the idea back to this book: &lt;a href=&quot;https://www.amazon.co.uk/Turn-Ship-Around-Building-Breaking/dp/1591846404&quot;&gt;Turn the ship around&lt;/a&gt;
by L. David Marquet.&lt;/p&gt;

&lt;p&gt;I’ll give you the gist: strive for excellence, don’t focus on avoiding mistakes.
If mistakes is all you care about, dodging bugs will drain all you time and energy.
And bugs happen all the time. See what lies beyond and aim for excellence.&lt;/p&gt;

&lt;p&gt;I read the book by the recommendation of my manager. This idea from the book is not original.
But because I know the source of the idea and the way I came to is certainly not original,
I grapple taking the bugs blogpost any further.&lt;/p&gt;

&lt;p&gt;Quite often when I write, I feel not like an imposter, but like a thief.
I read, listen, compile, reshape, put it in a pretty box and present it to others.&lt;/p&gt;

&lt;p&gt;This is why I haven’t been writing.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=nJPERZDfyWc&quot;&gt;Everything is a remix&lt;/a&gt;, but one hopes to create a remix that will become the original for other remixes.&lt;/em&gt;&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2018/06/03/the-cemetery-of-ideas/</id>
      <updated>2018-06-03T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Python: mutable vs immutable</title>
      <link href="http://ana-balica.github.io/2017/11/11/python-mutable-vs-immutable/" />
      <summary type="html">&lt;p&gt;Mutable means an object can be modified after it’s been created.
In contrast immutable is an object whose state can’t be changed after its creation.
Python has both mutable and immutable data types.
There’s a simple recipe to figure out if an object can be “mutated”:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;initialise a variable of the target type&lt;/li&gt;
  &lt;li&gt;store the ID
(Python has a build-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id()&lt;/code&gt; function. In CPython this is the address of the object in memory.)&lt;/li&gt;
  &lt;li&gt;mutate the variable&lt;/li&gt;
  &lt;li&gt;check the previously stored ID vs the current ID of the variable&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;mutable-types&quot;&gt;Mutable types&lt;/h2&gt;

&lt;p&gt;Take lists.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salad&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;spinach&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;tomatoes&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;salad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salad&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;eggs&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_after&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;salad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_after&lt;/span&gt;
&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I created my original salad with 2 ingredients. Then I added another ingredient - eggs.
Even after the mutation (adding eggs), the salad object is still pointing to the same place in memory,
it has the same ID.&lt;/p&gt;

&lt;p&gt;Even though we have used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; to mutate the list, Python exposes many methods
that imply that lists are mutable: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list.append&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list.pop&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list.remove&lt;/code&gt;.
With its API design programming languages usually try to tell us what is mutable and what is not.&lt;/p&gt;

&lt;h2 id=&quot;immutable-types&quot;&gt;Immutable types&lt;/h2&gt;

&lt;p&gt;Take strings.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;foo&apos;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;my_string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;bar&apos;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_after&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_before&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id_after&lt;/span&gt;
&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here we are doing something similar to what we did with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;salad&lt;/code&gt; list - use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; to append to the original string.
However in this case the object after the mutation happens to reside in a different place in memory.&lt;/p&gt;

&lt;p&gt;In fact, Python doesn’t really provide any methods to modify a string “in place” (or give us the illusion we can do that),
hinting on the fact that strings are immutable.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Now you’re able to understand better how mutability works.
Have fun figuring out the mutability of the other Python data types!&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2017/11/11/python-mutable-vs-immutable/</id>
      <updated>2017-11-11T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Struggling for creativity</title>
      <link href="http://ana-balica.github.io/2017/09/19/struggling-for-creativity/" />
      <summary type="html">&lt;p&gt;When I was in middle school (somewhere between 12 and 16 years old),
I wrote an essay for our English class
about the butterfly life cycle.
It was a short read and in some way beautiful (for a school assignment).
I was proud of it.
I remember my classmate asked me how did I manage to write this.
I shrugged it off, saying I just did it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complete lie.&lt;/strong&gt; I had a very meticulous process that I followed when writing anything.&lt;/p&gt;

&lt;p&gt;It’s all about the slow start and building blocks. 
As kids we first learn words to build up enough vocabulary.
From there we are asked to create sentences.
This one always puzzled me, because it’s tricky to come up
with a good sentence without any context.
Then we follow up with essays on a given topic.
From my experience it was mostly descriptions of physical things,
experiences or phenomena. &lt;em&gt;Describe in 150 words your favourite season.
Write an essay about your latest trip to grandparents.
Create a portrait of you mother.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And, oh boy, I sucked at it. I was seriously struggling
to express myself and write anything original.
In fact, for half of my school years my mother wrote my essays for me.
She is a native Russian speaker, learned Romanian together with me while I was growing up.
She would take the Russian - Romanian dictionary and try her best to compose a cohesive essay for my Romanian class.
As a journalism graduate, she had a taste for books and writing.
Of course, she shined when writing for my Russian class.
My teacher never skipped an opportunity to listen to what my mother wrote. 
Presumably she thought I made up most of it and someone with more experience “helped” me.&lt;/p&gt;

&lt;p&gt;And so it went. My mother liked writing in free form. 
She despised the template and was always trying to think of something captivating.
When it came to foreign languages (I did English, French and German),
my mother was trying her best, but word for word translations weren’t any good.
So I had to come up with a way of composing something that was at least a bit readable
(it is ridiculous my mum was doing my homework for me).&lt;/p&gt;

&lt;p&gt;Throughout the years, I learned about the structure of a composition: 
the introduction, the body and the conclusion. 
My teacher of Romanian took it to the extremes saying that any sentence should follow the same
logical structure. I learned about canned intros, closing thoughts,
most used connection words. 
I was taught I can create a plan of what I want to cover in a composition.
I was asked to dissect other people’s work and identify their works’ compositional parts.
Obviously I learned from my mum, while writing down in silence as she was dictating
word for word the essay to me.
It all boiled down to a framework for writing.&lt;/p&gt;

&lt;p&gt;Here’s how I did it. I would get a topic and research it, learn about any processes involved. 
Then make a plan, put down some bullet points.
If it’s a description (and most of the times it was) pick up the dictionary
and find enough adjectives and verbs that would aid that description.
I would start with a few known words, identify good synonyms
and repeat the process a few times until I end up with a word cloud 
that’s not too banal and not too obscure. &lt;em&gt;Nowadays I use thesaurus.com.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next I need to pick up some figures of speech.
Good I had a list of these as well.
Similarly I would choose a good intro template and adjust it slightly
to not sound too boring. Follow my composition plan.
And finally pick a good conclusion that fits the tone of the essay.
Throughout the writing use the selected adjectives, verbs and figures of speech.&lt;/p&gt;

&lt;p&gt;This is how I wrote my essay about the butterfly life cycle.
I struggled being creative, and still do. 
I follow a set of rules that help me think things up.
This is, of course, far from true creativity, but it works for me.&lt;/p&gt;

&lt;p&gt;Who knows, maybe you’ll find this framework useful yourself.
At the end of the day 
&lt;a href=&quot;https://www.youtube.com/watch?v=nJPERZDfyWc&quot; target=&quot;_blank&quot;&gt;everything is a remix&lt;/a&gt;.&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2017/09/19/struggling-for-creativity/</id>
      <updated>2017-09-19T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Django week_day Field lookup</title>
      <link href="http://ana-balica.github.io/2017/08/14/django-week-day-field-lookup/" />
      <summary type="html">&lt;p&gt;Django’s ORM offers built-in field lookups, one of which is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;week_day&lt;/code&gt;. So one can do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sale.objects.get(sale_date__week_day=2)&lt;/code&gt; to find out how well is the business doing on Mondays.&lt;/p&gt;

&lt;p&gt;Wait what? How come 2 is a Monday? According to Python documentation, there are 2 possible weekday representations (identical methods are available for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datetime&lt;/code&gt; objects):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date.weekday&lt;/code&gt; considers a weekday from &lt;a href=&quot;https://docs.python.org/3/library/datetime.html#datetime.date.weekday&quot;&gt;0 (Monday) to 6 (Sunday)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date.isoweekday()&lt;/code&gt; considers a weekday from &lt;a href=&quot;https://docs.python.org/3/library/datetime.html#datetime.date.isoweekday&quot;&gt;1 (Monday) to 7 (Sunday)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whereas Django interprets the integer as &lt;a href=&quot;https://docs.djangoproject.com/en/1.11/ref/models/querysets/#week-day&quot;&gt;1 (Sunday) to 7 (Saturday)&lt;/a&gt;. Here’s a short util to transform from Python to Django weekday value:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_django_weekday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isoweekday&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Databases too have different interpretations for this value:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;MySQL and Oracle are identical to Django’s weekday value - 1 (Sunday) to 7 (Saturday)&lt;/li&gt;
  &lt;li&gt;PostgreSQL - 0 (Sunday) to 6 (Saturday)&lt;/li&gt;
  &lt;li&gt;SQLite is identical to Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isoweekday()&lt;/code&gt; representation  - 1 (Monday) to 7 (Sunday)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though the value varies between databases, it’s still not exactly clear why this value is so alien to any of the Python representations. I think I will pester some people today at &lt;a href=&quot;https://2017.djangocon.us/&quot;&gt;DjangoCon US&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;UPD:&lt;/strong&gt; Thanks to &lt;a href=&quot;https://twitter.com/mjtamlyn&quot;&gt;Marc Tamlyn&lt;/a&gt; for confirming that there isn’t any special reason for the choice of weekday interpretation in Django (maybe MySQL). This code was last time updated in &lt;a href=&quot;https://github.com/django/django/commit/a584a6b40f8&quot;&gt;2009&lt;/a&gt; and, at this point, an update would be backwards incompatible.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2017/08/14/django-week-day-field-lookup/</id>
      <updated>2017-08-14T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>NDB in-context cache behaviour</title>
      <link href="http://ana-balica.github.io/2017/07/19/ndb-in-context-cache-behaviour/" />
      <summary type="html">&lt;p&gt;NDB allows an App Engine app to connect to Cloud Datastore.
It helpfully provides 2 types of caching enabled by default: memcache and
&lt;a href=&quot;https://cloud.google.com/appengine/docs/standard/python/ndb/cache#incontext&quot;&gt;in-context cache&lt;/a&gt;
(also referred to as in-memory cache).&lt;/p&gt;

&lt;h2 id=&quot;timestamped&quot;&gt;Timestamped&lt;/h2&gt;

&lt;p&gt;App Engine Python SDK 1.9.57&lt;/p&gt;

&lt;h2 id=&quot;anything-wrong-with-it&quot;&gt;Anything wrong with it?&lt;/h2&gt;

&lt;p&gt;Yes and no. See this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LegoBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pieces_count&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pieces_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# set the value, don&apos;t save
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LegoBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pieces_count&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LegoBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use_cache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pieces_count&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When fetching a fresh object even within the same thread,
one would expect to get the value from the database and not the one from an in-memory cache.
This is considered &lt;a href=&quot;https://issuetracker.google.com/issues/35897973&quot;&gt;working as intended&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A happy clueless developer could write this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_smth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LegoBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;box_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;architecture&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;v1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count_pieces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Refresh the box object and check the result
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pieces_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;544&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LegoBox.count_pieces&lt;/code&gt; has a bug in it where it forgets to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put&lt;/code&gt; (bugs happen y’know).
Unless one is diligent to always disable the in-context cache for the fetches,
this test isn’t good enough,
because it doesn’t expose the bug.
YOLO!&lt;/p&gt;

&lt;p&gt;Sadly this behaviour is not mentioned in the official documentation,
so there’s a high chance one will discover this “desired” effect in a bitter situation while debugging for hours.&lt;/p&gt;

&lt;h2 id=&quot;how-to-disable-in-context-cache&quot;&gt;How to disable in-context cache&lt;/h2&gt;

&lt;p&gt;First strategy is to pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;use_cache=False&lt;/code&gt; when making queries.&lt;/p&gt;

&lt;p&gt;Second option is to disable the cache per model. In theory this will slow down your app.
In practice, I don’t have benchmarks, so I don’t know.
Moreover it always depends on what you are doing.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LegoBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ndb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_use_cache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Third stategy is to set a global policy to turn off automatic caching for all NDB models and be done with it.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# appengine_config.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;google.appengine.ext&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndb&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ndb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_cache_policy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;hr /&gt;

&lt;p&gt;I was a happy-go-lucky developer who wrote lots of passing tests that interact with NDB models,
only later to discover that the code is failing in production.
Luckily people smarter than me pointed out what might be the cause.
This is a cautionary story to help one avoid such issues.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2017/07/19/ndb-in-context-cache-behaviour/</id>
      <updated>2017-07-19T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Humanizing among coders</title>
      <link href="http://ana-balica.github.io/2017/05/28/humanizing-among-coders/" />
      <summary type="html">&lt;p&gt;This is a transcript of the keynote I gave at &lt;a href=&quot;https://cz.pycon.org/2016/&quot;&gt;PyCon CZ 2016&lt;/a&gt;.
It’s a bit lengthy, but hopefully worth your attention. Alternatively there’s a &lt;a href=&quot;https://www.youtube.com/watch?v=npyB5Oz-v-I&quot;&gt;video recording&lt;/a&gt;
of the talk you can watch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/humanizing/humanizing.001.jpeg&quot; alt=&quot;Humanizing among coders slide 1&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.002.jpeg&quot; alt=&quot;Humanizing among coders slide 2&quot; /&gt;
    &lt;p&gt;Hello! Ahoj! Salut!&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.003.jpeg&quot; alt=&quot;Humanizing among coders slide 3&quot; /&gt;
    &lt;p&gt;There used to be a time when a tech-savvy, computer person was regarded as a reclusive night creature that lived in the basement and loathed going outside and talking to people. There are developers who prefer to work at night and don&apos;t feel very comfortable interacting with others. And that&apos;s alright. But the stereotype&apos;s been changing.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.004.jpeg&quot; alt=&quot;Humanizing among coders slide 4&quot; /&gt;
    &lt;p&gt;Similarly to how technology and some forms of programming have been creeping into the mainstream, the typical programmer has evolved into a social person, who likes going to conferences, meetups and hack days, give talks and generally enjoys the company of others.&lt;/p&gt;

    &lt;p&gt;We all know being a programmer isn&apos;t only about writing code, drawing diagrams and navigating documentation. It&apos;s also about planning, brainstorming, arguing design decisions with your team, giving and receiving feedback, joining client meetings and discussions, finding a middle-ground between clients&apos; or communities&apos; requirements and real world possibilities and being able to explain that.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.005.jpeg&quot; alt=&quot;Humanizing among coders slide 5&quot; /&gt;
    &lt;p&gt;Suppose our different sets of skills are a layered cake. &lt;em&gt;Yum!&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.006.jpeg&quot; alt=&quot;Humanizing among coders slide 6&quot; /&gt;
    &lt;p&gt;One big layer is dedicated to technical expertise...&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.007.jpeg&quot; alt=&quot;Humanizing among coders slide 7&quot; /&gt;
    &lt;p&gt;... and another layer for social competence.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.008.jpeg&quot; alt=&quot;Humanizing among coders slide 8&quot; /&gt;
    &lt;p&gt;Truth is, we still prioritize technical expertise over social and emotional education. Just think about the plethora of books, tutorials and articles that teach us coding. Even the most niche little things, find a community of devs that care about it and want to share and learn.&lt;/p&gt;
    &lt;p&gt;Conversely the social aspect of what makes a good developer isn&apos;t referred to very often.&lt;/p&gt;
    &lt;p&gt;&lt;em&gt;What does it actually mean to be a good developer from a social point of view?&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.009.jpeg&quot; alt=&quot;Humanizing among coders slide 9&quot; /&gt;
    &lt;p&gt;Is it about smiling to each other all the time? Or is it about general courtesies like saying &quot;Hi&quot;, &quot;Bye&quot; and &quot;Thank you&quot;? It&apos;s definitively about not insulting or harassing your team or community.&lt;/p&gt;
    &lt;p&gt;This talk isn&apos;t exactly going to be about that.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.010.jpeg&quot; alt=&quot;Humanizing among coders slide 10&quot; /&gt;
    &lt;p&gt;This talk is about the subtle &quot;that wasn&apos;t quite right&quot; moments and all sorts of invisible interactions that happen all the time between us and can inconspicuously shape the general mood around us. It&apos;s that slim layer of the cake.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.011.jpeg&quot; alt=&quot;Humanizing among coders slide 11&quot; /&gt;
    &lt;p&gt;This is our first story: &quot;Beginners &amp;amp; Mentorship&quot;.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.012.jpeg&quot; alt=&quot;Humanizing among coders slide 12&quot; /&gt;
    &lt;p&gt;Meet Martina. Martina is the maintainer of open source project &lt;code&gt;grepy&lt;/code&gt;. She handles the releases, changelogs and merging code into upstream.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.013.jpeg&quot; alt=&quot;Humanizing among coders slide 13&quot; /&gt;
    &lt;p&gt;This is Ionel and he is currently in his 2nd year at university, has been using C for a while and knows a bit of Python and JavaScript. He really likes &lt;code&gt;grepy&lt;/code&gt; and has been using it for a while. He figured he&apos;s missing an itty-bitty feature - making &lt;code&gt;grepy&lt;/code&gt; search for case-insensitive patterns.&lt;/p&gt;
    &lt;p&gt;He knew that the tool is &quot;open source&quot;. He heard that open source is like getting access to some code to which he can make a modification and then share with everybody and everyone will be very grateful to him.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.014.jpeg&quot; alt=&quot;Humanizing among coders slide 14&quot; /&gt;
    &lt;p&gt;Ionel, all enthusiastic, firstly finds out what the IRC address of the &lt;code&gt;grepy&lt;/code&gt; community is, joins and says: &quot;Hi all! I&apos;d like to contribute to your project. How do I get started?&quot;. Reply back: &quot;Welcome :) To get started check the documentation on contributing in the repo.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.015.jpeg&quot; alt=&quot;Humanizing among coders slide 15&quot; /&gt;
    &lt;p&gt;Ionel cracks on with the code, spends about a week of free time in total to implement the feature and creates a pull request. In the comments he says &quot;Hi. This is feature so and so and my first pull request ever. I&apos;m a total beginner.&quot; Here comes the moment of truth!&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.016.jpeg&quot; alt=&quot;Humanizing among coders slide 16&quot; /&gt;
    &lt;p&gt;Martina finally finds some spare time to review the code. She glances over the PR and leaves a couple of comments: &quot;Please remove the loop and change this variable name. For the PR to be accepted we require unit tests and documentation. Back to you.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.017.jpeg&quot; alt=&quot;Humanizing among coders slide 17&quot; /&gt;
    &lt;p&gt;Ionel is crushed by this message. What the hell are unit tests? How do I add docs? What exactly should I write? In reality it took Ionel 3 days to figure out how to run the project and then another 3 to write those 6 lines of code. He can&apos;t understand why his code can&apos;t be merged as is. It works, right? Due to growing frustration, Ionel gives up and never makes the second PR.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.018.jpeg&quot; alt=&quot;Humanizing among coders slide 18&quot; /&gt;
    &lt;p&gt;In an alternate universe, this is what could have happened.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.019.jpeg&quot; alt=&quot;Humanizing among coders slide 19&quot; /&gt;
    &lt;p&gt;Martina glances over the PR and leaves a couple of comments: &quot;Hi, thanks for your contribution. Good job on feature X. Please remove the loop and change the variable name. For the PR to be accepted we require unit tests and documentation. Back to you (smiley face).&quot;&lt;/p&gt;
    &lt;p&gt;This is called sandwich feedback: say something nice, say something not so nice, and end with niceness again. It&apos;s somewhat better than the previous version, but it feels insincere, and people can feel that. We can do better.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.020.jpeg&quot; alt=&quot;Humanizing among coders slide 20&quot; /&gt;
    &lt;p&gt;In an alternate universe, take II.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.021.jpeg&quot; alt=&quot;Humanizing among coders slide 21&quot; /&gt;
    &lt;p&gt;&quot;Hi, thanks for your contribution! We really appreciate having beginners on the project.&lt;/p&gt;
    &lt;p&gt;I see you are using a loop to make the string lowercase. That looks like a valid piece of Python code. You were probably not aware of that, Python has a built-in method for that called &quot;lower&quot;. You can do &lt;code&gt;&apos;aNyStRiNg&apos;.lower()&lt;/code&gt; and it will convert the entire string to lowercase. Neat, right?&lt;/p&gt;
    &lt;p&gt;Don&apos;t worry about missing this, I still have trouble remembering all of those functions and methods from Python STL.&lt;/p&gt;
    &lt;p&gt;Thank you for adding this feature to the &lt;code&gt;grepy&lt;/code&gt;. Usually when we write new features, we find it very useful to provide some short docs on them. If you look into the &lt;code&gt;docs&lt;/code&gt; folder, there is a file called features. Can you please add a line mentioning the case-insensitive argument, that&apos;ll be very helpful.&lt;/p&gt;
    &lt;p&gt;Ohh, and we also usually write tests. There&apos;s a lot of stuff to know about tests. Start by reading this and that. Follow our guide on adding tests.&lt;/p&gt;
    &lt;p&gt;If you get stuck, just ping me on IRC and I&apos;ll try to help you!&quot;&lt;/p&gt;
    &lt;p&gt;Huh, that was verbose. What changed? Everything!&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.022.jpeg&quot; alt=&quot;Humanizing among coders slide 22&quot; /&gt;
    &lt;p&gt;Let&apos;s break it down.&lt;/p&gt;
    &lt;p&gt;The intro: &quot;Hi, thanks for your contribution! We really appreciate having beginners on the project.&quot;&lt;/p&gt;
    &lt;p&gt;Be welcoming. As beginners, they have taken a very big leap to make that first step. Give them some encouragement to keep moving. And if you consider that your project is not well-suited for beginners, more on that a bit later.&lt;/p&gt;
    &lt;p&gt;Only say that you appreciate having beginners contributing, if you really mean it.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.023.jpeg&quot; alt=&quot;Humanizing among coders slide 23&quot; /&gt;
    &lt;p&gt;Seriously, be honest. If you&apos;re gonna say things you don&apos;t believe, don&apos;t even bother. People can sense when you&apos;re talking from a template.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.024.jpeg&quot; alt=&quot;Humanizing among coders slide 24&quot; /&gt;
    &lt;p&gt;If you&apos;re asking for a change, take the time to explain why something is important. Just stating facts sounds like giving orders.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.025.jpeg&quot; alt=&quot;Humanizing among coders slide 25&quot; /&gt;
    &lt;p&gt;And you won&apos;t believe how some things obvious things to you aren&apos;t obvious at all for beginners or even other developers.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.026.jpeg&quot; alt=&quot;Humanizing among coders slide 26&quot; /&gt;
    &lt;p&gt;&quot;Don&apos;t worry about missing this, I still have trouble remembering all of those functions and methods from Python STL.&quot;&lt;/p&gt;
    &lt;p&gt;With this you&apos;ve established a very humane connection. You&apos;ve admitted of your own flaws, which makes you seem more real and humane, not a super-creature (if you&apos;ve actually memorized all of the Python STL, then don&apos;t lie for the sake of the contributor to feel good about themselves). You&apos;ve connected with something very deep within yourself to understand what the person on the other side of the computer screen experiences.&lt;/p&gt;
    &lt;p&gt;This ability to put yourself in other people&apos;s shoes, to feel with them has a name.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.027.jpeg&quot; alt=&quot;Humanizing among coders slide 27&quot; /&gt;
    &lt;p&gt;It&apos;s called empathy.&lt;/p&gt;
    &lt;p&gt;Empathy is about taking perspective, withholding judgment, recognizing emotion in other people and communicating it. &lt;strong&gt;We all need a little bit more empathy, both on the giving and receiving end.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.028.jpeg&quot; alt=&quot;Humanizing among coders slide 28&quot; /&gt;
    &lt;p&gt;Along with explaining why, also explain how. If it&apos;s a simple task, make it sound simple. Don&apos;t obscure by using fancy words or shoveling in some elaborate concepts from computer science. It&apos;s just one line of text in a markdown file. And offer help, beginners need our help.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.029.jpeg&quot; alt=&quot;Humanizing among coders slide 29&quot; /&gt;
    &lt;p&gt;That was a lot, wasn&apos;t it?&lt;/p&gt;
    &lt;p&gt;To be exact that&apos;s 168 more words than the first draft. But we know it&apos;s not about the quantity of sentences, right? It&apos;s about their quality.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.030.jpeg&quot; alt=&quot;Humanizing among coders slide 30&quot; /&gt;
    &lt;p&gt;To achieve this level of understanding and empathy, it takes a lot of energy. It takes enormous amounts of energy and emotional struggle for the beginner to make the PR and it&apos;s equally energy draining for the mentor to keep up. And when both sides can see each other&apos;s perspective, beautiful things happen.&lt;/p&gt;
    &lt;p&gt;I&apos;ve set the focus on the mentor and their ability to be empathetic, because they have been beginners themselves and have a direct reference where to look, whereas beginners have rarely been mentors, hence lack that experience.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.031.jpeg&quot; alt=&quot;Humanizing among coders slide 31&quot; /&gt;
    &lt;p&gt;Don&apos;t forget to connect with your beginner self. Nobody is born knowing these things. We&apos;ve all written bad smelly code and we kept on writing that bad smelly code, because nobody told us that we suck and we should never do that. Or maybe someone told you so, but you were stubborn, and brave, and continued regardless. But not everybody is. So don&apos;t discourage people. &lt;strong&gt;We grow professionally with time. Offer this time to beginners.&lt;/strong&gt;&lt;/p&gt;
    &lt;p&gt;It&apos;s curious that almost every developer will tell you that when looking at their one year old code, they&apos;ll say &quot;That is horrible, what was I thinking back then?&quot;. We accept our flaws, we know we are not perfect. Let&apos;s accept the fact that others aren&apos;t either and let them make mistakes.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.032.jpeg&quot; alt=&quot;Humanizing among coders slide 32&quot; /&gt;
    &lt;p&gt;Mentorship is not just about that. There&apos;s a whole lot more...&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.033.jpeg&quot; alt=&quot;Humanizing among coders slide 33&quot; /&gt;
    &lt;p&gt;For me personally mentorship is an intersection of teaching, inspiring and guiding. It&apos;s hard work.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.034.jpeg&quot; alt=&quot;Humanizing among coders slide 34&quot; /&gt;
    &lt;p&gt;So open source...&lt;/p&gt;
    &lt;p&gt;I think beginners should have a safe playground to try things out without the pressure of perfectionism. Open source is often not the place, especially with a small, solitary, one maintainer, who probably also works full-time, projects. Lack of energy drives a lack of mentorship. Also consider most of us are not getting paid for it and even being shouted at by random people on the internet for not fixing a bug in time, because, you know, they need it.&lt;/p&gt;
    &lt;p&gt;What fascinates me is that there are projects that harvest the energy for mentorship. Often those will be big community, many contributors type of projects. These are the kind of projects that can afford to invest in good beginner documentation, that have people who can do so, who will often participate in Google CodeIn, Summer of Code camps and such. I want to say thank you :)&lt;/p&gt;
    &lt;p&gt;If you are a big community, but you prefer to neglect beginners, then you are losing some unique perspectives to improve your project and to self-evaluate.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.035.jpeg&quot; alt=&quot;Humanizing among coders slide 35&quot; /&gt;
    &lt;p&gt;Let&apos;s talk about legacy, also nicknamed &quot;code archeology&quot;.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.036.jpeg&quot; alt=&quot;Humanizing among coders slide 36&quot; /&gt;
    &lt;p&gt;This is Lela. Lela has been working on this legacy project for the past 2 months. The more she got into it, the more she realized how big it is. It&apos;s been developed in the company for the past 3 years and before that it belonged to another agency, having in total about 50 contributors.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.037.jpeg&quot; alt=&quot;Humanizing among coders slide 37&quot; /&gt;
    &lt;p&gt;Lela has a bug to fix and first thing she does she writes a failing test and then git bisects until she finds the hurting commit.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.038.jpeg&quot; alt=&quot;Humanizing among coders slide 38&quot; /&gt;
    &lt;p&gt;Aaaaand the commit&apos;s author is herself. It looks like this is another fix that she did when she joined the project.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.039.jpeg&quot; alt=&quot;Humanizing among coders slide 39&quot; /&gt;
    &lt;p&gt;Going back in time when she first tried to fix whatever she was fixing, we can see how she acted. It was a side fix, she saw something that looked like an awkward way of accomplishing what she thought it was supposed to accomplish.&lt;/p&gt;
    &lt;p&gt;So she &lt;code&gt;git blame&lt;/code&gt;d. Saw it was a person who already left the company, made a snarky comment to herself: &quot;Ha, is that proper Python? Must be the reason someone got fired.&quot; So she changed a couple of lines of code as a matter of fact. As we know, it backfired.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.040.jpeg&quot; alt=&quot;Humanizing among coders slide 40&quot; /&gt;
    &lt;p&gt;In an alternate universe, what could have happened?&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.041.jpeg&quot; alt=&quot;Humanizing among coders slide 41&quot; /&gt;
    &lt;p&gt;Lela finds the odd looking piece of code, does &lt;code&gt;git blame -s /path/to/file.py&lt;/code&gt;, because at this point it actually doesn&apos;t really matter who made the change. Finds the commit. Looks at the commit message and commit contents. She is gaining more context.&lt;/p&gt;
    &lt;p&gt;Seems like this bit of code was moved from somewhere else, so she does &lt;code&gt;git blame&lt;/code&gt; before that commit - goes deeper into the history.&lt;/p&gt;
    &lt;p&gt;Finds out a very nice explanation on why it looks the way it looks and what it&apos;s supposed to serve. She found the root!&lt;/p&gt;
    &lt;p&gt;Lila leaves a comment in the code, summarizing everything she learned and why this shouldn&apos;t be removed. Case closed.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.042.jpeg&quot; alt=&quot;Humanizing among coders slide 42&quot; /&gt;
    &lt;p&gt;Git blame is an excellent tool if used for things beyond just blaming people.&lt;/p&gt;
    &lt;p&gt;Some people have strong feelings about the choice of words - blame.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.043.jpeg&quot; alt=&quot;Humanizing among coders slide 43&quot; /&gt;
    &lt;p&gt;We have an alternative. We can create an alias to &lt;code&gt;git blame&lt;/code&gt;. Quoting from the original repo of this &lt;code&gt;git praise&lt;/code&gt; alias: &quot;Sometimes you find the most amazing piece of code and want to know who to thank for this wonderful contribution and then it feels wrong to use git blame.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.044.jpeg&quot; alt=&quot;Humanizing among coders slide 44&quot; /&gt;
    &lt;p&gt;But what if you personally rarely use &lt;code&gt;git blame&lt;/code&gt; to literally blame someone or &lt;code&gt;git praise&lt;/code&gt; to thank people (though that&apos;s definitely nice)?&lt;/p&gt;
    &lt;p&gt;Hence I came up with this alias - &lt;code&gt;git travel&lt;/code&gt;. Because for me it&apos;s all about going back in time and like an archaeologist figure out why things are the way they are. It&apos;s not about me and my judgment, it&apos;s about the history. Most probably nobody is playing dump, there is a reason for this bit to exist.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.045.jpeg&quot; alt=&quot;Humanizing among coders slide 45&quot; /&gt;
    &lt;p&gt;Context makes a very big difference and that&apos;s why it&apos;s worth spending time to understand project history. All code is legacy or will be some sort of legacy soon enough (you don&apos;t need decades for that), otherwise we wouldn&apos;t have big and complicated systems. So knowing your way around legacy is a skill we should develop.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.046.jpeg&quot; alt=&quot;Humanizing among coders slide 46&quot; /&gt;
    &lt;p&gt;Couple of years ago, while at university, I stumbled upon this article that discussed a very complex codebase of a system. And it&apos;s presented from the perspective of the new architect that decides to makes a big revamp of some core components. Why? Because they wanted to make it better.&lt;/p&gt;
    &lt;p&gt;After 3 years into the project, they realized that was not the way to go. And the main issue that was identified is the fact they didn&apos;t try to understand in-depth the reasons behind the initial design solutions to understand the basic problems that it tried to solve. We often see only the tip of the iceberg.&lt;/p&gt;
    &lt;p&gt;That doesn&apos;t mean we shouldn&apos;t improve our systems - refactor and improve our code! It just means &lt;strong&gt;we better be aware of the history before trying to write the future&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.047.jpeg&quot; alt=&quot;Humanizing among coders slide 47&quot; /&gt;
    &lt;p&gt;Interestingly enough while traveling into a project&apos;s past, you realise what a commit message should be and what it shouldn&apos;t be: it should explain why, not what (because I can read the code, I can see that the variable got renamed, I want to know why). And that suddenly makes you realise how terrible you are at writing commit message. You can correct yourself.&lt;/p&gt;
    &lt;p&gt;It&apos;s incredibly useful to tie commits to a ticket. That opens a new dimension to understanding the context.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.048.jpeg&quot; alt=&quot;Humanizing among coders slide 48&quot; /&gt;
    &lt;p&gt;Finally as a last resort, if no meaningful artifacts are found, check the author and if they are still around ping them and ask why.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.049.jpeg&quot; alt=&quot;Humanizing among coders slide 49&quot; /&gt;
    &lt;p&gt;This is my code travel guide. I hope you&apos;ll find it useful.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.050.jpeg&quot; alt=&quot;Humanizing among coders slide 50&quot; /&gt;
    &lt;p&gt;Having talked all about &lt;code&gt;git blame&lt;/code&gt;, made me think of another story.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.051.jpeg&quot; alt=&quot;Humanizing among coders slide 51&quot; /&gt;
    &lt;p&gt;Imagine a regular day at the office. Suddenly the reporting tool starts flashing red, everybody is getting notifications on every email, the alarm in the room goes off, there are lots of 500s happening on production. Panic-panic! Team gets together really fast, figures out what the problem is and hotfixes the issue on production. Everything is back to normal.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.052.jpeg&quot; alt=&quot;Humanizing among coders slide 52&quot; /&gt;
    &lt;p&gt;Now stage 2 begins: who&apos;s to blame and who should we punish?&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.053.jpeg&quot; alt=&quot;Humanizing among coders slide 53&quot; /&gt;
    &lt;p&gt;The team figured it was Miloš who made the commit that broke everything. (At this point the room burst into laughter and I am completely clueless why this is funny. Apparently this is an inside joke - Miloš is the first name of Czech Republic president and he is not a very popular figure.) Everybody starts pointing fingers. Miloš is not fired or removed from the project, but the management is giving him the looks. It&apos;s cringy. Ivona, his teammate, even said: &quot;I always thought Miloš is sloppy and something like that will happen eventually.&quot; Everybody settled with the root cause of the problem - Miloš, and now they can move on.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.054.jpeg&quot; alt=&quot;Humanizing among coders slide 54&quot; /&gt;
    &lt;p&gt;This tendency for people to place an undue emphasis on internal characteristics of Miloš (as being sloppy or inattentive), rather than the external factors, in explaining the situation is called the attribution effect. We want to find a simple answer to a complex problem.&lt;/p&gt;
    &lt;p&gt;Did we actually solve the problem? No, we didn&apos;t. Because anyone can be Miloš.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.055.jpeg&quot; alt=&quot;Humanizing among coders slide 55&quot; /&gt;
    &lt;p&gt;Therefore in an alternate universe.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.056.jpeg&quot; alt=&quot;Humanizing among coders slide 56&quot; /&gt;
    &lt;p&gt;After fixing the bug, the team gets together and has a different post-mortem. They ask questions: &quot;Why did it happen in the first place? How did it slip into production? How can we prevent these kind of problems in the future?&quot;. And they try to find solutions: &quot;Maybe we need better tests, or CI, or a different way of doing code reviews.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.057.jpeg&quot; alt=&quot;Humanizing among coders slide 57&quot; /&gt;
    &lt;p&gt;&lt;strong&gt;Don&apos;t find fault, find remedy.&lt;/strong&gt;&lt;/p&gt;
    &lt;p&gt;This could happen to anyone. We are humans, we make mistakes. That&apos;s why we make up rules and build tools to prevent us from making those mistakes.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.058.jpeg&quot; alt=&quot;Humanizing among coders slide 58&quot; /&gt;
    &lt;p&gt;That said, we should not keep people that are dragging the project down. Sometimes we have to say no to some people. How we decide who and why should be let go is a complicated matter and I believe every company has its own process for that.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.059.jpeg&quot; alt=&quot;Humanizing among coders slide 59&quot; /&gt;
    &lt;p&gt;Our next story is about passive aggressive interactions.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.060.jpeg&quot; alt=&quot;Humanizing among coders slide 60&quot; /&gt;
    &lt;p&gt;This is Özlem. She joined a new team. How exciting!&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.061.jpeg&quot; alt=&quot;Humanizing among coders slide 61&quot; /&gt;
    &lt;p&gt;And this is Mărioara. She&apos;s been in the team for the past 2 years - proper old-time team player.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.062.jpeg&quot; alt=&quot;Humanizing among coders slide 62&quot; /&gt;
    &lt;p&gt;Özlem is excited to get started. She picks up her first ticket, investigates, writes the code, writes the tests - all good. Puts it in code complete.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.063.jpeg&quot; alt=&quot;Humanizing among coders slide 63&quot; /&gt;
    &lt;p&gt;Mărioara picks it up for a review. She changes some implementation details splitting some functions and rewriting a method. She then proceeds to merge that code and set it as done.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.064.jpeg&quot; alt=&quot;Humanizing among coders slide 64&quot; /&gt;
    &lt;p&gt;Özlem looks at the changes made, feels a bit awkward to ask questions, so she lets it go. She thinks to herself: &quot;I should probably be more attentive next time.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.065.jpeg&quot; alt=&quot;Humanizing among coders slide 65&quot; /&gt;
    &lt;p&gt;In a few weeks time Mărioara again picks up one of the Özlem&apos;s tickets for review and again moves things around, rewrites variable names, etc. Again no real comments from her. That happens again and again. Özlem remains silent to her growing frustration.&lt;/p&gt;
    &lt;p&gt;Now let&apos;s see the perspectives of both parties involved.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.066.jpeg&quot; alt=&quot;Humanizing among coders slide 66&quot; /&gt;
    &lt;p&gt;Özlem feels like she isn&apos;t even contributing to the project. She can&apos;t take ownership of anything on the project, because some bits of her work are being rewritten all the time. She never gets any real feedback on what was wrong and why this different solution is better. She didn&apos;t want to speak up, since she was new to the team. Didn&apos;t want to be the trouble-maker.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.067.jpeg&quot; alt=&quot;Humanizing among coders slide 67&quot; /&gt;
    &lt;p&gt;Mărioara does a code review and sees some parts that could be improved, not that the original solution was wrong. She has this itch of just making things perfect. She think it&apos;s just faster (hence more beneficial to the project) to fix those things herself, rather than leaving long comments and explaining her vision. She never considered that the author of the ticket is offended or feels alienated.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.068.jpeg&quot; alt=&quot;Humanizing among coders slide 68&quot; /&gt;
    &lt;p&gt;In an alternate universe.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.069.jpeg&quot; alt=&quot;Humanizing among coders slide 69&quot; /&gt;
    &lt;p&gt;Mărioara reviews the ticket and sees a main point that could be improved. She goes to Özlem and says: &quot;Hey, I was reviewing this ticket and I think it&apos;s a bad idea to store that value in the database, since once it expires, it&apos;s no use to us. Do you think we might change that and store that value as a class attribute?&quot;&lt;/p&gt;
    &lt;p&gt;&quot;That&apos;s a good point. But the problem here is that we instantiate that class in two other places. So we will have to fetch that value twice, which is expensive.&quot;, says Özlem.&lt;/p&gt;
    &lt;p&gt;&quot;Right.&quot;&lt;/p&gt;
    &lt;p&gt;Özlem goes again: &quot;We could store it in memcache.&quot;&lt;/p&gt;
    &lt;p&gt;&quot;Good idea!&quot;, says Mărioara. &quot;Wanna grab the ticket again or do you want me to do it?&quot;&lt;/p&gt;
    &lt;p&gt;&quot;I&apos;m free now, so I&apos;ll gladly amend the feature.&quot;&lt;/p&gt;
    &lt;p&gt;&quot;Nice. Ping me after you&apos;re done if you need a review.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.070.jpeg&quot; alt=&quot;Humanizing among coders slide 70&quot; /&gt;
    &lt;p&gt;Özlem and Mărioara manage to truly collaborate and come up with a better solution than either of them had in mind. Also both feel included. It&apos;s so easy to say: &quot;Hey, I have this concern.&quot; It&apos;s also about offering a choice.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.071.jpeg&quot; alt=&quot;Humanizing among coders slide 71&quot; /&gt;
    &lt;p&gt;At this point it doesn&apos;t matter who will finish the ticket, because they have an agreement and both are looking into the same direction. &lt;strong&gt;That way spirit of collaboration and trust can flourish in a team.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.072.jpeg&quot; alt=&quot;Humanizing among coders slide 72&quot; /&gt;
    &lt;p&gt;Here we are at our final story - the power of we. We as in we together, not the royalty.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.073.jpeg&quot; alt=&quot;Humanizing among coders slide 73&quot; /&gt;
    &lt;p&gt;This is Haru and Vlad. They work together.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.074.jpeg&quot; alt=&quot;Humanizing among coders slide 74&quot; /&gt;
    &lt;p&gt;Haru and Vlad are estimating a new feature. On a specific line in the estimate Haru says: &quot;Max wrote this parser a while ago. I wouldn&apos;t use it for this feature, because it&apos;s meant to handle only very small sets of data. Plus I constantly find bugs in it. You could rewrite it Vlad.&quot;&lt;/p&gt;
    &lt;p&gt;&quot;Alright, I&apos;ll make sure I also use the new conventions that Amira introduced recently.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.075.jpeg&quot; alt=&quot;Humanizing among coders slide 75&quot; /&gt;
    &lt;p&gt;In an alternate universe. You probably see where I&apos;m going with this...&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.076.jpeg&quot; alt=&quot;Humanizing among coders slide 76&quot; /&gt;
    &lt;p&gt;I made an itty-bitty correction. Replace all the pronouns with &quot;we&quot;.&lt;/p&gt;
    &lt;p&gt;&quot;We wrote this parser a while ago. We shouldn&apos;t use it for this feature, because it&apos;s meant to handle only very small sets of data. Plus we constantly find bugs in it. We could rewrite it now. What do you think Vlad?&quot;&lt;/p&gt;
    &lt;p&gt;&quot;Sound good, we need to make sure we use the new conventions that we&apos;ve introduced recently.&quot;&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.077.jpeg&quot; alt=&quot;Humanizing among coders slide 77&quot; /&gt;
    &lt;p&gt;&quot;We&quot; gives a strong feeling of togetherness.&lt;/p&gt;
    &lt;p&gt;This is such a trivial change. But the tone changes straight away. It&apos;s a big shift in our heads of how we think about our work and what a team is. &lt;strong&gt;We are together in failure and success.&lt;/strong&gt;&lt;/p&gt;
    &lt;p&gt;The I vs he/she/they idea extends to communities build around tools, libraries, programming languages. I - part of Python community versus them - from Java/PHP/Go/whatever community. I&apos;d be very glad if we could change the versus to together. And let&apos;s not tolerate belittling of others.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.078.jpeg&quot; alt=&quot;Humanizing among coders slide 78&quot; /&gt;
    &lt;p&gt;I&apos;ve made all of those mistakes and more. But I believe it&apos;s possible to change and I&apos;d like to encourage people around me to change for the better as well.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.079.jpeg&quot; alt=&quot;Humanizing among coders slide 70&quot; /&gt;
    &lt;p&gt;Influence and changes to the norm of interacting in a team or open source community can be nourished in different ways. One possibility is to have it imposed by a general rule coming from higher up management. But I find that true long-lasting shatterproof rules of interactions come unwritten kicked off by individuals themselves in their everyday social encounters with other people.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.080.gif&quot; alt=&quot;Humanizing among coders slide 80&quot; /&gt;
    &lt;p&gt;Things tend to accumulate and little by little good things and healthy interactions will overflow into something good - like a pleasurable place to work.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.081.jpeg&quot; alt=&quot;Humanizing among coders slide 81&quot; /&gt;
    &lt;p&gt;All these little stories are just a fraction of what we experience every day on a social level. These stories won&apos;t give answers to many situations that we find ourselves in.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.082.jpeg&quot; alt=&quot;Humanizing among coders slide 82&quot; /&gt;
    &lt;p&gt;That&apos;s why you should let empathy and compassion be your guide.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.083.jpeg&quot; alt=&quot;Humanizing among coders slide 83&quot; /&gt;
    &lt;p&gt;Not only in your professional life, but also when you&apos;re driving, getting tomatoes at your local corner shop, visiting family for holidays or ordering pizza.&lt;/p&gt;
&lt;/div&gt;

&lt;hr class=&quot;section-delimiter&quot; /&gt;

&lt;div class=&quot;slide-section&quot;&gt;
    &lt;img src=&quot;/assets/img/humanizing/humanizing.084.jpeg&quot; alt=&quot;Humanizing among coders slide 84&quot; /&gt;
    &lt;p&gt;Thanks! Děkuji! Mulțumesc!&lt;/p&gt;
&lt;/div&gt;
</summary>
      <id>http://ana-balica.github.io/2017/05/28/humanizing-among-coders/</id>
      <updated>2017-05-28T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Code review checklist</title>
      <link href="http://ana-balica.github.io/2017/02/21/code-review-checklist/" />
      <summary type="html">&lt;p&gt;Writing code is hard, reviewing it, is equally hard. In my team every ticket is scanned by a second pair of eyes.&lt;/p&gt;

&lt;p&gt;Why? Half-assed work can make a company look bad, lose money, lose clients, generate stress and extra work, thus a good code review is a must before going live.&lt;/p&gt;

&lt;p&gt;Over the last couple of months, I’ve developed my own internal code review checklist. I use it both for reviewing for own finished code and my teammates code complete tickets. It’s split up into 3 sections: code, automated testing and manual testing.&lt;/p&gt;

&lt;h2 id=&quot;code&quot;&gt;Code&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Does it compile?&lt;/strong&gt; Look for obvious errors, most IDEs will spot them for you. Baffling that these kind of issues slip into code completes, but we are all humans and mistakes happen. Most common reasons: last minute untested change that surely won’t break anything or forgot to push the fix.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Can you spot any runtime errors&lt;/strong&gt; just by looking at code? Try to reproduce the exception.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is the feature/bugfix complete?&lt;/strong&gt; Does it tick off all the requirements? Is there anything missing or misbehaving?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is this a good solution?&lt;/strong&gt; Is this the best solution out of all those that have been considered? This is mostly related to system design and general approach to problem solving. The definition of good and best is context dependent.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Does it introduce any security holes?&lt;/strong&gt; Definitely not something to be disregarded.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is the code efficient&lt;/strong&gt; in whatever metrics matter for your case?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is it logically correct?&lt;/strong&gt; Does it solve the problem? This is usually central to the code review, hence obvious, but I don’t want to skip obvious steps.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;How does it affect the rest of the system?&lt;/strong&gt; We review code diffs with no or minimum context regarding the rest of the codebase. With diffs you can only see that much, thus how about start looking in other places? Think about all the other components that might depend on this change. Where any of the APIs violated?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is it within the scope?&lt;/strong&gt; Does the ticket touch any unrelated parts of the codebase or does side fixes? The more it gets cluttered, the more complicated it becomes to review, test and release. Stay on topic.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Are there any code style issues?&lt;/strong&gt; Conventions &lt;em&gt;are&lt;/em&gt; important for the sake of codebase sanity. I know we all have strong opinions about all the things, but for your team and code well-being, please disagree and commit.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is the code readable?&lt;/strong&gt; Can someone else understand it? How long did it take you to figure it out? Do all namings make sense?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Does it have good and enough documentation?&lt;/strong&gt; Not to be ignored or considered of least importance.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;automated-testing&quot;&gt;Automated testing&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Does it need tests?&lt;/strong&gt; Sometimes a favicon update will do just fine without tests.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Does it have tests?&lt;/strong&gt; Seriously, write tests.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Are tests logically correct?&lt;/strong&gt; Tests can have bugs too. Review tests thoroughly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Are tests simple, easy to read and debug?&lt;/strong&gt; Forget about DRY, don’t build a whole infrastructure to test your code (unless you are writing an isolated testing framework with a clear API that everyone else on the team is more or less familiar with), KISS (keep it simple, stupid). If something fails, it should be apparent what broke.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Are tests testing the right thing?&lt;/strong&gt; Tests are not a checkbox to be ticked off, they are your safety net. Just the existence of tests or higher test coverage doesn’t guarantee a bug-free life. Make sure to get a good insurance with a solid testbase.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Are tests testing the edge cases?&lt;/strong&gt; Best case scenarios suck!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;manual-testing&quot;&gt;Manual testing&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Can you run the code?&lt;/strong&gt; Don’t skip that. Automated tests look good on paper (ehhhm, computer screen?), but running the project is still a good idea. Automated tests reduce manual testing to the minimum, but don’t exclude it completely.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Can you follow through several test scenarios?&lt;/strong&gt; Pick obvious and non-obvious ones: do they succeed?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Is the rest of the system looking/working fine?&lt;/strong&gt; Links to &lt;em&gt;How does it affect the rest of the system?&lt;/em&gt; from Code section. Similar, but more straight-forward. Have a click-around and make sure things are fine.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Can you break it?&lt;/strong&gt; Try to think of ways it might fail: feed it large sets of data, consider third-party systems downtime and how it can affect you, use an unusual email address (&lt;a href=&quot;https://tools.ietf.org/html/rfc2822#page-47&quot;&gt;did you know email address can have comments in-between tokens?&lt;/a&gt;). Don’t worry, your users will still find ways to break it for you.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;Feel free to suggest more checkpoints :)&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2017/02/21/code-review-checklist/</id>
      <updated>2017-02-21T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Keynote animations: express yourself</title>
      <link href="http://ana-balica.github.io/2016/12/15/keynote-animations/" />
      <summary type="html">&lt;p&gt;Keynote might not be the best tool to create animations,
but it’s good enough and provides most common animation tools.
Moreover you don’t really want to open After Effects and export a movie
just to make an object wiggle a bit during your presentation.
It’s also an interesting challenge to create something complex
out of something trivial.
Constraints foster creativity.&lt;/p&gt;

&lt;h2 id=&quot;meaning&quot;&gt;Meaning&lt;/h2&gt;

&lt;p&gt;The main goal of an animation is to convey meaning.
Think of it as another dimension to express an idea.
Try to remove the animation and see if you can communicate
the same message equally well.
If you loose clarity, then this is a meaningful animation.&lt;/p&gt;

&lt;video autoplay=&quot;&quot; loop=&quot;&quot;&gt;
  &lt;source src=&quot;/assets/video/keynote/potato.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;In this case, the animation is used to convey playfulness.
“Potato is a serious company, but we also like to be silly.”&lt;/p&gt;

&lt;h2 id=&quot;dont-overdo-it&quot;&gt;Don’t overdo it&lt;/h2&gt;

&lt;p&gt;In conjunction with the previous statement, don’t fill up your presentation
with useless animations.
When things move, spin, burn too often, it’s hard to follow along
and justify any of this live action on the screen.&lt;/p&gt;

&lt;p&gt;On a more practical note, certain types of animations might even make some people dizzy -
I’m looking at you &lt;a href=&quot;https://prezi.com/_ueivw8ad8xx/prezi-demo/&quot;&gt;Prezi&lt;/a&gt;.&lt;/p&gt;

&lt;video autoplay=&quot;&quot; loop=&quot;&quot;&gt;
  &lt;source src=&quot;/assets/video/keynote/tacky.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;Oh you, flame effect, I will never use you, unless I’m going for on-purpose tacky style.&lt;/p&gt;

&lt;h2 id=&quot;baby-steps&quot;&gt;Baby steps&lt;/h2&gt;

&lt;p&gt;So how to make the first slide with the smiling Potato?
First solution: use 2 slides, one with a plain Potato
and another with a Potato with a big smile on it.
Better solution: apply an animation called “Appear”,
found in the “Build In” tab of the Animate section.
Click/tap and, voila, the image appears!&lt;/p&gt;

&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/W3naF-73Olw&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&quot;bullet-points&quot;&gt;Bullet points&lt;/h2&gt;

&lt;p&gt;They are haunting us in every presentation! They are useful though, as they reduce
long complex sentences to a few important key points.
And if you want to make them appear in a special way, say one by one,
Keynote has got your back.&lt;/p&gt;

&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/vD5s2_5qVf8&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Don’t even think making 5 separate slides and placing on each plus-one bullet point.
This easily gets out of sync when you decide to add or remove a bullet point
and now you have to edit not one slide, but 5 (worst-case scenario).&lt;/p&gt;

&lt;p&gt;These is an exception to the rule though.
If the speaker notes for the first 2 points are already too big
and in presentation mode you need to scroll to get to the last sentence,
then it’s a good idea to split up the notes into a couple of slides
and hence duplicate the content. &lt;em&gt;I should start doing that&lt;/em&gt; ʕ⊙ᴥ⊙ʔ&lt;/p&gt;

&lt;h2 id=&quot;center-of-attention-highlighting&quot;&gt;Center of attention: highlighting&lt;/h2&gt;

&lt;p&gt;As you speak you might want to direct the attention of your audience
to a specific line of code, element or word.
This is a neat trick, because it allows the viewers to grasp the general picture at first
and then dive deep into certain segments.
There are many ways to do that.
In case of code I like to use highlighting.&lt;/p&gt;

&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/8KwH_ZmM6Co&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Create a shape and give it enough opacity to make the text underneath eligible.
Then apply an appropriate “Build In” animation to the shape -
I like “Move In” with a little bit of bounce.
It’s hard to ignore such an animation, and at the same time it doesn’t make me cringe
(like “Bouncy”).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; assess animation duration.
The animation should be fast and noticeable.
In most cases 1s is too long.
Experiment with 0.5 - 1s range and see what feels best to your presentation pace.&lt;/p&gt;

&lt;h2 id=&quot;center-of-attention-opacity&quot;&gt;Center of attention: opacity&lt;/h2&gt;

&lt;p&gt;Similarly to highlighting, you can use opacity to make something stand out
in the midst of blurred/semi-transparent content.
I remember seeing the trick for the first time at DjangoCon Europe 2015 in Cardiff
in Ola’s talk &lt;a href=&quot;https://vimeo.com/channels/952478/134817269&quot;&gt;Pushing the pony’s boundaries&lt;/a&gt;
and I really liked it.&lt;/p&gt;

&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/fXgcwCpiBQI&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;“Opacity” animation can be found under the “Action” tab.
Since I prefer to almost omit the transition of going transparent,
I set the duration to 0.1s.&lt;/p&gt;

&lt;p&gt;An important take-away from this short video is the “Build Order” dialog.
This is the control panel of all animations, where they can be deleted,
grouped and rearranged.&lt;/p&gt;

&lt;p&gt;By the way, alternatively to copy-pasting animations, it’s also possible to group elements together
and apply a single animation.
Unfortunately for the current 3 elements when grouped, the animation doesn’t apply well.
Would be fun to aggregate and post all Keynote bugs I’ve discovered while preparing for my talks.&lt;/p&gt;

&lt;h2 id=&quot;multi-actions&quot;&gt;Multi-actions&lt;/h2&gt;

&lt;p&gt;Things get complicated when you want something to go opaque, then transparent,
then opaque again.
In other words, apply multi-actions to the same element.
It’s somewhat simple - click “Add Action”, select another animation and configure it.
My problem with that is the UI that is showing only the last applied action.
To be able to go to older layers of animation, you need to open “Build Order”
and operate from there (that was so not obvious at the beginning).&lt;/p&gt;

&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/-CFr_VluCjg&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&quot;a-process&quot;&gt;A process&lt;/h2&gt;

&lt;p&gt;A single animation is worth a thousand words when modeling a process.
It’s like when they spend 5 pages to explain how an engine works,
and you still don’t get it.
But once you see the animation, it suddenly becomes clear.&lt;/p&gt;

&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/EQzfc7OnuMY&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Here I explain visually how tests are run in parallel, simplified version taken from my
&lt;a href=&quot;https://www.youtube.com/watch?v=EHyKzPQFXzo&quot;&gt;Testing in Django&lt;/a&gt;
talk at Django Under The Hood 2016.
This is a showcase of what is possible and how it can be achieved using
Keynote animation toolkit.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Now you are ready to unleash your creative freedom and deliver
jaw-dropping presentations. &lt;em&gt;No flames please.&lt;/em&gt;&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2016/12/15/keynote-animations/</id>
      <updated>2016-12-15T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Intricacies and optimization of Datastore indexes</title>
      <link href="http://ana-balica.github.io/2016/11/28/intricacies-and-optimization-of-datastore-indexes/" />
      <summary type="html">&lt;p&gt;It’s nice that development server is so kind to generate Datastore indexes for us, unfortunately those aren’t always optimal and might require some tweaking from our side. Hence it’s important to be knowledgeable on intricacies of index creation.&lt;/p&gt;

&lt;p&gt;This is a follow up post to &lt;a href=&quot;/2016/11/20/datastore-indexes-basics/&quot;&gt;Datastore indexes basics&lt;/a&gt; that covers essentials, mentions the dependencies used and contains some base models that we will be using here.&lt;/p&gt;

&lt;h2 id=&quot;speed-considerations&quot;&gt;Speed considerations&lt;/h2&gt;

&lt;p&gt;The reason why we want to optimize indexes is speed. Simply put the more simple and composite indexes an entity has, the slower it becomes to do writes. That’s why Datastore imposes limits on the number and size of index entries (&lt;a href=&quot;https://cloud.google.com/datastore/docs/concepts/limits&quot;&gt;200 composite indexes and 2 Mib maximum sum of the size of an entity’s composite index entries&lt;/a&gt;). It is possible by having a large number of properties on an entity/model or having a huge amount of composite indexes in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.yaml&lt;/code&gt; to exceed those limits though.&lt;/p&gt;

&lt;h2 id=&quot;when-order-matters&quot;&gt;When order matters&lt;/h2&gt;

&lt;p&gt;Order in the &lt;strong&gt;WHERE&lt;/strong&gt; clause &lt;em&gt;doesn’t&lt;/em&gt; matter. If you have multiple equality filters on different properties, then those 2 indexes are equivalent and one of them can be safely discarded. Going back to our example with a Book model. If we execute this query:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Mark Twain&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Some title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;-published_date&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Development server will create this index:&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;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;author&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;published_date&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;desc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It can serve this query as well (we have swapped in place author and title properties):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Some title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Mark Twain&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;-published_date&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is possible to confuse automatic index creation and make it also create this index:&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;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;author&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;published_date&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;desc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then it’s our duty to spot indexes alike and remove duplicates.&lt;/p&gt;

&lt;p&gt;In general Datastore will try to create and insert indexes in alphabetical order with properties inside of an index ordered like that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Properties used in equality filters&lt;/li&gt;
  &lt;li&gt;Property used in an inequality filter (there can be only one)&lt;/li&gt;
  &lt;li&gt;Properties used in sort order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, the &lt;strong&gt;direction&lt;/strong&gt; of a property &lt;em&gt;makes&lt;/em&gt; a difference, hence &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order_by(&apos;published_date&apos;)&lt;/code&gt; is not the same as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;order_by(&apos;-published_date&apos;)&lt;/code&gt; and 2 indexes should be created respectively.&lt;/p&gt;

&lt;h2 id=&quot;minimum-vs-perfect&quot;&gt;Minimum vs perfect&lt;/h2&gt;

&lt;p&gt;The index that we created above is a perfect index - the whole query is served by a single index. This allows the most efficient and fast querying. In contrast we could split the perfect index into 2 minimum indexes:&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;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;author&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;published_date&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;desc&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;published_date&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;desc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These 2 indexes now serve 3 different complex queries:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Mark Twain&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;-published_date&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Some title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;-published_date&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Mark Twain&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Some title&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;-published_date&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To serve the last query, Datastore uses &lt;a href=&quot;http://www.youtube.com/watch?v=ofhEyDBpngM&quot;&gt;zigzag merge join algorithm&lt;/a&gt;. To be able to merge those 2 indexes to obtain results for the last query, both indexes have to be ordered the same way.&lt;/p&gt;

&lt;p&gt;It might not seem like a major winning strategy. In our case we have reduced 3 indexes to 2 - not a big deal. But consider a different example where we add more properties to the Book model and we create an interface where librarians can choose by which properties to filter and to sort. If we try to predict every single combination and create perfect indexes for each, we will obtain fast querying, nevertheless we might easily reach the index cap and the operation of creating or updating books will become slower.&lt;/p&gt;

&lt;p&gt;Consider we have 6 properties for filtering and we allow ordering by 4 properties. That’ll result in 256 perfect indexes (whoops, we’ve reached the index cap). It’s computed the following way:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;2^(number of filters) * (number of different orders)
2^6 * 4 = 256&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this case we should resort to creating minimum indexes or a combination of minimum and perfect indexes. The absolute minimum to serve all the possible queries in this case is 24 indexes (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6 * 4&lt;/code&gt;). This might not be the optimal solution though, some queries might be executed more often than others, so maybe it makes sense to add another 3-4 perfect indexes to serve most common use cases.&lt;/p&gt;

&lt;p&gt;Besides when resorting to minimum indexes, we should be aware of the shape of the data. Merging using the zigzag merge join algorithm comes with a cost. Poor performance is achieved when many entities match each scan in separation, but few entities match the query as a whole. App Engine has an excellent explanation on that in &lt;a href=&quot;https://cloud.google.com/appengine/articles/indexselection&quot;&gt;Datastore Index Selection &amp;amp; Advanced Search&lt;/a&gt; article.&lt;/p&gt;

&lt;h2 id=&quot;exploding-indexes&quot;&gt;Exploding indexes&lt;/h2&gt;

&lt;p&gt;Iterable fields complicate things. Normally each row in the index table represents one entity in Datastore. Take this index &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Index(Book, author, title, -published_date)&lt;/code&gt;. If we have 10 books with those properties set, then Datastore will create 10 rows in the index table.&lt;/p&gt;

&lt;p&gt;If we add another indexable property to Book &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keywords = ListField(CharField)&lt;/code&gt;, then the number of rows becomes the number of unique values in the ListProperty. Datastore will create an entry for each combination of property values.&lt;/p&gt;

&lt;p&gt;Now if we use multiple multi-valued properties, then the number of entries for each entity can “explode” combinatorially. Even though it’s a single index, such an index can dramatically increase the cost of writing an entity to Datastore.&lt;/p&gt;

&lt;p&gt;Let’s amend our Book model:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&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;n&quot;&gt;keywords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SetField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ratings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ListField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DecimalField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And create another index:&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;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;keywords&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ratings&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With the following new instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;My sci-fi book&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;keywords&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;sci-fi&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;dystopia&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;post-modern&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ratings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;4.9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;4.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;4.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Datastore will create 15 entries (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|keywords| * |ratings| * |title|&lt;/code&gt;) for this index. The larger the number of items in an iterable property, the more rows will be created in the index table. This is what is called &lt;em&gt;exploding indexes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To ameliorate such a hungry index, we can split it up into 2 indexes (same zigzag merge join algorithm applied in case of a query that filters and sorts on those 3 properties):&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;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;keywords&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ratings&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For this example Datastore will create 8 entries (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|keywords| * |title| + |ratings| * |title|&lt;/code&gt;) in contrast with 15 entries in the index table. Don’t forget to vacuum clean indexes, once you update them.&lt;/p&gt;

&lt;p&gt;Unexploding indexes might not always be a necessity, since (again) it all depends on the shape of your data. You might be fine with a single index that contains 2 iterable properties if one of those is a property that always has only one value. Maybe it was created with a thought about distant future, where more options can be added without the need to migrate all the data.&lt;/p&gt;

&lt;h2 id=&quot;dead-indexes&quot;&gt;Dead indexes&lt;/h2&gt;

&lt;p&gt;Large projects with a lot of models might suffer from dead-index weight. Adding indexes is easy, removing them - not so much. You never know if there’s a hidden query somewhere that your search through the codebase didn’t spot. So maybe we should just keep that index? Nope.&lt;/p&gt;

&lt;p&gt;There are different scenarios when we can and should identify dead indexes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Removing a query. That query might have required an index in the past. We can delete it, but we also need to check the rest of the code if nobody else is using this index. It can be also be a minimum index used in a mix with other indexes to serve a complex query.&lt;/li&gt;
  &lt;li&gt;Changing Django Meta class ordering. This kind of change will have repercussions all over the code and most probably all the indexes will have to be updated. Big changes ahead!&lt;/li&gt;
  &lt;li&gt;Scanning for duplicate indexes, whether it’s obvious duplicates with properties in different orders or hidden duplicates with equivalent indexes just in a different form (think minimum vs perfect).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Either way we need to practice mindfulness to keep our indexes optimal and at a minimum.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2016/11/28/intricacies-and-optimization-of-datastore-indexes/</id>
      <updated>2016-11-28T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Datastore indexes basics</title>
      <link href="http://ana-balica.github.io/2016/11/20/datastore-indexes-basics/" />
      <summary type="html">&lt;p&gt;If you’ve been developing apps to host on Google App Engine (GAE) and use Google Cloud Datastore database (further referred to simply as Datastore), then you are probably aware of indexes. Simply put, indexes are what makes reads faster with the caveat of slower writes.&lt;/p&gt;

&lt;h2 id=&quot;timestamped&quot;&gt;Timestamped&lt;/h2&gt;

&lt;p&gt;This is a section that I want to include more often to ground any of my explanations into a specific time-dependencies frame.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;App Engine Python SDK 1.9.40 - 2016-07-15 (examples are in Python, though the concepts are language agnostic and applicable to other GAE environments)&lt;/li&gt;
  &lt;li&gt;Python 2.7 (because App Engine Python SDK doesn’t support Python3, &lt;a href=&quot;https://code.google.com/p/googleappengine/issues/detail?id=909&quot;&gt;the issue about that has been open since 2008&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/potatolondon/djangae/releases/tag/v0.9.6&quot;&gt;Djangae v0.9.6&lt;/a&gt; because it’s the easiest way to run Django on GAE and I’ll be using Django’s ORM integration with Datastore instead of &lt;a href=&quot;https://cloud.google.com/appengine/docs/python/ndb/&quot;&gt;ndb&lt;/a&gt; (still same concepts apply regardless of who makes the query)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;simple-indexes&quot;&gt;Simple indexes&lt;/h2&gt;

&lt;p&gt;Say we have the following Django model:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;published_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;App Engine will define a single index on each property of an entity (model in this case), except for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextProperty&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlobProperty&lt;/code&gt;. Each index has a direction, by default ascending. In our case it means entity Book will have 4 simple ascending indexes (3 explicit properties and implicit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pk&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;What can we do with only 4 indexes? Well, lots of things: fetch all the books, query books using only equality filters or only inequality filters, sort only by a single property with no additional filters. App Engine docs contain the &lt;a href=&quot;https://cloud.google.com/appengine/docs/python/datastore/indexes#Python_Index_configuration&quot;&gt;full list of allowed queries for automatically predefined indexes&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;composite-indexes&quot;&gt;Composite indexes&lt;/h2&gt;

&lt;p&gt;What if we want make a more sophisticated query:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Mark Twain&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;-published_date&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this case Datastore can’t return a result based on the simple indexes. It requires a composite index. All composite indexes go in an index configuration file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.yaml&lt;/code&gt;. When uploaded to production server, App Engine will parse this file and create all the indexes based on this configuration. Already existent indexes will not be recreated.&lt;/p&gt;

&lt;h2 id=&quot;generating-composite-indexes&quot;&gt;Generating composite indexes&lt;/h2&gt;

&lt;p&gt;We wrote a complex query. So far App Engine doesn’t know about it. &lt;strong&gt;For the system to be able to recognize a new composite index, we should execute the query on the development server.&lt;/strong&gt; This will trigger an automatic write to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.yaml&lt;/code&gt; of the perfect index in the section bellow this line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;# AUTOGENERATED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To be noted: &lt;strong&gt;indexes will be not created while running Django tests&lt;/strong&gt;, because Django test framework will not run the server during tests (it interacts directly with the WSGI interface to produce requests and responses, so dev appserver is not involved).&lt;/p&gt;

&lt;p&gt;Furthermore indexes can be manipulated manually, by listing them above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;# AUTOGENERATED&lt;/code&gt; line in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.yaml&lt;/code&gt;. We have the power to decide what’s the best index to serve our query.&lt;/p&gt;

&lt;h2 id=&quot;require-indexes&quot;&gt;Require indexes&lt;/h2&gt;

&lt;p&gt;If we want to be aware of what indexes are getting created, rather then letting the dev appserver do its automatic index creation, we can configure our dev environment to throw &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NeedIndexError&lt;/code&gt; exceptions when it’s missing an index. If running the server using the App Engine command, then we can do:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;dev_appserver.py &lt;span class=&quot;nt&quot;&gt;--require_indexes&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If using Django’s/Djangae’s management command to run the server, then there’s no easy to do that.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;./manage.py runserver &lt;span class=&quot;nt&quot;&gt;--require_indexes&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# won&apos;t work :(&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That won’t work because Djangae isn’t passing command line args to the dev appserver args parser and &lt;a href=&quot;https://github.com/potatolondon/djangae/pull/688&quot;&gt;there’s an open issue about it&lt;/a&gt; (if by the time you are reading this, this issue is closed and has a merged patch, then you might be lucky and that command works).&lt;/p&gt;

&lt;p&gt;Hacky workaround to just make it work: go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;google/appengine/tools/devappserver2/devappserver2.py&lt;/code&gt; and replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datastore_require_indexes=options.require_indexes&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datastore_require_indexes=True&lt;/code&gt; inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DevelopmentServer._create_api_server&lt;/code&gt;. Sorry, I just grepped (actually &lt;a href=&quot;https://github.com/ggreer/the_silver_searcher&quot;&gt;ag&lt;/a&gt;ed) inside Python SDK and picked up the first convenient place to force this setting. Maybe there’s a better way ¯\_(ツ)_/¯&lt;/p&gt;

&lt;p&gt;Therefore now if we want to run this query on dev server, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Book.objects.filter(author=&apos;Mark Twain&apos;).order_by(&apos;-published_date&apos;)&lt;/code&gt;, we will get a pretty error saying:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/datastore-indexes-basics/needindexerror.png&quot; alt=&quot;Appstats Console&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If this index fits us well, we can copy it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.yaml&lt;/code&gt;. Most important we are aware what index got created and what
query triggered it.&lt;/p&gt;

&lt;h2 id=&quot;cleaning-indexes&quot;&gt;Cleaning indexes&lt;/h2&gt;

&lt;p&gt;Consider that we have pushed this index file to your production server.&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;na&quot;&gt;indexes&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;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;author&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;published_date&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;desc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After a month or so we get a notice that librarians are not using this feature, so they ask us to remove it. Instead they want to be able to filter by author and sort by book titles in alphabetical order. This request yields another index. Since the old query has been removed, we remove the old index as well and hence end up with this index conf:&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;na&quot;&gt;indexes&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;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;library_book&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&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;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;author&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;title&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once pushed to production, App Engine will build the new index, but &lt;strong&gt;will also keep the old indexes, ignoring the fact that we’ve updated the configuration file&lt;/strong&gt;. This is intentional, since other versions of your app might still be using this index, so we have to be explicit.&lt;/p&gt;

&lt;p&gt;Once we’re sure we don’t need any of the removed indexes, let’s run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appcfg.py vacuum_indexes&lt;/code&gt;. We should be careful what we &lt;a href=&quot;(https://cloud.google.com/appengine/docs/python/tools/appcfg-arguments#vacuum_indexes)&quot;&gt;vacuum clean&lt;/a&gt;, since a missing index will result in a 500 for our users.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;There is a lot more to say about indexes and various intricacies related to them. Now that you know the basics, we can delve into more details in my next post &lt;a href=&quot;/2016/11/28/intricacies-and-optimization-of-datastore-indexes/&quot;&gt;Intricacies and optimization of Datastore indexes&lt;/a&gt;.&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2016/11/20/datastore-indexes-basics/</id>
      <updated>2016-11-20T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>A present for you, and you, and you</title>
      <link href="http://ana-balica.github.io/2016/07/23/a-present-for-you/" />
      <summary type="html">&lt;p&gt;Not here to try to sell you best Darth Vader mugs, perfect gift for your loved ones - only $9.99! Or am I? Haha! NO. I’ll be sharing how I’m responsibly prepping for my family and friends special occasions (think mostly birthdays).&lt;/p&gt;

&lt;p&gt;Yes, often I’ll resort to a typical birthday gift, that doesn’t require any of my time or brainpower. I console myself there’s nothing bad in gifting a birthday card, a nice body cream, a funny T-shirt, a kick scooter, a kite, right?&lt;/p&gt;

&lt;p&gt;But there’s this whole other level of coming up with soulful presents that require a lot more effort than just clicking “Buy now” on Amazon (don’t forget to enable 1-click Ordering to skyrocket your purchasing power or even get an &lt;strike&gt;Echo&lt;/strike&gt; Alexa). So here’s the list of presents that I’ve given to other people and wish I could receive myself.&lt;/p&gt;

&lt;h2 id=&quot;fly-high&quot;&gt;Fly high&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/presents/fly_high.jpg&quot; alt=&quot;Flying Lesson&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; 3 hours&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; nobody can read my boyfriend, so it’s basically hard to know&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; experience - safe and exciting enough&lt;/p&gt;

&lt;p&gt;This one is actually a developed-world present, but it has a nice touch to it. Since we have this whole trend of giving people experiences, rather than objects, plus my boyfriend is very minimalist with his possessions and he already has everything he needs, I decided to get him a &lt;strong&gt;Trial Flying Lesson&lt;/strong&gt; in a two seater aircraft. Once in the air the pilot lets you take over the yoke and pedals and fly the plane yourself. I knew my SO never flew a plane and wanted to.&lt;/p&gt;

&lt;p&gt;I bought the voucher online. It was too late to order the &lt;em&gt;special&lt;/em&gt; birthday pack that comes by post, so I decided to just print the page and make a cute origami shirt + mandatory birthday card with cats, which has handwritten inside “Open the shirt”.&lt;/p&gt;

&lt;h2 id=&quot;jojo-in-the-stars&quot;&gt;Jojo in the stars&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; 3 days&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; ecstatic rainbows spurring out of the mouth&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; dangerous, thrilling and very teenagy&lt;/p&gt;

&lt;p&gt;Ok. When I was a teenager, it was “cool” to be all bummed out about everything. Don’t judge me. And so I had this friend who liked this dark short animation video &lt;a href=&quot;https://www.youtube.com/watch?v=i_Yn4SMIeP8&quot;&gt;Jojo in the stars&lt;/a&gt; (I tried rewatching it now, but meh).&lt;/p&gt;

&lt;p&gt;Jojo has a sad fate. I decided to light up the mood by making a graffiti of Jojo (he’s geometrically shaped and easy to draw) and give him wings, so that he can fly and save himself!&lt;/p&gt;

&lt;p&gt;The logistics were simple: one white and a couple of black spay paint cans. Grab my friend, go under the bridge near the train tracks and start being all artistic (never actually did graffiti before). Now in retrospect I wouldn’t recommend to anyone going under the bridge when you’re a 17 year old teenage girl without event mentioning it to parents or any close friends. Nevertheless it all ended well. And my friend was ecstatic to see his birthday gift.&lt;/p&gt;

&lt;p&gt;I’ve spend one hour trying to find a picture of the graffiti: nothing on my old photosharing account, nothing on google, nothing on any of my old blogs T_T&lt;/p&gt;

&lt;h2 id=&quot;doodled-mug&quot;&gt;Doodled mug&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/presents/nadya_mug.jpg&quot; alt=&quot;Doodled mug&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; 3 hours&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; I think she liked it&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; boring overall, but with a nice very personal touch&lt;/p&gt;

&lt;p&gt;Mugs are a boring gift (I’ve just mentioned the Darth Vader mug at the beginning of this post). But… but this one is cute, because I covered it all in silly childish doodles. Used my acrylic paint. For a long lasting effect you can cover it in a layer of glaze.&lt;/p&gt;

&lt;h2 id=&quot;blossom-in-winter&quot;&gt;Blossom in winter&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; half a day&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; getting someone out of depression is a pretty good outcome&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; romantic and almost environmentally friendly&lt;/p&gt;

&lt;p&gt;It was one of those sad, cold, snowless winters. My friend used to live not far from the forest slash park. The bare trees in this time of the year look very gloomy and unwelcoming. I dragged my friend into the forest (no, I’m not a rapist), even though he kept on saying that’s going to make things worse and I kept on saying it’s going to make things better.&lt;/p&gt;

&lt;p&gt;It made things better because I decorated a tree by the lake with pink &lt;a href=&quot;http://ancdn-k-o.shopletcdn.com/productimages/500x500/MMMR333FLW_3_1.JPG&quot;&gt;flower-shaped post it notes&lt;/a&gt;. Few hours before meeting my friend I hooked the tiny pieces of paper by strings to the branches. Also scattered a few “flowers” forming a path to the tree. It looked like a little island of spring (⌒▽⌒)☆&lt;/p&gt;

&lt;p&gt;A wave of good emotions. So good I forgot to take any pictures. Also no smartphones era.&lt;/p&gt;

&lt;h2 id=&quot;i-give-you-my-hand&quot;&gt;I give you my hand&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/presents/hand.jpg&quot; alt=&quot;I give you my hand&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; half a day&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; someone was very impressed with my doodling skills (not sure if that was actually offensive)&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; cute, useless and doesn’t take up much space&lt;/p&gt;

&lt;p&gt;Connecting with my creative self again. On a A4 ~200gsm sheet of paper with antique finish I outlined the shape of my hand with a pencil. Cut the hand form. One side of it is feminine: soft shapes flowing in chaos. The other side is boyish: funky, hip with video games and robots. Nothing too special, but the execution was good and I know my friend kept it for a really long time (might still have it, but we don’t keep in touch).&lt;/p&gt;

&lt;h2 id=&quot;post-it-everywhere&quot;&gt;Post-it everywhere&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; 2 hours&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; big smiles&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; all about how much I care about you mom&lt;/p&gt;

&lt;p&gt;When I was a kid and didn’t have money to buy mom flowers, perfume or fancy creams, I’d make cards (handmade crazy looking “Happy Birthday Mom” cards). One year I wanted to make something different, so I used my pack of post-it notes and stuck them all over the flat with various inscriptions on them, things like “You cook the most delicious meals”, “Thank you for taking care of us”, “You look beautiful every day”. My mom mentioned a few spelling mistakes I made, but I’m sure she loved it (≧◡≦)&lt;/p&gt;

&lt;h2 id=&quot;diy-robot&quot;&gt;DIY robot&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/presents/pibot.jpg&quot; alt=&quot;Pibot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rough estimate of consumed time:&lt;/em&gt; 1 hour&lt;br /&gt;
&lt;em&gt;Resulting effect:&lt;/em&gt; he didn’t build the robot, but is still excited about the potential thought of it&lt;br /&gt;
&lt;em&gt;Gift specimen:&lt;/em&gt; guided geekiness&lt;/p&gt;

&lt;p&gt;This is the time when first Raspberry Pi came out. So I got one for my friend. In addition to it I wanted to give him all the tools to build his first robot. I found &lt;a href=&quot;http://pibot.org/&quot;&gt;pibot kit&lt;/a&gt; that has all the elements and also you a step-by-step guide how to build a robot. They changed their website ever since and also posted better instructions.&lt;/p&gt;

&lt;p&gt;My friend fiddled with the Raspberry Pi and other components, but never build the robot. At least I tried…&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2016/07/23/a-present-for-you/</id>
      <updated>2016-07-23T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Profiling a Django App hosted on Google App Engine</title>
      <link href="http://ana-balica.github.io/2016/03/19/profiling-a-django-app-hosted-on-gae/" />
      <summary type="html">&lt;p&gt;Ever used Django with App Engine? How about the &lt;a href=&quot;https://cloud.google.com/appengine/docs/python/datastore/&quot;&gt;Datastore&lt;/a&gt;? Well, if you didn’t
&lt;a href=&quot;https://p.ota.to/&quot;&gt;Potato&lt;/a&gt; actually developed an in-house solution called &lt;a href=&quot;https://github.com/potatolondon/djangae&quot;&gt;Djangae&lt;/a&gt; that makes
Django play nicely and almost seamlessly with the Datastore via its ORM. As if
you are writing an app that’ll work with a SQL database, except you don’t.&lt;/p&gt;

&lt;p&gt;If you go down that road, how do you figure out why a piece of Django code is slow?
This brings us to Appstats.&lt;/p&gt;

&lt;h2 id=&quot;what-is-appstats&quot;&gt;What is Appstats&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://cloud.google.com/appengine/docs/python/tools/appstats&quot;&gt;Appstats&lt;/a&gt; is a
profiling library that comes together with the App Engine SDK. Its
only purpose is profiling RPC performance of apps. The App Engine Remote
Procedure Calls include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Datastore calls (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Datastore.Get&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Datastore.Put&lt;/code&gt;, etc)&lt;/li&gt;
  &lt;li&gt;Memcache calls (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memcache.get&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memcache.set&lt;/code&gt;, etc)&lt;/li&gt;
  &lt;li&gt;URL Fetches&lt;/li&gt;
  &lt;li&gt;Mail sends&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;why-do-you-need-it&quot;&gt;Why do you need it&lt;/h2&gt;

&lt;p&gt;Django offers a lovely ORM to abstract our code from a specific database. It
has tremendous benefits and (at least) one big drawback. It hides the complexity of
database queries. It’s easier to make a very expensive query (or make it even
multiple times during a request) without realizing it. That’s why profilers exists:
find out why an app is slow.&lt;/p&gt;

&lt;p&gt;There is a popular library called &lt;a href=&quot;https://github.com/django-debug-toolbar/django-debug-toolbar&quot;&gt;django-debug-toolbar&lt;/a&gt;.
It shows developers the raw SQL queries and the time it took to
perform them. Unfortunately it’s rather useless when it comes to profiling an App Engine
app - remember there is no SQL. But thanks to App Engine developers, we have Appstats.&lt;/p&gt;

&lt;h2 id=&quot;how-to-use-it&quot;&gt;How to use it&lt;/h2&gt;

&lt;p&gt;It’s actually incredibly simple. To enable Appstats you need to update only 2 files:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# settings.py
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&apos;google.appengine.ext.appstats.recording.AppStatsDjangoMiddleware&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&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;c1&quot;&gt;# app.yaml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;builtins&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;na&quot;&gt;appstats&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;on&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is optional, but highly recommended:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# appengine_config.py
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;appstats_MAX_STACK&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Since Django is a multi-layered framework, some of the calls recorded by Appstats
can have very deep stacks, so the &lt;a href=&quot;https://googleappengine.googlecode.com/svn/trunk/python/google/appengine/ext/appstats/sample_appengine_config.py&quot;&gt;default value of 10&lt;/a&gt;
won’t be enough to reach our own code. You’ll see for yourself soon.&lt;/p&gt;

&lt;h2 id=&quot;appstats-console&quot;&gt;Appstats console&lt;/h2&gt;

&lt;p&gt;Once the middleware and the builtin are enabled, you can view the Appstats console
at &lt;a href=&quot;http://127.0.0.1:8000/_ah/stats/&quot;&gt;http://127:0.0.1:8000/_ah/stats/&lt;/a&gt;. If you bother, this URL can be changed.&lt;/p&gt;

&lt;p&gt;Welcome to the ’90s!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/appstats/appstats_console.png&quot; alt=&quot;Appstats Console&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see there are 3 components of the console:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RPC Stats - it will tell you how many of each RPC calls are made overall.&lt;/li&gt;
  &lt;li&gt;Path Stats - how often you’ve hit a specific URL.&lt;/li&gt;
  &lt;li&gt;Requests History - all the requests that were made once you’ve started your server,
the most recent being on the top.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s focus on the Requests History - this is where the fun part is. From this list
you can already see plenty of interesting information. Every request has a short
summary: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;real=410ms api=0ms overhead=2ms (17 RPCs, cost=0, billed_ops=[])&lt;/code&gt;. It
shows the total request time 410ms, the overhead 2ms of recording this
request (Appstats does come with a little cost) and total number of RPC calls
that were made during this request - 17 RPCs.&lt;/p&gt;

&lt;p&gt;Click on either of the requests from Request History list and you’ll see this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/appstats/appstats_timeline.png&quot; alt=&quot;Appstats Request Timeline&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This particular example is &lt;em&gt;boring&lt;/em&gt;, because I’m making a request to Django admin.
But still this looks very helpful. You can instantly see the most expensive RPCs here.
If you expand an item by clicking on little &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; button
or directly on the rectangle from the timeline, it will show you the full stack.
There are more than 10 lines there, right? Enough to actually go
beyond the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;googleappengine&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django&lt;/code&gt; code, and get to your app’s codebase
(not in this case, since no custom code is involved) -
because that’s where most probably stuff is slow. Thank you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appstats_MAX_STACK&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/appstats/appstats_stack.png&quot; alt=&quot;Appstats Stack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once you are there, inspect the code. Maybe you are making a terribly expensive
query or you are writing too often to memcache (without a good reason), or you
are not fetching from memcache when you should be, or you are creating a hell lot
of deferred tasks, or… there can be lots of reasons!&lt;/p&gt;

&lt;h2 id=&quot;can-i-use-it-in-production&quot;&gt;Can I use it in production?&lt;/h2&gt;

&lt;p&gt;You could, if you want to identify a problem that is production specific, but no
real reason to leave it enabled, because Appstats will only store the last 1000
requests. Moreover they have that tiny overhead. In conclusion, use Appstats
extensively during development and only occasionally on production.&lt;/p&gt;

&lt;p&gt;Happy profiling!&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2016/03/19/profiling-a-django-app-hosted-on-gae/</id>
      <updated>2016-03-19T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Mistune custom lexers - we are going deeper</title>
      <link href="http://ana-balica.github.io/2015/12/21/mistune-custom-lexers-we-are-going-deeper/" />
      <summary type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/lepture/mistune&quot;&gt;Mistune&lt;/a&gt; is the fastest markdown parser
written in pure Python. And it has good documentation. At least so it seemed
until I tried to write a custom lexer (hint: tests are a good source of inspiration).&lt;/p&gt;

&lt;h2 id=&quot;vocabulary&quot;&gt;Vocabulary&lt;/h2&gt;

&lt;p&gt;Even though this is a recipe for solving a specific problem, I’ll start off with
some basics and a definition list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grammar&lt;/strong&gt; - set of rules for rewriting strings. In case of Markdown we are
rewriting rules like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;**some string**&lt;/code&gt; to &lt;strong&gt;some string&lt;/strong&gt;. Basically I’m saying
“if I use two asterisks followed by any random string
and end with another 2 asterisks, wrap the string into an HTML &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;strong&lt;/code&gt;&amp;gt; tag”.
The full list of those rules is available on &lt;a href=&quot;https://daringfireball.net/projects/markdown/&quot;&gt;Daring Fireball website&lt;/a&gt;.
A formalized spec of Markdown, a big community effort is also available on
&lt;a href=&quot;http://commonmark.org/&quot;&gt;CommonMark website&lt;/a&gt;. For example, it goes into much bigger detail &lt;a href=&quot;http://spec.commonmark.org/0.22/#emphasis-and-strong-emphasis&quot;&gt;when
and how strong emphasis should be applied&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inline grammar&lt;/strong&gt; - rules of the grammar that when rewritten will appear, well, inline.
Examples of inline rules in Markdown are links, emphasizes, images, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block grammar&lt;/strong&gt; - conversely to inline grammar, these rules of the grammar will
take up a whole block. Examples are headers, paragraphs, code blocks, lists, tables,
etc. Inline and block grammar rules directly translate to HTML definition of
inline vs block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lexer&lt;/strong&gt; - program that is able to convert a series of characters into a
sequence of tokens according to the grammar, and it’s doing that using regular
expressions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Renderer&lt;/strong&gt; - program that controls the output of grammar rules. There is no
one fixed way to go from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;**strong**&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;strong&amp;gt;strong&amp;lt;/strong&amp;gt;&lt;/code&gt;, but rather an
infinite number of ways to adjust that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;strong&amp;gt;strong&amp;lt;/strong&amp;gt;&lt;/code&gt; output.&lt;/p&gt;

&lt;p&gt;Mistune offers a way to have custom renderers and custom lexers.
Add whatever specific rules and outputs you want. &lt;a href=&quot;https://github.com/lepture/mistune/blob/master/README.rst#lexers&quot;&gt;The example from the docs&lt;/a&gt; picks GitHub Wiki links and creates a custom inline renderer to output it as an HTML anchor
tag and an inline lexer that defines a regular expression capable of parsing
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[[Page 2|Page 2]]&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;scratching-my-itch&quot;&gt;Scratching my itch&lt;/h2&gt;

&lt;p&gt;I want to be able to refer to people by their twitter username and link to their
twitter accounts when I’m writing in Markdown right on my blog (this is a theoretical
desire, I’m actually not using mistune on this blog yet :sad_face:). This is an inline grammar and it’s
going to be composed of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; and a sequence of characters that only accepts letters,
numbers and underscore. Replace twitter with any website that has accounts and direct
URLs to them.&lt;/p&gt;

&lt;p&gt;Basically the thing twitter is already good at: recognizing @username and linking
to this account (if it exists).&lt;/p&gt;

&lt;p&gt;Following the docs available on mistune README I came up with this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;re&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;mistune&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UsernameRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;username_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&amp;lt;a href=&quot;%s&quot;&amp;gt;%s&amp;lt;/a&amp;gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UsernameInlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;enable_username_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username_link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;@(\w+)&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;username_link&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;output_username_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://twitter.com/%s/&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;__main__&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UsernameRenderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UsernameInlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enable_username_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Hello @username&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# &amp;lt;p&amp;gt;Hello @username&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Aaaand it doesn’t do its job. It follows the example of the wiki link
quite closely: a custom renderer, a custom inline lexer which adds a new rule
using a really simply regular expression and then all the initialization. &lt;strong&gt;Why
doesn’t it work then?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/mistune-lexers/yunowork.jpg&quot; alt=&quot;Y U NO WORK&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;going-deeper&quot;&gt;Going deeper&lt;/h2&gt;

&lt;p&gt;Surprise surprise! It doesn’t even match my regular expression. To find out why I’ve
pdb-ed a couple of times into the one-file mistune package and learned the
following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Mistune takes the initial string and runs it through all the rules (by the way
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;username_link&lt;/code&gt; rule is there) to match at least something. It uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;re.match()&lt;/code&gt;,
which specifically is looking for a pattern match at the beginning of the file
(for finding a match anywhere within the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;re.search()&lt;/code&gt; is used). And yes, if we
try to do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print markdown(&apos;@username&apos;)&lt;/code&gt; it will work as expected and return
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;a href=&quot;https://twitter.com/username/&quot;&amp;gt;username&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Once something was matched it will slice the matched bit from the string
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text = text[len(m.group(0)):]&lt;/code&gt; and continue with point 1 until the whole string
is exhausted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What happens in our case is that the string “Hello @username” is treated as a
whole paragraph. How come &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hello [[Link Text|Wiki Link]]&lt;/code&gt; is recognized as a paragraph
that also contains a wiki link?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution lies in the text pattern of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InlineGrammar&lt;/code&gt; class.&lt;/strong&gt; Look at this
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text = re.compile(r&apos;^[\s\S]+?(?=[\\&amp;lt;!\[_*`~]|https?://| {2,}\n|$)&apos;)&lt;/code&gt;. Zoom in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(?=[\\&amp;lt;!\[_*`~]|https?://| {2,}\n|$)&lt;/code&gt;. This is called a lookahead assertion, which
matches if the stuff between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(?=...)&lt;/code&gt; will match, but doesn’t actually consume it.
The lookahead assertion contains a couple of characters, which will make mistune
slice the string and try to render the token. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[&lt;/code&gt; symbol is there, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; is not.
That’s why the wiki link example works just fine and the username link example
doesn’t.&lt;/p&gt;

&lt;h2 id=&quot;another-way&quot;&gt;Another way&lt;/h2&gt;

&lt;p&gt;This other way involves overriding the text pattern to take into consideration
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; symbol and tokenize the string per our wish. This is my ugly solution (code
below is scrollable to the right).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;copy&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;re&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;mistune&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UsernameInlineGrammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InlineGrammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;username_link&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;^@(\w+)&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Override the text grammar pattern to contain the `@` as a stop element in the lookahead assertion
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;^[\s\S]+?(?=[\\&amp;lt;!\[_*`~@]|https?://| {2,}\n|$)&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UsernameUrlInlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Inline lexer for @&amp;lt;username&amp;gt; which links to the user twitter page.&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;default_rules&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;default_rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;username_link&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;default_rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UsernameInlineGrammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UsernameUrlInlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;output_username_link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;alt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://twitter/{}/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;__main__&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mistune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Markdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UsernameUrlInlineLexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Hello @username&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# &amp;lt;p&amp;gt;Hello &amp;lt;a href=&quot;https://twitter/username/&quot;&amp;gt;@username&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this case we are extending the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InlineGrammar&lt;/code&gt;, adding a new rule and
overriding the existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text&lt;/code&gt; rule, which isn’t a very pleasant experience.
Notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;username_link&lt;/code&gt; grammar regular expression has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; (caret) symbol,
which tells it look from the very beginning of the string. Also notice the lack
of any custom renderer - I just decided to use the link renderer, which it yield
the same result.&lt;/p&gt;

&lt;h2 id=&quot;fin&quot;&gt;Fin&lt;/h2&gt;

&lt;p&gt;Congratulations! You’ve made it to the end! Got a better solution? Share it with
everybody or take a nap :)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/mistune-lexers/catnap.jpeg&quot; alt=&quot;Cat nap&quot; /&gt;&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2015/12/21/mistune-custom-lexers-we-are-going-deeper/</id>
      <updated>2015-12-21T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>DjangoCon, ponies and emoji</title>
      <link href="http://ana-balica.github.io/2015/06/06/djangocon-ponies-and-emoji/" />
      <summary type="html">&lt;p&gt;Early on when &lt;a href=&quot;http://2015.djangocon.eu/&quot;&gt;DjangoCon Europe 2015&lt;/a&gt; was announced,
it instantly differentiated itself from other conferences.&lt;/p&gt;

&lt;p&gt;Organized this year in Cardiff, UK, DjangoCon
set its goals high by planning 3 days of talks, 2 days of sprints and providing
inclusive environment for everybody. It encouraged first time speakers to come
and share their thoughts and adventures in Djangoland (© &lt;a href=&quot;https://twitter.com/bmispelon&quot;&gt;@bmispelon&lt;/a&gt;) by
launching a speaker mentor program, included a live text transcription throughout the whole
conference, offered a free crèche (and we had some lovely young djangonaughts),
organized a free open day, which students of Cardiff University benefited from.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/djangocon/cardiffuni.jpg&quot; alt=&quot;Cardiff University&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In addition to all of this DjangoCon is characterized by an extremely friendly
community. Mark said it better:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;I can honestly say that the &lt;a href=&quot;https://twitter.com/hashtag/djangocon?src=hash&quot;&gt;#djangocon&lt;/a&gt; community is the nicest, most decent collection of people I have ever met. Breath-takingly lovely ❤️&lt;/p&gt;&amp;mdash; Mark Henwood (@mcbhenwood) &lt;a href=&quot;https://twitter.com/mcbhenwood/status/606150799270539265&quot;&gt;June 3, 2015&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;During those few days spent in Cardiff, you realize that Django is not just a
framework that we all use and like, it’s the people who
make it awesome. It’s also sort of snowball effect. Once you see how Django
community treats all the newcomers, you want to share this right attitude
with the rest of the world.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/djangocon/mybadge.jpg&quot; alt=&quot;DjangoCon badge with my customized emoji&quot; /&gt;&lt;/p&gt;

&lt;p&gt;DjangoCon did everything right. And it’s pretty hard to get everything right
when you have 300+ attendees, volunteer-driven team (actually the most pony-awesome team:
Vincent, Baptiste, David, Daniele, Ola, Jason, Geraint) and
&lt;a href=&quot;https://www.youtube.com/watch?v=QJO3ROT-A4E&quot;&gt;One Direction&lt;/a&gt; invasion.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2015/06/06/djangocon-ponies-and-emoji/</id>
      <updated>2015-06-06T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>The tale of DRY with django-crispy-forms | Part II</title>
      <link href="http://ana-balica.github.io/2015/03/18/the-tale-of-dry-with-django-crispy-forms-part-2/" />
      <summary type="html">&lt;p&gt;When you write a blog post, people of Internet will point out any mistakes
they find. It’s a great opportunity to improve existing code and look into other
solutions. After posting &lt;a href=&quot;/2014/11/04/the-tale-of-dry-with-django-crispy-forms/&quot;&gt;The tale of DRY with django-crispy-forms&lt;/a&gt;
I found out about &lt;a href=&quot;https://github.com/funkybob/formulation&quot;&gt;formulation&lt;/a&gt; -
a template-based solution for rendering forms, in contrast to crispy-forms that
builds the form structure in code.&lt;/p&gt;

&lt;p&gt;Also &lt;a href=&quot;https://twitter.com/maraujop&quot;&gt;@maraujop&lt;/a&gt; – crispy-forms developer – made
several very helpful suggestions in the comments area, which brings us to Part II.&lt;/p&gt;

&lt;h2 id=&quot;mistakes-of-the-past&quot;&gt;Mistakes of the past&lt;/h2&gt;

&lt;p&gt;The story of Foo people can be found in this &lt;a href=&quot;/2014/11/04/the-tale-of-dry-with-django-crispy-forms/&quot;&gt;archive&lt;/a&gt;.
Their end was tragic. They knew truth was somewhere close, but they were unable
to grasp it to its fullest and failed to survive this cruel software world.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FooForm&lt;/code&gt;s had their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__&lt;/code&gt; cluttered with the initialization
of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FormHelper&lt;/code&gt; object and the attachment of  the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitCancelFormActions&lt;/code&gt;.
Nothing bad with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitCancelFormActions&lt;/code&gt; itself, but as they grew in number
overriding the initialization started to look silly.&lt;/p&gt;

&lt;p&gt;Decline of Foo marked the birth of powerful Bar people.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/dry-tale-2/laputa.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/dry-tale-2/laputa.jpg&quot; alt=&quot;Laputa: Castle in the Sky (Ghibli Studio) - How I imagine the fairy tale kingdoms&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Laputa: Castle in the Sky (Ghibli Studio) - How I imagine the fairy tale kingdoms
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;reforms&quot;&gt;Reforms&lt;/h2&gt;

&lt;p&gt;Assume that Bar model, view and template are similar to Foo. Bar people knew
they should start with the API, and so they shaped their dreams first.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/characters/forms.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;characters.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;common.forms&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModelFormWithHelper&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;common.helpers&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SubmitCancelFormHelper&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BarForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelFormWithHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Model Bar form&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;helper_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SubmitCancelFormHelper&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;helper_cancel_href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;{% url &apos;some_cancel_url&apos; %}&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What Bar wants is to declare an alternative &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FormHelper&lt;/code&gt;, which is responsible
for customizing the form. Also it wants to provide helper attributes, that are different
for each form - the cancel URL, for example.&lt;/p&gt;

&lt;p&gt;There are 2 unknown creatures here - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitCancelFormHelper&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModelFormWithHelper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitCancelFormHelper&lt;/code&gt; as you might have guessed is of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FormHelper&lt;/code&gt; breed. It
tells you right to the face that it appends to the layout submit and cancel buttons.
See for yourself.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/common/helpers.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.bootstrap&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormActions&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.helper&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Layout&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.layout&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SubmitCancelFormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Custom FormHelper that appends to the layout cancel and submit
    buttons (works only with bootstrap crispy-forms pack). It expects a
    `cancel_href` attribute to be used as cancel button URL.

    Example::

        SubmitCancelFormHelper(self, cancel_href=&quot;/some/url/&quot;)
    &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cancel_href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;cancel_href&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;#&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SubmitCancelFormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;FormActions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;&amp;lt;a role=&quot;button&quot; class=&quot;btn btn-default mr4&quot;
                            href=&quot;{0}&quot;&amp;gt;Cancel&amp;lt;/a&amp;gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cancel_href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;save&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Submit&apos;&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;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This class expects a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cancel_href&lt;/code&gt; named parameter. Afterwards it takes
advantage of the power it was given by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FormHelper&lt;/code&gt; and modifies the layout by
appending a button that we represent using HTML widget and a Submit widget.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitCancelFormHelper&lt;/code&gt; serves us well.&lt;/p&gt;

&lt;p&gt;What about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModelFormWithHelper&lt;/code&gt; mystery. This base class is a bit more tricky,
but still nothing out of this world.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/common/helpers.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.core.exceptions&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImproperlyConfigured&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.forms&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModelForm&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModelFormWithHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Custom ModelForm that allows to attach a crispy-forms FormHelper class,
    that will modify in some way the rendering of the layout.

    Example::

        FooForm(ModelFormWithHelper):
            class Meta:
                model = FooModel
                helper_class = FooFormHelper
    &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelFormWithHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hasattr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;helper_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;helper_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;getattr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;helper_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_helper_kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;helper_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImproperlyConfigured&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;{0} is missing a &apos;helper_class&apos; meta attribute.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__class__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_helper_kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Get all helper attributes from class Meta by stripping them of
        `helper_` part of attribute string

        :return: dict with helper kwargs
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__dict__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;helper_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;helper_class&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;new_attr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ohh, that’s a lot of code. Well, docstrings make it 1/3 of the listing. Let’s
see what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModelFormWithHelper&lt;/code&gt; is trying to tell us.&lt;/p&gt;

&lt;p&gt;In the initialization phase it checks if the class
has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;helper_class&lt;/code&gt; attribute. It’s mandatory to be there, otherwise there’s
no point in using this class at all. If there isn’t, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModelFormWithHelper&lt;/code&gt; will
throw an exception to remind you, &lt;em&gt;Hey, you forgot that attribute - helper_class!&lt;/em&gt;
Otherwise, it will initialize the form helper class and attach it
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self.helper&lt;/code&gt;. But before that it extracts the helper kwargs.&lt;/p&gt;

&lt;p&gt;Look at the dream &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BarForm&lt;/code&gt; class. Bar people wanted to have a custom cancel URL
and used a meta attribute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;helper_cancel_href&lt;/code&gt;. Method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_helper_kwargs()&lt;/code&gt; deals
with all the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;helper_&lt;/code&gt; attributes and strips them of that prefix to ultimately
feed them to the helper.&lt;/p&gt;

&lt;p&gt;The class is not tied to any specific form helper, so you can create as many custom
form helpers as your kingdom needs.&lt;/p&gt;

&lt;p&gt;That’s it. Now forms will become more compact and readable due to the new meta
attributes.&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2015/03/18/the-tale-of-dry-with-django-crispy-forms-part-2/</id>
      <updated>2015-03-18T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Pagination in Django</title>
      <link href="http://ana-balica.github.io/2015/01/29/pagination-in-django/" />
      <summary type="html">&lt;p&gt;Isn’t it delightful when things just work? That’s how it is for Django pagination
feature.&lt;/p&gt;

&lt;p&gt;Say you are writing a blog in Django. Actually seems like a silly idea. If you
want a blog, get yourself a static blog, or tumblr, or wordpress, or blogger
(is it still popular?).
Ok, maybe it’s not a blog. Probably you want to display a list of books in a
paginated way. Definitely not cool to list all 2k books on a single page.&lt;/p&gt;

&lt;p&gt;I like Django class-based views. They do for you all the hard work if you stick
to the basics. So let’s start writing a CBV. Assume the model contains any kind of gibberish.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# my_library/library/views.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.views.generic&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;library.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BookListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Book&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;paginate_by&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;template_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;book_list.html&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is basically what we ought to do to enable pagination. Just specify how many
objects we want on one page. Let’s take a look
at the route and the template.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# my_library/urls.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.conf.urls&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;library.views&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BookListView&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;^books/$&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BookListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;book_list&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# my_library/templates/book_list.html #}
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# omit all the additional HTML markup and leave the bare minimum #}
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now if you start your server and access the URL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1:8000/books/&lt;/code&gt; you will
get 10 book objects listed on the first page. In order to access the second page
you need to enter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1:8000/books/?page=2&lt;/code&gt;. But your user isn’t supposed
to know that (don’t even think about writing a manual for that and giving it
to the end user). That’s why we will create pagination buttons.&lt;/p&gt;

&lt;p&gt;Django &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt; is so smart that it will add to your context some special
objects that will allow you to build those pagination buttons. In fact the
pagination we will build is reusable, so we will put in a separate snippet and
include to any template that requires pagination.&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;{# my_library/templates/snippets/pagination.html #}
{% if is_paginated %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pagination&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      {% if page_obj.has_previous %}
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;?page={{ page_obj.previous_page_number }}&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;Previous&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      {% else %}
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;disabled&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;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&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;Previous&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      {% endif %}

      {% for page in paginator.page_range %}
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;page =&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;page_obj.number&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;active&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;?page={{ page }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      {% endfor %}

      {% if page_obj.has_next %}
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;?page={{ page_obj.next_page_number }}&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;Next&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      {% else %}
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;page_obj.has_next&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&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;Next&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      {% endif %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
{% endif %}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now back to our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;book_list.html&lt;/code&gt; template.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# my_library/templates/book_list.html #}
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&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;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;snippets/pagination.html&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Dead simple. And this snippet will serve you well for all kinds of list views.&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2015/01/29/pagination-in-django/</id>
      <updated>2015-01-29T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Take me to Bali</title>
      <link href="http://ana-balica.github.io/2015/01/22/take-me-to-bali/" />
      <summary type="html">&lt;p&gt;Bali is probably one of those beautiful and exotic places, that are actively advertised at your local travel agency. &lt;em&gt;Paradise on earth&lt;/em&gt;, I think, they call it. Not without a reason, of course. It’s this beautiful, haunting place, where you imagine yourself lying on the white-sand beaches, sipping coconut cocktails and watching the azure ocean. You know, like in movies.&lt;/p&gt;

&lt;h2 id=&quot;selamat-datang&quot;&gt;Selamat Datang&lt;/h2&gt;

&lt;p&gt;Welcome to Bali! You and the other 3 million curious tourists annually made it to the destination. Seriously, Bali has almost no off season. People come and go all the time. &lt;a href=&quot;http://www.disparda.baliprov.go.id/en/Statistics2&quot;&gt;According to the statistics, provided by Bali Government Tourism Office&lt;/a&gt;, the island hosted on average 300,000 newcomers each month during 2014.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/flower1.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/flower1.jpg&quot; alt=&quot;Tropical Plumeria&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Tropical Plumeria
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Even though Indonesia has &lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_islands_of_Indonesia&quot;&gt;18,307 islands&lt;/a&gt;, Bali stays the top one attraction. So be prepared to meet crowds of people. To your attention, Visa on Arrival (VOA) costs 35 US dollars and don’t forget to spare 20,000 IDR for the departure tax. Generally prices grow every year, so get informed before the trip.&lt;/p&gt;

&lt;h2 id=&quot;where-to-go&quot;&gt;Where to go&lt;/h2&gt;

&lt;p&gt;When I was hearing &lt;em&gt;Bali&lt;/em&gt;, I always thought of just Bali. It never crossed my mind that the island is big enough to have a variety of touristic flavors. North is different from South. Center of the island is different from its outer parts. Since I have spent a month and a half in Indonesia, I got plenty of time to try 3 types of Bali life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kuta&lt;/strong&gt; is a famous beach on Bali. It’s full of life, since most of the Australians stop here. As a matter of fact, Australians represent the major nationality visiting Bali. It is a 3-hour flight on average from Darwin to a paradise-like, cheap and always welcoming location.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/sea.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/sea.jpg&quot; alt=&quot;Kuta Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Kuta Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Kuta was very attractive to me, because it has the best beginners surfing beach. The ocean surface by the beach is sandy with almost no rocks, it is not deep and the waves are good both for beginners, as well as for pros. Kuta doesn’t have the perfect tube wave, but I guess I am far from mastering that one.&lt;/p&gt;

&lt;p&gt;There isn’t much you can do around Kuta, except for party and surfing. If you can get out of the village, then you can visit Pandawa Beach. The water is clean and still. There are less people and the cliffs around look lovely.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/pandawa-beach.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/pandawa-beach.jpg&quot; alt=&quot;Clean and still waters at Pandawa Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Clean and still waters at Pandawa Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/pandawa-beach2.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/pandawa-beach2.jpg&quot; alt=&quot;Cliffs at Pandawa Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Cliffs at Pandawa Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Unfortunately Kuta is the most annoying place on all Bali. Every time you walk past local people, they will try to sell you goods or services: massage, motorbike rent, taxi, tattoo, souvenirs, board rent, surfing lessons. They never get tired of asking you again and again.&lt;/p&gt;

&lt;p&gt;I guess I sound very picky, but in 2 or 3 days most of the tourists start to feel the need to avoid the eye contact with vendors. On the other hand the behavior is understandable, since the competition is huge. The advertising is aggressive and pushy, but it works for the most part.&lt;/p&gt;

&lt;p&gt;Some of the marketing strategies are more sophisticated. Locals try to establish a relationship with you. Make a little smalltalk. Lure you with their fake interest. And when time is right, they tell you what they really want - sell stuff.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/sunset.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/sunset.jpg&quot; alt=&quot;Sunset at Buta Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Sunset at Buta Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Most people who tend to seek peace and balance go to &lt;strong&gt;Ubud&lt;/strong&gt;. Ubud is a lovely place, 2 hour ride from Kuta to the north. It breaths culture and style. It can be summarized as art, yoga and dance. Ubud has several museums and plenty of galleries.&lt;/p&gt;

&lt;p&gt;There are a lot of home-stays in Ubud, so it is kinda easy to find intimate accommodation for a low price. Search for a home-stay that offers breakfast. They cook tasty pancakes and always include fresh fruits - yummy.&lt;/p&gt;

&lt;p&gt;Ubud has this big hype around organic stuff: organic food, organic drinks, organic yoga pants. I might be wrong, but I assume the local cheap food uses same veggies as organic restaurant do. It’s just &lt;em&gt;organic&lt;/em&gt; rises the price tag.&lt;/p&gt;

&lt;p&gt;There are some famous foot tracks in Ubud, which lead you to beautiful fields and hills. I have really enjoyed the Campuan Ridge walking tour.&lt;/p&gt;

&lt;p&gt;If you like monkeys, go to Monkey Forest. I am not sure who is bothering who: monkeys the tourists or tourists the monkeys. I have seen people who were not respecting the rules of the forest and in some way harming the animals. Monkeys aren’t really polite as well. They will snatch shiny objects and will climb on to you if they think you have food.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/nature1.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/nature1.jpg&quot; alt=&quot;Monkey Forest, Ubud&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Monkey Forest, Ubud
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/nature2.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/nature2.jpg&quot; alt=&quot;Monkey Forest, Ubud&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Monkey Forest, Ubud
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Up to the north is tranquility. We visited &lt;strong&gt;Lovina Beach&lt;/strong&gt; - a real backpackers heaven. There are considerably fewer people and the accommodation prices can be very low. Nearby is the Bali sea, mountains and beautiful nature.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/nature4.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/nature4.jpg&quot; alt=&quot;Postcard view, Lovina Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Postcard view, Lovina Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Lovina is known for its volcanic black sand beaches. If you go swimming, there are barely any waves. It’s an amazing feeling to swim in quiet rain and witness some gorgeous rainbows (&lt;a href=&quot;https://www.youtube.com/watch?v=OQSNhk5ICTI&quot;&gt;and double rainbows&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;It is a fishing village, so expect to see a lot of boats. But the real symbol of Lovina are the dolphins. By the beach there is a tall status of a dolphin. They come to Lovina for the fish and no one loses the opportunity to see the mighty creatures. Wake up at 6 in the morning to catch a boat to see the wild dolphin chase. It’s kinda funny how tens of boats try to guess where exactly the dolphins will appear. And when they do, the whole gang of roaring boats tries to catch up with them.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/boat.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/boat.jpg&quot; alt=&quot;Boats and fishing in Lovina Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Boats and fishing in Lovina Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/dolphin-chase.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/dolphin-chase.jpg&quot; alt=&quot;A wild dolphin chase&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    A wild dolphin chase
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It’s worth going to the north to do snorkeling and diving to the Menjangan Island. I will never forget how impressed I was by the rush of the tropic aquatic life near the riff. Those pretty little fish going round their own business, as if never really bothered by weird guys in masks.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/menjangan-island.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/menjangan-island.jpg&quot; alt=&quot;Beautiful Menjangan island&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Beautiful Menjangan island
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/water.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/water.jpg&quot; alt=&quot;On the way to Menjangan island&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    On the way to Menjangan island
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;temples&quot;&gt;Temples&lt;/h2&gt;

&lt;p&gt;For the most part Indonesia is a Muslim country. But Bali is different. Bali practices Hinduism as religion. And you could feel it even with the soles of your feet. It is a big deal in the life of locals. They wake up in the morning and prepare the offerings for the God, light up a scent stick and repeat the process by the afternoon and evening. It doesn’t seem like a burden to them, they feel happy and accomplished to perform the ritual daily.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/offering.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/offering.jpg&quot; alt=&quot;Offerings prepared 3 times a day&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Offerings prepared 3 times a day
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;That said, Bali is overwhelmed with temples. To be honest, most of the them look the same with slight differences. There are important temples, then big touristic temples and everyday temples. Important ones are of some big significance for local people, but on the exterior they have nothing special. Pura Besakih is the largest template of Bali and was my one and only saint place, which I visited. And then come the everyday temples - the ones built by the house. Yes, more or less every house has a temple of its own.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/pura-besakih.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/pura-besakih.jpg&quot; alt=&quot;Puka Besakih - largest temple on Bali&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Puka Besakih - largest temple on Bali
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If you plan to visit more than one template, buy a sarong up front. Men and women are not allowed without one. Besides even if you get inside the template, you actually just walk around it, since visitors are not allowed in the prayer/meditation zone.&lt;/p&gt;

&lt;h2 id=&quot;nature&quot;&gt;Nature&lt;/h2&gt;

&lt;p&gt;Mesmerizing tropical nature is what left me speechless. During the trip good and bad stuff happened, but I always got reconciled somehow by the natural beauty of the island.&lt;/p&gt;

&lt;p&gt;Bali is famous for its wonderful rice fields. The green cascading pieces of land are protected by UNESCO, otherwise endangering the main Bali cultivation to be torn apart by greedy construction companies.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/ricefields.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/ricefields.jpg&quot; alt=&quot;Rice Fields, Bali&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Rice Fields, Bali
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/nature3.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/nature3.jpg&quot; alt=&quot;Green Fields, Bali&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Green Fields, Bali
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/nature6.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/nature6.jpg&quot; alt=&quot;Stairway to rice fields, Ubud&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Stairway to rice fields, Ubud
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Bali has to offer several hot springs mostly found at the north of the island. The way to Air Panas Banjar Hot String is somewhat famous, for the road being beautifully shadowed by old trees, with a clear blue coastline by the side of the road, which makes up for nice bike ride.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/nature5.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/nature5.jpg&quot; alt=&quot;On the way to Air Panas Banjar, Lovina Beach&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    On the way to Air Panas Banjar, Lovina Beach
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/air-panas-banjar.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/air-panas-banjar.jpg&quot; alt=&quot;Air Panas Banjar, Hot Strings of Banjar, Bali&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Air Panas Banjar, Hot Strings of Banjar, Bali
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Volcanoes - just some mountains with some lava boiling in it. But it’s kinda impressive to see a real active smoking volcano. We’ve been to Batur Volcano on motorbikes and the whole trip was a blast.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/baturvolcano.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/baturvolcano.jpg&quot; alt=&quot;Batur Volcano&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Batur Volcano
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/batur-road.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/batur-road.jpg&quot; alt=&quot;Road to Batur Volcano&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Road to Batur Volcano
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/volcano-nature.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/volcano-nature.jpg&quot; alt=&quot;Batur Volcano ashes&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Batur Volcano ashes
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;That being said, there ain’t no sunshine without rain. Unfortunately ecology is not something locals care about. People throw tons of plastic into the ocean and guess what, during the rain season it all comes back to the shore. The amazing tingling of plastic bags in the water - a dream come true.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/garbage1.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/garbage1.jpg&quot; alt=&quot;Garbage by the riverside&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Garbage by the riverside
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/garbage2.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/garbage2.jpg&quot; alt=&quot;Kuta Beach during rain season&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Kuta Beach during rain season
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;fruits&quot;&gt;Fruits&lt;/h2&gt;

&lt;p&gt;That smell can never be forgotten - durian. Druin is a fruit extremely liked by the Asian population. There is very little point in trying to describe the smell, but as they say it, whether you love or you hate it. I got the last one.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/durian.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/durian.jpg&quot; alt=&quot;Durian fruit&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Durian fruit
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Along with durian there are all kinds of fruits: passion fruit, dragon fruit, bananas, papaya, pineapple, watermelon, lychee, mango, etc.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/dragonfruit.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/dragonfruit.jpg&quot; alt=&quot;Pitahaya or Dragon fruit&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Pitahaya or Dragon fruit
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;But the real treasure is Manggis. This fruit is not particularly rich in nutritional value, but it’s inner juicy vesicles are very tasty. The fruit is in high demand always. Manggis season is short and hence big price fluctuations happen. It’s nice when you are able to catch the season.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/mangis.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/mangis.jpg&quot; alt=&quot;Mangosteen (Manggis) - the Queen of Fruit&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Mangosteen (Manggis) - the Queen of Fruit
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;locals&quot;&gt;Locals&lt;/h2&gt;

&lt;p&gt;You walk by and every local person will greet with “Hi” or “Hello”. Local greetings sound the same as English versions by the way. The hospitality of the place is felt everywhere as long as you behave. Once you crossed the line, bad things can happen. Don’t forget that the police is corrupt, so no easy way to get out of a bad situation.&lt;/p&gt;

&lt;p&gt;The whole time we were on Bali nothing was stolen or attempted to be stolen. At the inns they usually don’t have safe boxes, but it felt like you don’t even need them. I was told by the locals that indeed theft doesn’t occur often and for the most part it happens to drunk tourists late in the night returning from a party.&lt;/p&gt;

&lt;p&gt;Balinese people are very friendly and smiley. They will always help you if you have the intention to purchase something from them. But with all the welcoming appearance, it’s never a bad idea to be prudent. I hate to say it, but Balinese will lie and deceive you if they see profit. For example, you might be deceived at some local money exchange booths ending up with less money than you’d expect. Nevertheless nothing seriously bad ever happened.&lt;/p&gt;

&lt;p&gt;Bargaining is more than welcome. Once the price was dropped by 70% and I didn’t say a word. To me all the prices felt dummy afterwards, since it’s rather hard to estimate the real value. Nevertheless white people will overpay in any case. You can’t convince them to sell goods by the local real price. It just never happens.&lt;/p&gt;

&lt;h2 id=&quot;food&quot;&gt;Food&lt;/h2&gt;

&lt;p&gt;I felt in love with Balinese food. It’s slightly spicy, averagely salty and delicious for my tastes. Bali has a lot of vegetarian and vegan dishes. Generally meat is more expensive, seafood is mainly available and vegetables and rice are everywhere. Most common dishes are mie goreng (fried noodles), nasi goreng (fried rice), nasi campur (rice with toppings like meat, veggies, souses), soto bakso (soup with meatballs), soto ayam (chicken soup). My all time favorite is the mie soto - chicken soup with noodles, prepared at a &lt;a href=&quot;https://www.google.co.th/maps/place/8%C2%B031&apos;05.1%22S+115%C2%B016&apos;08.1%22E/@-8.5152122,115.2675073,16z/data=!4m2!3m1!1s0x2dd23d7102a8c64f:0x2d017f9076a37718?hl=en&quot;&gt;small local dinner in Ubud&lt;/a&gt;. I can fill my mouth all watery now just by the thought of mie soto.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/mie_goreng.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/mie_goreng.jpg&quot; alt=&quot;Mie goreng take-away in banana leaf&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Mie goreng take-away in banana leaf
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Rice is a complement to every meal. Even McDonals and KFC will serve you rice.&lt;/p&gt;

&lt;p&gt;As in most Asian countries food is everywhere, and particularly on the street. The authentic bakso is sold by guys driving a bike-tiny-kitchen assembly. They stop where there are customers and fix you a fine bakso, that you eat on the spot.&lt;/p&gt;

&lt;p&gt;Of course hygiene should be of concern and you would probably prefer a more “posh” place for dining. In reality there is one universal rule: if locals eat that food, it’s safe for you too. To be mentioned, I have never had food poisoning while on Bali.&lt;/p&gt;

&lt;h2 id=&quot;transport-and-traffic&quot;&gt;Transport and traffic&lt;/h2&gt;

&lt;p&gt;Traffic is big and hectic. Few rules apply. For the most part just watch out! People drive bikes, all kinds of bikes. It’s a like a big collection of cute Vespas, Scoopies and not so cute Honda Vario. It’s easy and cheap to rent a bike, if you like extreme driving. Keep in mind that cars are not exactly respectful towards the bike drivers and traffic jams are awful.&lt;/p&gt;

&lt;!--figure tags without plugin: http://stackoverflow.com/questions/19331362/using-an-image-caption-in-markdown-jekyll --&gt;

&lt;figure&gt;
	&lt;a href=&quot;/assets/img/bali/vespa.jpg&quot;&gt;
		&lt;img src=&quot;/assets/img/bali/vespa.jpg&quot; alt=&quot;Vespa bike&quot; /&gt;
	&lt;/a&gt;
&lt;figcaption&gt;
    Vespa bike
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;activities&quot;&gt;Activities&lt;/h2&gt;

&lt;p&gt;It won’t be boring on Bali, trust me. Locals are offering plenty of activities.&lt;/p&gt;

&lt;p&gt;Start with lying on the beach with a good book and get a gorgeous tan. Catch the wave on a surfing board, fall, try again. Go trekking on the top of a volcano. Get a bicycle and visit some nearby villages, buy bakso for it’s real price of 5,000 IDR. Soak in the greenish water of a hot spring. Don’t forget about white water rafting in Ayung River - instructors make it an unbelievably fun experience. Take long walk to discover the blooming nature of Bali. Go to a cooking class and learn some secrets about Bali cuisine. Explore the templates if you feel attracted to the spiritual side of the island. Get fit by taking yoga or traditional dance classes or relax by having an oily Balinese massage. Go diving or snorkeling to special beautiful spots. Join a group of tourists to see the Legong and Kecak dance. I think there is a lot more to this. Once you are there, you will figure it out.&lt;/p&gt;

&lt;h2 id=&quot;goodbye&quot;&gt;Goodbye&lt;/h2&gt;

&lt;p&gt;One last piece of advice: &lt;strong&gt;Live in Bali once, but leave it before it makes you soft.&lt;/strong&gt; And that’s what we did.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2015/01/22/take-me-to-bali/</id>
      <updated>2015-01-22T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Contributing to open source like a boss</title>
      <link href="http://ana-balica.github.io/2015/01/11/contributing-to-open-source-like-a-boss/" />
      <summary type="html">&lt;p&gt;This is a collection of the most obvious, nevertheless overlooked, bullet points
that every contributor should be aware of when making the first contribution
to an open source project.&lt;/p&gt;

&lt;p&gt;I remember my first contribution to
&lt;a href=&quot;http://moinmo.in/&quot;&gt;MoinMoin Wiki Engine&lt;/a&gt; and it was terrible. And I’m not talking about code
(which was probably also pretty bad), but about all the surrounding elements
to an open source contribution. With time you learn how to do it the right the
way.&lt;/p&gt;

&lt;p&gt;Now I find myself in the position of the reviewer and I see tons of
mistakes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/contributing/noobs_everywhere.jpg&quot; alt=&quot;Noobs everywhere&quot; class=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;But it’s OK. I was a noob quite recently and for some projects I am still holding
on to my noob award. Everybody passed through the stage of first contribution.
But once you learn and get comfortable, it’s very false to start assuming that
newcomers should catch on very fast. I think newcomers need help and guidance.
That’s why I figured it’s a good idea to disseminate some of the common rules
of open source world.&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-get-started&quot;&gt;How do I get started?&lt;/h2&gt;

&lt;p&gt;If you made the decision to contribute, don’t go to the organization’s
communication channel and say that out loud. That’s not bad, it’s just useless.
Long term contributors and maintainers are like smart girls dating teenage boys:
they ignore everything boys say and only pay attention to what they do.&lt;/p&gt;

&lt;p&gt;And since you set your mind to contribute, take some time to search for project
documentation and read it. The question &lt;em&gt;How do I get started?&lt;/em&gt; is mostly
irrelevant. I find it kind when people on the channel point out to relevant links
and give short instructions. But… come on! Open source projects’ documentation
is not a hidden treasure chest, it’s out there indexed by Google. Don’t be lazy.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://imgs.xkcd.com/comics/rtfm.png&quot; title=&quot;Life is too short for man pages, but occasionally much too short without them.&quot; alt=&quot;RTFM&quot; class=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Spend at least an hour trying to find relevant developer documentation. It’s
perfectly OK to ask for help if the docs are missing, lacking or misleading. In
fact, if you figured the documentation is not straight-forward, express your
concern and propose a solution. Your feedback will be appreciated if the
community is welcoming.&lt;/p&gt;

&lt;h2 id=&quot;follow-that-guide&quot;&gt;Follow that guide&lt;/h2&gt;

&lt;p&gt;Usually a community that cares about code quality will comply to a code style guide.
This is a very important document, read it carefully. It will teach you about
naming conventions, do’s and don’ts and other recommendations. For example, in
Python world a lot of projects follow &lt;a href=&quot;https://www.python.org/dev/peps/pep-0008&quot;&gt;PEP8&lt;/a&gt; -
if you haven’t seen a style guide, here is what it looks like.&lt;/p&gt;

&lt;p&gt;Pay attention to the tools the community uses. They might prefer one pastebin
over another, have a community-wide wiki, expect people to use a single code
review tool. Follow those recommendations. It makes everybody’s life easier.&lt;/p&gt;

&lt;h2 id=&quot;find-easy-todo&quot;&gt;Find easy TODO&lt;/h2&gt;

&lt;p&gt;Projects usually have a bug tracker, whether it’s a Trac tracker, GitHub issues
or simple wiki page. Doesn’t matter as long as the tracker is up-to-date. Try to
see if they have tickets with &lt;em&gt;easy&lt;/em&gt; tag or something similar. Search for the one you feel most
confident about.&lt;/p&gt;

&lt;p&gt;If you found a bug while using the software, check if it’s being already listed.
If not, report the problem.&lt;/p&gt;

&lt;p&gt;Further express your willingness to work on the ticket: assign it to yourself or
leave a comment - whatever works best. The reason is nobody wants duplicate
work.&lt;/p&gt;

&lt;p&gt;Well, now is your time to shine.&lt;/p&gt;

&lt;h2 id=&quot;branch-that-out&quot;&gt;Branch that out&lt;/h2&gt;

&lt;p&gt;Most probably you will need to create a new feature branch. Holds true for git,
somewhat for mercurial. Name the branch appropriately. Don’t name
it &lt;em&gt;stephen&lt;/em&gt; or &lt;em&gt;my_branch&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Check what is the leading branch for development, might be &lt;em&gt;master&lt;/em&gt; or maybe &lt;em&gt;dev&lt;/em&gt;.
Create the feature branch from the leading development branch. Pull the latests
changes. If the branch was updated while you were working on your feature branch,
rebase your work. It’s so much easier to merge the contributions of others if
their branches contain the latest changes.&lt;/p&gt;

&lt;p&gt;Do this for every feature. It might seem like overhead, but it actually saves
some pain in the future.&lt;/p&gt;

&lt;h2 id=&quot;run-those-tests&quot;&gt;Run those tests&lt;/h2&gt;

&lt;p&gt;After you solved the ticket, take some time to run all the necessary scripts
before committing. Those might be unittests, UI tests, linters. Pay attention
to their output. If the output makes little sense to you, take a step back and
read about the tool to figure out the meaning of the output.&lt;/p&gt;

&lt;p&gt;It’s pretty cool when a project uses a CI (Continuous Integration) tool. It tells
the developers straight away if something is wrong. Thought that doesn’t spare
you and others from submitting clean working code.&lt;/p&gt;

&lt;p&gt;Seriously, run those tests.&lt;/p&gt;

&lt;h2 id=&quot;code-review&quot;&gt;Code review&lt;/h2&gt;

&lt;p&gt;Go back to the docs and search for the section that tells you where and how to
submit code for review.&lt;/p&gt;

&lt;p&gt;There are plenty of code review tools: &lt;a href=&quot;https://code.google.com/p/gerrit/&quot;&gt;Gerrit&lt;/a&gt; ,
&lt;a href=&quot;https://code.google.com/p/rietveld/&quot;&gt;Rietveld&lt;/a&gt;, &lt;a href=&quot;http://phabricator.org/&quot;&gt;Phabricator&lt;/a&gt;,
&lt;a href=&quot;https://help.github.com/articles/using-pull-requests/&quot;&gt;GitHub pull requests&lt;/a&gt;.
So there must be one that community prefers. Before you
put your code on review, check if you are submitting only the relevant pieces,
remove all the debug code, don’t submit sensible information (passwords, keys)
or local user configuration.&lt;/p&gt;

&lt;p&gt;Your code review should contain a title and a description if necessary. Don’t
name it &lt;em&gt;First contribution&lt;/em&gt; or &lt;em&gt;My first pull request please review asap&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And once you did submit the code, go to that link and &lt;strong&gt;review it yourself&lt;/strong&gt;. It’s
hard to emphasize how important is that step. Take a minute or two to scan with
your eyes all the code. You will be surprised to find out that you have slipped
some unwanted code in there or you just found a better solution.&lt;/p&gt;

&lt;h2 id=&quot;pull-request&quot;&gt;Pull request&lt;/h2&gt;

&lt;p&gt;Pull request process can be merged with the code review process. Contributors can
review your code once you make the pull request. Or they might be separate.
Matter of preference.&lt;/p&gt;

&lt;p&gt;Repeating myself, but clean title, description, commit messages are important.
Refer to the ticket in commit message or pull request title if it’s necessary.&lt;/p&gt;

&lt;p&gt;Limit a pull request to one to 3 commits. Don’t overload code reviews and pull
requests with tons of code. It’s almost impossible to review big chunks of code.
A method, a function, a small class, some bugfixing - OK. Class with 10 methods,
extra 5 templates with controllers and routes - not OK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewing isn’t easy&lt;/strong&gt;. It takes quite some time and the reviewer holds same
responsibility for your code as you do, since he or she  decides to accept or
discard your contribution.&lt;/p&gt;

&lt;p&gt;Keep it short. Keep it simple. And people will love it.&lt;/p&gt;

&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h2&gt;

&lt;p&gt;It’s OK to make mistakes, as long as we acknowledge and fix them. The rules we
have imposed on ourselves help keep the codebase readable and maintainable, hence
ensure the longevity and popularity of the project. Comply to this set of rules
and, boy, you’re gonna become a pleasant person
to work with.&lt;/p&gt;

&lt;p&gt;Open source is a good place to learn from others. Don’t miss that opportunity.
Appreciate the feedback.&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2015/01/11/contributing-to-open-source-like-a-boss/</id>
      <updated>2015-01-11T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Systers Portal</title>
      <link href="http://ana-balica.github.io/2014/11/11/systers-portal/" />
      <summary type="html">&lt;p&gt;Today I was listening to &lt;a href=&quot;http://www.programmingthrowdown.com/2014/09/episode-36-swift.html&quot;&gt;Swift&lt;/a&gt;
episode by &lt;em&gt;Programming Throwdown&lt;/em&gt; podcast
series. At some point hosts raise the question of open source involvement. You probably
also received this piece of advice:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you want to get your hands on some programming as a beginner or a recent
graduate, try doing some open source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is rather vague.
What most people skip saying is what kind of open source work should you start with. Hosts
of the show point out the fact that it’s not necessary to jump right into big
popular projects, like Linux Kernel or PostgreSQL, simply because it will take tons
of time to read and understand the existing codebase and get your patch accepted by
the core maintainers. So the solution is to seek for a small open source
project, that involves a technology you like or want to get better at it, preferably
with few developers involved.&lt;/p&gt;

&lt;p&gt;Systers Portal is one of those one-man-show projects, that might suit very well
the open source beginners.&lt;/p&gt;

&lt;h2 id=&quot;what-is-that&quot;&gt;What is that?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://systers.org/&quot;&gt;Systers&lt;/a&gt; is the world’s largest email community of women
in technical roles in computing. It is indeed huge and covers a lot of technical
areas. It started as a small mailing list and grew to 4,000
members from all over the world. Considering the modern needs, a single mailing list
isn’t very nifty to manage such a huge community.&lt;/p&gt;

&lt;p&gt;Hence the idea of a portal came up. Systers Portal is a unified platform for
Systers and its sub-groups to share information and get the latest news. This is
a place to manage sub-communities, latest news, interesting and useful
resources, community members.&lt;/p&gt;

&lt;p&gt;Systers Portal was started in summer 2014 as a
&lt;a href=&quot;http://www.google-melange.com/gsoc/homepage/google/gsoc2014&quot;&gt;Google Summer of Code&lt;/a&gt;
project involving two students: me and &lt;a href=&quot;in.linkedin.com/pub/chitra-khatwani/39/763/6b1&quot;&gt;Chitra Khatwani&lt;/a&gt;,
under the mentorship of &lt;a href=&quot;http://www.roguelynn.com/&quot;&gt;Lynn Root&lt;/a&gt;,
&lt;a href=&quot;http://www.rosariorobinson.com/&quot;&gt;Rosario Robinson&lt;/a&gt;, Promita Bose and Laura Cassell. We launched a prototype,
hosted on &lt;a href=&quot;http://portal.systers.org/&quot;&gt;portal.systers.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: the prototype hosted on &lt;a href=&quot;http://portal.systers.org/&quot;&gt;portal.systers.org&lt;/a&gt;
isn’t going to match exactly your development version from the official repository. The
development version incrementally adds features present in the prototype.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;reasons&quot;&gt;Reasons&lt;/h2&gt;

&lt;p&gt;Here are some of the obvious reasons why Systers Portal is so good for you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It is a Django project, build using best practices and techniques, with
readability and maintainability in mind. We try to keep up with the latest
releases, hence we are using Django 1.7 with a set of up-to-date packages.&lt;/li&gt;
  &lt;li&gt;We are strict about styleguides and code readability. You will learn fast
about one of my favorite Python mantras, called &lt;a href=&quot;https://www.python.org/dev/peps/pep-0008&quot;&gt;PEP8&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;We have &lt;a href=&quot;https://coveralls.io/r/systers/portal?branch=master&quot;&gt;100% code coverage&lt;/a&gt;
and care about unittests.&lt;/li&gt;
  &lt;li&gt;We are hosted on &lt;a href=&quot;https://github.com/systers/portal&quot;&gt;GitHub&lt;/a&gt;, ready to be
forked and accepting pull requests.&lt;/li&gt;
  &lt;li&gt;We have &lt;a href=&quot;http://systers-portal.readthedocs.org/en/latest/&quot;&gt;documentation&lt;/a&gt;.
Particularly documentation how to get started, what should you know before
getting down to code, how to run the project locally. The
&lt;a href=&quot;http://systers-portal.readthedocs.org/en/latest/develop/contributing.html&quot;&gt;First Contribution&lt;/a&gt;
article will drive you through all the necessary steps to make your first
contribution to Systers Portal. The code contains helpful docstrings as well.&lt;/li&gt;
  &lt;li&gt;There is currently one developer working on Portal - it’s me. It is generally
easier to read a single mind expressed in code, than a whole bunch. This
doesn’t imply that the code is always obvious and clear. Particularly
every time I review old pieces of code, I rewrite something. I need your
help to see the errors and solutions.&lt;/li&gt;
  &lt;li&gt;We have a list of &lt;a href=&quot;http://systers.org/systers-dev/doku.php/gci14systers:portal&quot;&gt;easy TODOs&lt;/a&gt;
(initially created for Google Code-in).&lt;/li&gt;
  &lt;li&gt;By contributing to Systers Portal, you will help women from technical fields
to enjoy a friendly environment via a unified portal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;links-links-links&quot;&gt;Links! Links! Links!&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;GitHub repo - &lt;a href=&quot;https://github.com/systers/portal&quot;&gt;github.com/systers/portal&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Documentation - &lt;a href=&quot;http://systers-portal.readthedocs.org/&quot;&gt;systers-portal.readthedocs.org&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Systers Portal prototype - &lt;a href=&quot;http://portal.systers.org/&quot;&gt;portal.systers.org&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;About Systers - &lt;a href=&quot;http://systers.org/&quot;&gt;systers.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</summary>
      <id>http://ana-balica.github.io/2014/11/11/systers-portal/</id>
      <updated>2014-11-11T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>The tale of DRY with django-crispy-forms</title>
      <link href="http://ana-balica.github.io/2014/11/04/the-tale-of-dry-with-django-crispy-forms/" />
      <summary type="html">&lt;p&gt;So you have this Django app. If you are like me and don’t have quite the skills
for a good UI design, you probably stick to
&lt;a href=&quot;http://getbootstrap.com/&quot;&gt;bootstrap&lt;/a&gt;. You know you will have a bunch of forms
and you don’t want to style them yourself. Let’s say, you came to the idea that
&lt;a href=&quot;http://django-crispy-forms.rtfd.org&quot;&gt;django-crispy-forms&lt;/a&gt; fits your needs
perfectly (it definitely fits mine).&lt;/p&gt;

&lt;h2 id=&quot;how-it-all-began&quot;&gt;How it all began&lt;/h2&gt;

&lt;p&gt;This is a story about a model &lt;em&gt;Foo&lt;/em&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/characters/models.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;A magical creature from Foo dynasty&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mighty_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;kingdoms_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PositiveIntegerField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EmailField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# What? Magical creatures also have emails.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Model &lt;em&gt;Foo&lt;/em&gt; was lonely, so it summoned a view, a template and a url.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/characters/views.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.views.generic.edit&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateView&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;characters.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CreateFooView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CreateView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;A create view for Foo model&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;template_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;characters/create_foo.html&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;# fairytale/templates/characters/create_foo.html
{% extends &quot;base.html&quot; %}

{% load crispy_forms_tags %}
{% block content %}
  &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;row&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;col-md-6&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;h1&amp;gt;&lt;/span&gt;Create Foo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;hr/&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;well&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        {% crispy form %}
      &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;/div&amp;gt;&lt;/span&gt;
{% endblock %}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base.html&lt;/code&gt; contents are left out, as they include standard HTML markup,
bootstrap stylesheet include and a mandatory template block &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content&lt;/code&gt; (in our
specific case).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/fairytale/urls.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.conf.urls&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;characters.views&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateFooView&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;^foo/create/$&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateFooView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;create_foo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And this is what we created so far:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/dry-tale/create_form_no_submit.png&quot; alt=&quot;Foo form without submit&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Such cool, right?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/dry-tale/doge-meme.jpg&quot; alt=&quot;Doge Django meme&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Oh, wait! Where are the buttons? How do I submit this thing? &lt;em&gt;Foo the Emperor&lt;/em&gt;
must live!&lt;/p&gt;

&lt;p&gt;Ok, I will need a &lt;em&gt;Cancel&lt;/em&gt; anchor tag that will look like a button, because I
want to redirect to some other page, and a &lt;em&gt;Submit&lt;/em&gt; input. Easy!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/characters/forms.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.helper&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.layout&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.bootstrap&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormActions&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;characters.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FooForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Model Foo form&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FooForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;FormActions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;&amp;lt;a role=&quot;button&quot; class=&quot;btn btn-default&quot;
                        href=&quot;{% url &quot;some_cancel_url&quot; %}&quot;&amp;gt;Cancel&amp;lt;/a&amp;gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;save&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Submit&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Meh, not the prettiest way to achieve what I want, but apparently this is the
only easy and straight-forward way. Also don’t forget to update the view.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/characters/views.py
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ifrom&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;django&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edit&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;CreateView&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;characters.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CreateFooView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CreateView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;A create view for Foo model&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;template_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;characters/create_foo.html&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;form_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FooForm&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# the change is over here
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And so this is what we get:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/dry-tale/create_form_with_submit.png&quot; alt=&quot;Foo form with submit&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The lack of space between the anchor tag and the input looks awful, right? This
tiny cosmetic issue was discussed in
&lt;a href=&quot;https://github.com/maraujop/django-crispy-forms/issues/62&quot;&gt;issue #62&lt;/a&gt; and
solved for groups of buttons and inputs. Unfortunately it persists in case of
an input/button and anchor tag with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;role=&quot;button&quot;&lt;/code&gt;. If it’s bugging you, add
some margin by yourself.&lt;/p&gt;

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

&lt;p&gt;Life goes on and &lt;em&gt;Foo&lt;/em&gt; objects seem to be doing just fine. Until a great misfortune
takes over their destiny. It doesn’t seem like a big deal, since all that
happened was the addition of two more characters: &lt;em&gt;Bar&lt;/em&gt; and &lt;em&gt;Baz&lt;/em&gt;. What harm
can they potentially cause? Well, let’s see.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bar&lt;/em&gt; and &lt;em&gt;Baz&lt;/em&gt; follow the same old path &lt;em&gt;Foo&lt;/em&gt; did a long time ago:
model/form/view/template/url. The form again will initialize a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FormHelper&lt;/code&gt; to
append those 2 elements. It seems like every form will need them (like duhh, how
can I get around the form without them?). And so we copy-pasty, we copy-paste.&lt;/p&gt;

&lt;p&gt;And then the pressure of the invisible monster can be felt, crawling under the
skin and whispering to you: “You will do this over and over again. For every
form. And when you will want to change a tiny detail, you will change it for
every form, because you want to stay consistent. That can be the change in the
bootstrap anchor tag interface, class of the &lt;em&gt;Submit&lt;/em&gt; input, text of the anchor
tag.”&lt;/p&gt;

&lt;p&gt;This is the punishment for the violation of DRY (Don’t Repeat Yourself)
principle.&lt;/p&gt;

&lt;p&gt;It’s not too late to fix the situation, until the quicksand doesn’t devour
all the codebase into the abyss of “refactoring is too expensive for us”.&lt;/p&gt;

&lt;h2 id=&quot;layout-objects-to-the-rescue&quot;&gt;Layout objects to the rescue&lt;/h2&gt;

&lt;p&gt;At first, it seems like a good idea to use
&lt;a href=&quot;http://django-crispy-forms.readthedocs.org/en/latest/layouts.html#composing-layouts&quot;&gt;Composing layouts&lt;/a&gt;.
We take that chunk of layout and simply store it into a variable somewhere. But
how can we change that &lt;em&gt;Cancel&lt;/em&gt; URL? Or maybe we plan to have different input
values for &lt;em&gt;submit&lt;/em&gt; input for different forms. There might be several variables
that we would like to keep flexible for a more or less fixed piece of layout.&lt;/p&gt;

&lt;p&gt;One of the solutions is to create our own custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObjectLayout&lt;/code&gt;. It involves a
little bit of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django-crispy-forms&lt;/code&gt; internals, but don’t worry, I’m here to
help.&lt;/p&gt;

&lt;p&gt;This is where we start from -
&lt;a href=&quot;http://django-crispy-forms.readthedocs.org/en/latest/layouts.html#creating-your-own-layout-objects&quot;&gt;creating your own layout objects&lt;/a&gt;.
As it says in the current section, we investigate the objects that live in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;layout.py&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.py&lt;/code&gt;. We come up with the following cure for the
misfortune:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/common/crispy_forms/bootstrap.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.bootstrap&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormActions&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.layout&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LayoutObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SubmitCancelFormActions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LayoutObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Custom bootstrap layout object. It wraps a Cancel anchor tag and a Submit
    input field in a &amp;lt;div class=&quot;form-actions&quot;&amp;gt;.

    Example::

        SubmitCancelFormActions(cancel_href=&quot;/some/url/&quot;)
    &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cancel_href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;cancel_href&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;#&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form_style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;layout_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormActions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;&amp;lt;a role=&quot;button&quot; class=&quot;btn btn-default&quot; href=&quot;{0}&quot;&amp;gt;
                    Cancel&amp;lt;/a&amp;gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cancel_href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;save&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Submit&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layout_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form_style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__&lt;/code&gt; we extract all the arguments we are interested in, for example
the URL of the &lt;em&gt;Cancel&lt;/em&gt; anchor tag. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;render&lt;/code&gt; method produces the HTML string
with all the nodes translated. There is no need to create our own template to be
rendered, since we can reuse &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;render&lt;/code&gt; method provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django-crispy-forms&lt;/code&gt;.
It already knows how to translate all those objects we have put together, to plain
HTML.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/characters/forms.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.helper&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;characters.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;common.crispy_forms.bootstrap&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SubmitCancelFormActions&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FooForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Model Foo form&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FooForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;SubmitCancelFormActions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cancel_href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{% url &apos;some_cancel_url&apos; %}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Maybe it doesn’t seem like a big deal, saves us maybe 2 lines of code in the
form and adds up lots of code some place else. As the monster warned us, the
real danger comes with the growth of objects and forms in number. At some point
it will become much more complicated to make any changes to those form actions.
It is a small enhancement that might save time for future &lt;em&gt;me&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Alright, that looks much better. Both for &lt;em&gt;Foo&lt;/em&gt;, &lt;em&gt;Bar&lt;/em&gt; and &lt;em&gt;Baz&lt;/em&gt;. Oh, and don’t
forget about unittest, otherwise another monster will come to bite your ass.&lt;/p&gt;

&lt;p&gt;Let’s see how can we write a unittest for our little layout object. I will
cheat a bit and use some test tools and shortcuts created specifically for
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django-crispy-forms&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# fairytale/common/tests.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.template&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.test&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestCase&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.tests.forms&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestForm&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.helper&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;crispy_forms.layout&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Layout&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;common.forms.bootstrap&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SubmitCancelFormActions&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FormLayoutObjectsTestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_submit_cancel_form_actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;Test custom SubmitCancelFormActions bootstrap layout object&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_template_from_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
            {% load crispy_forms_tags %}
            {% crispy form %}
        &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;test_form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;test_form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FormHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;test_form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;SubmitCancelFormActions&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;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;form&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;class=&quot;form-actions&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;role=&quot;button&quot;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;href=&quot;#&quot;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Cancel&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Submit&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;test_form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;helper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Layout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;SubmitCancelFormActions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cancel_href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/some/url/&quot;&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;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;form&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assertEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;href=&quot;/some/url/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the unittest we render the form with the custom layout object
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubmitCancelFormActions&lt;/code&gt; and check for some keywords if present in the rendered
HTML.&lt;/p&gt;

&lt;h2 id=&quot;happy-ending&quot;&gt;Happy ending&lt;/h2&gt;

&lt;p&gt;That’s all folks! Keep DRY and write unittests!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;P.S. In case you are still in doubt about the provided solution, here is what
&lt;a href=&quot;http://pydanny.com/&quot;&gt;Daniel Greenfeld&lt;/a&gt; says: “As one of the leads of
django-crispy-forms, I approve this blog post. :-)”&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;See &lt;a href=&quot;/2015/03/18/the-tale-of-dry-with-django-crispy-forms-part-2/&quot;&gt;The tale of DRY with django-crispy-forms | Part II&lt;/a&gt;
for a better solution, if you wanna to go an extra mile.&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2014/11/04/the-tale-of-dry-with-django-crispy-forms/</id>
      <updated>2014-11-04T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Erasmus FAQ</title>
      <link href="http://ana-balica.github.io/2014/10/27/erasmus-faq/" />
      <summary type="html">&lt;p&gt;I see a lot of interest from students towards going on Erasmus. Their excitement
is understandable, nevertheless students tend to rely heavily on other’s
experience and ask same questions all over again (rather than reading piles of
information on official websites). Hence I have decided to collect all those
questions by creating this FAQ. The questions are not grouped anyhow and are not
in any specific order.&lt;/p&gt;

&lt;h2 id=&quot;1-how-many-credits-are-required-to-finish-one-semester-of-erasmus-program&quot;&gt;1. How many credits are required to finish one semester of Erasmus program?&lt;/h2&gt;

&lt;p&gt;In the official “Learning Agreement” you will see that each student is expected
to collect 30 credits per semester. In reality you can have less, but still a
fair amount of courses and credits. At the Czech Technical University we were
given the following numbers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;more than 27 – you got the perfect score&lt;/li&gt;
  &lt;li&gt;23 - 27 – that’s a good result&lt;/li&gt;
  &lt;li&gt;17 - 23 – fair, but you could have done better&lt;/li&gt;
  &lt;li&gt;less than 17 – you might get kicked out of the program&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The numbers are extracted from memory, so expect some delta error. Don’t risk
and try to get all the credits you can.&lt;/p&gt;

&lt;h2 id=&quot;2-what-is-the-case-if-you-are-on-erasmus-during-your-last-semester-can-you-include-the-thesis-credits-as-well&quot;&gt;2. What is the case if you are on Erasmus during your last semester? Can you include the thesis credits as well?&lt;/h2&gt;

&lt;p&gt;I believe this is something university specific, but I can tell about my
experience at Czech Technical University. The credits are bound to courses,
therefore there are some “Bachelor/Master Thesis” courses. Before being able to
take the course, you, as a student, should find a mentor – the guide-teacher
that will help you with your thesis and will give you the credits by the end of
the semester. Considering this, it is a good idea to spend one semester before
your last thesis-semester at the host university. If you have the topic or the
field of study you want to work in, it will be easy to spot the right mentor.
Approach the teacher and explain what you are expecting from him as a mentor,
what are your responsibilities towards the home and host university. Most
probably it will work out ok.&lt;/p&gt;

&lt;h2 id=&quot;3-do-you-need-to-find-mentor-before-going-or-you-can-do-so-later&quot;&gt;3. Do you need to find mentor before going or you can do so later?&lt;/h2&gt;

&lt;p&gt;It is perfectly ok to find the mentor on the spot. Nobody expects you to email
dozens of teachers and find a mentor blindfolded.&lt;/p&gt;

&lt;h2 id=&quot;4-where-to-start-research-on-your-options&quot;&gt;4. Where to start research on your options?&lt;/h2&gt;

&lt;p&gt;I know at least 2 resources - &lt;a href=&quot;http://ewent.meil.pw.edu.pl/&quot;&gt;EWENT&lt;/a&gt; and
&lt;a href=&quot;http://active.meil.pw.edu.pl/&quot;&gt;ACTIVE&lt;/a&gt;. I’ve got not idea why there are 2
programs at the same time and what is the difference between them. Both websites
contains clear information about the partner universities, coordinators,
courses, scholarships. It will take probably an hour to read everything.&lt;/p&gt;

&lt;h2 id=&quot;5-in-order-to-become-an-exchange-student-my-home-university-should-have-parter-relationships-with-other-universities-the-ones-listed-on-the-website-are-those-the-only-parter-universities&quot;&gt;5. In order to become an exchange student, my home university should have parter relationships with other universities (the ones listed on the website)? Are those the only parter universities?&lt;/h2&gt;

&lt;p&gt;Yes. You can go on Erasmus only to the universities listed on website. There are
7-8 partner European universities (depending on the program) and if any other
join the program, they will be listed there most probably.&lt;/p&gt;

&lt;h2 id=&quot;6-is-it-necessary-that-technical-university-of-moldova-endorses-me&quot;&gt;6. Is it necessary that Technical University of Moldova endorses me?&lt;/h2&gt;

&lt;p&gt;No. Home university will provide a certificate to confirm the fact that
you are their student. And that’s all.&lt;/p&gt;

&lt;h2 id=&quot;7-with-a-average-mark-of-almost-9-do-i-have-any-chances&quot;&gt;7. With a average mark of almost 9, do I have any chances?&lt;/h2&gt;

&lt;p&gt;It’s hard to know what are the selection criteria. I might assume that
university record is important, along with extracurricular activities,
involvement in a variety of projects and a good motivational letter.&lt;/p&gt;

&lt;h2 id=&quot;8-so-how-was-your-erasmus&quot;&gt;8. So how was your Erasmus?&lt;/h2&gt;

&lt;p&gt;It is definitely a good experience. I have plenty of good memories. I have
managed to make good friends, live in one of the most beautiful cities of
Europe, see student-friendly environment created to facilitate studies and
teamwork.&lt;/p&gt;

&lt;p&gt;At times it was not easy, due to the temptation of traveling and exploring,
instead of studying. But it all can be balanced well with the proper discipline.&lt;/p&gt;

&lt;h2 id=&quot;9-did-you-write-your-thesis-at-host-university&quot;&gt;9. Did you write your thesis at host university?&lt;/h2&gt;

&lt;p&gt;Yes. The core part. Some sections, bugfixes, formatting were done by the end of
the semester, when I came back to Moldova to prepare to defend the thesis.&lt;/p&gt;

&lt;h2 id=&quot;10-how-did-you-find-the-study-program-compared-to-the-one-from-technical-university-of-moldova-did-the-complexity-level-grow-exponentially&quot;&gt;10. How did you find the study program compared to the one from Technical University of Moldova? Did the complexity level grow exponentially?&lt;/h2&gt;

&lt;p&gt;I would say the study programs are comparable. I didn’t find any difficulty to
pass my courses. But I know some of the courses that are extremely complicated
to pass at Czech Technical University and require a lot of hard work. If you
find the course interesting and important to you nevertheless, you can give it a
try at least.&lt;/p&gt;

&lt;p&gt;I met some excellent professors at Technical University of Moldova. I was less
inspired by Czech Technical University professors. But it’s understandable, since
I have spend there only one year and generally, teachers invest less effort in
Erasmus students than in regular students.&lt;/p&gt;

&lt;h2 id=&quot;11-do-i-need-toefl-or-is-it-ok-to-just-pass-an-exam-at-the-university&quot;&gt;11. Do I need TOEFL? Or is it ok to just pass an exam at the university?&lt;/h2&gt;

&lt;p&gt;In case TOEFL is required, it will be stated so in host university information. For
example, Dublin Institude of Technology accepts applications only from students
who have TOEFL certificate.&lt;/p&gt;

&lt;p&gt;I have no information about the English university exam though. Since I was
doing my studies at FAF (English Taught Honors Program in “Computer Science”),
we were given automatically a certificate from TUM.&lt;/p&gt;

&lt;h2 id=&quot;12-can-you-choose-where-collegeuniversity-to-apply-or-are-you-distributed&quot;&gt;12. Can you choose where (college/university) to apply or are you distributed?&lt;/h2&gt;

&lt;p&gt;You can choose up to 3 partner universities, where you would like to go. The
motivational letter respectively should be addressed to all of them. Eventually
you will be selected to one of the universities you have listed.&lt;/p&gt;

&lt;h2 id=&quot;13-can-you-go-to-phd-directly-or-you-need-to-do-masters-first&quot;&gt;13. Can you go to PhD directly or you need to do Masters first?&lt;/h2&gt;

&lt;p&gt;If you can convince our home university to get enrolled into a PhD program
without graduate studies, then yes. But generally that is very unlikely. According
to study specifications, one should have the prerequisites, before going
any further (Bachelor – Masters – PhD).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This is it. I hope I cleared out some questions for you. Next application process
starts on November 1st 2014, so start your application now and good luck :)&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2014/10/27/erasmus-faq/</id>
      <updated>2014-10-27T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Developers at Eco Village</title>
      <link href="http://ana-balica.github.io/2014/09/21/developers-at-eco-village/" />
      <summary type="html">&lt;p&gt;&lt;a href=&quot;http://eco-village.md/&quot;&gt;Eco Village&lt;/a&gt; supports the idea that sustainable lifestyle can be revived in rural area of Moldova with the effort of the community. It’s also an NGO and a great bunch of people.&lt;/p&gt;

&lt;p&gt;It’s pretty cool how people with strong vision can make things happen. At the moment on the edge of &lt;a href=&quot;https://goo.gl/maps/RHLTt&quot;&gt;Rascova village&lt;/a&gt; a big construction site is in action. There are regular workers and volunteers. There is a in-progress building for cohousing (concept that describes how groups of people decide to live next to each other, sharing some of the common space), training center for local community, meditation center and other adjacent constructions. Along with the Eco Village, the founders of the project are offering a house for volunteers, who want to stay more than one day.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/eco-village/eco-village-3.jpg&quot; alt=&quot;Eco Village 1&quot; /&gt;
&lt;img src=&quot;/assets/img/eco-village/eco-village-1.jpg&quot; alt=&quot;Eco Village 1&quot; /&gt;
&lt;img src=&quot;/assets/img/eco-village/eco-village-2.jpg&quot; alt=&quot;Eco Village 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I have found out about Eco Village accidentally, right during the time I was searching for a rent in a village. This is not an easy task to accomplish, since apparently nobody thinks that some youngsters would like to come over. Therefore there are no postings about renting property outside of the urban area.&lt;/p&gt;

&lt;p&gt;And so 2 developers took their backpacks and winter coats in early September to go to Eco Village. We have spent 4 days being welcomed by the hosts of the volunteer house. The everyday routine included biking, some work on site and coding. During those days we were interested in finding the perfect combination for building earth blocks. Earth blocks are a mixture of clay, soil and other supplements, compressed and left to dry. They are a pretty nice alternative to bricks, earth blocks being environmentally friendly, non-toxic and much cheaper. I imagine getting back after a year and seeing what was build out of those.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/eco-village/eco-village-5.jpg&quot; alt=&quot;Eco Village 1&quot; /&gt;
&lt;img src=&quot;/assets/img/eco-village/eco-village-4.jpg&quot; alt=&quot;Eco Village 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Overall it was nice to get out from the city for a while and find a peaceful place to stay. We are thankful for the people who gave us the opportunity and are wishing good luck to Eco Village&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2014/09/21/developers-at-eco-village/</id>
      <updated>2014-09-21T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Python Moldova Meetup #3</title>
      <link href="http://ana-balica.github.io/2014/09/08/python-moldova-meetup-3/" />
      <summary type="html">&lt;p&gt;Quite recently we organized our third Python Moldova Meetup. We also have updated the official Python wiki page and added &lt;a href=&quot;https://wiki.python.org/moin/LocalUserGroups#Moldova&quot;&gt;Python Moldova&lt;/a&gt; to the list. Meanwhile &lt;a href=&quot;https://www.facebook.com/groups/pymoldova/&quot;&gt;Python Moldova Community&lt;/a&gt; exists over a year and counts 154 members at the moment. Though the number of members vaguely defines the Python involvement rate in Moldova.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pymeetup3/pymeetup_2.JPG&quot; alt=&quot;Python Moldova Meetup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We didn’t grow yet to give any pseudo-official talks with prepared presentation and extra 5 minutes for questions from the audience. At the moment it’s easier to get people out for a drink in a pub. We were lucky to find a quiet public place during the weekend, where we could discuss different Python-related topics.&lt;/p&gt;

&lt;p&gt;At first, we debated over pros and cons of adapting Python as the main programming language for Informatics course in schools. Apparently not every country has Informatics as a mandatory course in their curriculum. Moldova does. So far we had Basic Pascal. From a specific point of view, it might not be necessary to change the language – learning programming is not about the syntax. But… but… &lt;a href=&quot;http://cacm.acm.org/blogs/blog-cacm/176450-python-is-now-the-most-popular-introductory-teaching-language-at-top-us-universities/fulltext&quot;&gt;it’s so trendy to have Python in schools&lt;/a&gt;. In the end we compiled a list of advantages to use Python as introductory language in schools: REPL, clean syntax, indentation as language feature, good standard library, &lt;a href=&quot;https://www.pythonanywhere.com/&quot;&gt;online IDEs for Python&lt;/a&gt;, gaming libraries. I assume the decision will be taken in about a year. I would like to see kids playing around with Python in schools.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pymeetup3/pymeetup_3.JPG&quot; alt=&quot;Python Moldova Meetup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We did our small improvised &lt;a href=&quot;http://doughellmann.com/&quot;&gt;Python Module of the Week&lt;/a&gt; with an accent on “tools that changed my life”, agreed on the fact that there are no popular podcasts about Python, talked about females in programming world. The gender question in CS is always acute due to the difficulty of balancing between encouraging females and not discouraging males. None of the present males at the meeting, who were the big majority, expressed any discomfort or annoyance while working with females in IT.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/pymeetup3/pymeetup_1.JPG&quot; alt=&quot;Python Moldova Meetup&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Overall it was a nice outing with smart people. To everybody who joined us, I am glad you were there. To everybody who didn’t, you owe us a presentation for the next meetup :P&lt;/p&gt;

&lt;p&gt;P.S. All pictures are kindly provided by Ilona Sergheevna, reporter and wannabe programmer who joined us at Python Moldova Meetup.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2014/09/08/python-moldova-meetup-3/</id>
      <updated>2014-09-08T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Buda and Pest</title>
      <link href="http://ana-balica.github.io/2014/07/05/buda-and-pest/" />
      <summary type="html">&lt;p&gt;Every time going on vacation to some new place I am telling myself to not look into any guides and follow my intuition. I want to be amazed and surprised by what I see and preferable have zero expectations. That doesn’t work always, because you start getting this feeling that you are simply passing by old buildings, monuments, squares and having no idea what and why they are here. A piece of history or a legend helps to grasp the beauty of the place. Too bad for my trip to Budapest I didn’t research on any of that. At least kept my WOW moment.&lt;/p&gt;

&lt;p&gt;After a sever-hour drive from Prague, we are finally in Budapest – considered by many of the most delightful cities in Europe. Mainstream is so cool that I couldn’t resist the urge to see it myself. I lied, it just happened that we ended up on our weekend in Budapest.&lt;/p&gt;

&lt;h2 id=&quot;baths&quot;&gt;Baths&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/baths.jpg&quot; alt=&quot;Szechenyi Baths&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I usually say don’t go where all the tourists go, but not in this case. Natural thermal baths are simply amazing. As if you are swimming and having fun in a museum. We have been to &lt;a href=&quot;http://www.szechenyifurdo.hu/&quot;&gt;Szechenyi&lt;/a&gt;. Wikipedia says it’s the largest medicinal bath in Europe – good to know. Szechenyi has outdoor and indoor pools, saunas, steam rooms, whirlpool, streams to massage your neck, feet and ass. Probably there is much more, but I didn’t bother hoping from one pool to another, so I simply enjoyed sunbathing outside.&lt;/p&gt;

&lt;h2 id=&quot;landmarks&quot;&gt;Landmarks&lt;/h2&gt;

&lt;p&gt;Be a tourist till the end and go take tons of pictures by the Budapest &lt;a href=&quot;http://www.parlament.hu/&quot;&gt;Parliament&lt;/a&gt;. This building is huge, I mean it. I haven’t been inside, but was told very little can be seen and is not worth the money. Don’t forget to check on the monuments around, &lt;a href=&quot;http://micro.neprajz.hu/&quot;&gt;Museum of Ethnography&lt;/a&gt;, a bunch of statues and the rocky beach by the Danube river.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/parliament.jpg&quot; alt=&quot;Budapest Parliament&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/etnography.jpg&quot; alt=&quot;Museum of Etnography&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Across the river you can see the &lt;a href=&quot;http://en.wikipedia.org/wiki/Buda_Castle&quot;&gt;Buda Castle&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Matthias_Church&quot;&gt;Matthias Church&lt;/a&gt; and &lt;a href=&quot;http://www.fishermansbastion.com/&quot;&gt;Fisherman’s Bastion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/bastion.jpg&quot; alt=&quot;Fisherman&apos;s Bastion&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Not far from Szechenyi baths you can see &lt;a href=&quot;http://en.wikipedia.org/wiki/H%C5%91s%C3%B6k_tere&quot;&gt;Heroes’ Square&lt;/a&gt;, the Timewheel and &lt;a href=&quot;http://www.vajdahunyadcastle.com/&quot;&gt;Vajdahunyad Castle&lt;/a&gt;. Pack them up together in one sightseeing tour. The story with Vajdahunyad Castle is curious – it was built to celebrate 1000 years since the Hungarian conquest of the Carpathian Basin. Was made initially in cardboard and wood, afterwards being rebuilt in brick and stone. Different perspectives on history start to pop up when you travel to your neighborhood countries.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/castle.jpg&quot; alt=&quot;Vajdahunyad Castle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/timewheel.jpg&quot; alt=&quot;Timewheel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;St. Stephen’s Basilica keeps up with the majestic atmosphere of the city. Go up if you want to see the city from the top, because it is one of the two tallest buildings in Budapest and no other building is allowed to overcome its height of 96 meters.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/stephen_church.jpg&quot; alt=&quot;St. Stephen&apos;s Basilica&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Even though I am not particularly interested in those landmarks and have very little knowledge about their architectural or historical importance, I like the atmosphere that they create and the fact that in 2 days I have walked 47,000 steps, around 34 km and climbed 90 floors to see just a tiny portion of the city.&lt;/p&gt;

&lt;h2 id=&quot;parapark&quot;&gt;Parapark&lt;/h2&gt;

&lt;p&gt;Now about the cool stuff. &lt;a href=&quot;http://parapark.hu/&quot;&gt;Parapark&lt;/a&gt; is a game where you descent with your friends into a basement to crack some code, solve puzzles and reveal the mysteries. It is the classical doors puzzle game with real locks, keys, basement heavy smell, creepy background sounds and Xubuntu installed on an in-game PC. Go to their website and book a last minute game.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/parapark1.jpg&quot; alt=&quot;Parapark&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/parapark2.jpg&quot; alt=&quot;Parapark game&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We had a team of 3 and it was perfect. While having the most incredible team, we still didn’t solve the mystery in 60 minutes, but we were close. Nevertheless our guide was kind enough to allow us to finish the game. My hands were dirty from all the dust around, we were sweating running around trying to fit a code to a safe, I was struggling to understand the walkie-talkie accent and it was awesome!&lt;/p&gt;

&lt;h2 id=&quot;cat-cafe-budapest&quot;&gt;Cat Cafe Budapest&lt;/h2&gt;

&lt;p&gt;Few cities in Europe have cat cafes and Budapest is one of them. &lt;a href=&quot;http://catcafebudapest.hu/&quot;&gt;Cat Cafe Budapest&lt;/a&gt; is an adorable place with about 8-10 cats lying around, waiting to be pet by you, curiously inspecting the insides of your bag. There is a big lion-like cat, a newbie in the house, a grey elegant cat, long-haired pitch-black cat – for all tastes. The owner of the place is a very nice man, who sincerely loves all of his cats and high-fives with them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/cat1.jpg&quot; alt=&quot;Curious cat&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/cat2.jpg&quot; alt=&quot;Cats&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;musical-fountain&quot;&gt;Musical fountain&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.google.com/maps/place/Margaret+Island/@47.5268881,19.0483968,14z/data=!3m1!4b1!4m2!3m1!1s0x4741dbfc77cfaad7:0x689f7bae3aa650fd&quot;&gt;Margaret island&lt;/a&gt;, where Sziget Festival takes place, has a fun fountain. Go there in the evening at 9PM to enjoy music and lights. It gave me goose bumps listening to Verdi accompanied by the spectacular water show. It is not a world wonder, but it is a nice place to meet the sunset.&lt;/p&gt;

&lt;h2 id=&quot;small-pleasures&quot;&gt;Small pleasures&lt;/h2&gt;

&lt;p&gt;They make your trip memorable. Like a gigantic ice-cream that you can buy at &lt;a href=&quot;https://www.google.com/maps/preview?q=oktogon&amp;amp;ie=UTF-8&amp;amp;hq=&amp;amp;hnear=0x4741dc6e79d6f8a3:0x73cb72000feaf437,Budapest,+Oktogon,+Hungary&amp;amp;ei=DwK3U57-B-bI0QX0q4C4Dg&amp;amp;ved=0CLgBEPIBMA8&quot;&gt;Oktogon intersection&lt;/a&gt;, old metro line of Budapest that resembles a way to hell, fun Erasmus people riding a beer bike, top of a fake boat and sinking Greek arc by the National Theater, big number of various fountains, not being able to find a specialty Hungarian dish that wouldn’t be also serve in Czech Republic.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/icecream.jpg&quot; alt=&quot;Ice Cream&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/langos.jpg&quot; alt=&quot;Langos&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/greek.jpg&quot; alt=&quot;Sinking Greece&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/water.jpg&quot; alt=&quot;Water fountains&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;not-so-pretty&quot;&gt;Not so pretty&lt;/h2&gt;

&lt;p&gt;When you are visiting a place, you don’t want to see the ugly part of the city. But it stoke me how dirty can Budapest be. I suppose it was some special “throw-away” weekend, since by the houses on the streets there were mounds of garbage, like old cupboards, chairs, paintings, computer screens and other apartment waste.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/garbage.jpg&quot; alt=&quot;Garbage&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Homeless people is probably also one of the city’s problems.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/budapest/homeless.jpg&quot; alt=&quot;Homeless&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;locations&quot;&gt;Locations&lt;/h2&gt;

&lt;p&gt;I have collected all the Budapest locations I have been to on a Google Map. Who knows, maybe you are going there this weekend and will find it useful.&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;350&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; src=&quot;https://www.google.com/maps/ms?msa=0&amp;amp;msid=202092952599254318758.0004fd6e3ab135701d4e9&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=47.498764,19.058533&amp;amp;spn=0.040591,0.120163&amp;amp;z=13&amp;amp;output=embed&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;br /&gt;&lt;small&gt;View &lt;a href=&quot;https://www.google.com/maps/ms?msa=0&amp;amp;msid=202092952599254318758.0004fd6e3ab135701d4e9&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=47.498764,19.058533&amp;amp;spn=0.040591,0.120163&amp;amp;z=13&amp;amp;source=embed&quot; style=&quot;color:#0000FF;text-align:left&quot;&gt;Budapest&lt;/a&gt; in a larger map&lt;/small&gt;&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2014/07/05/buda-and-pest/</id>
      <updated>2014-07-05T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Packing light is hard</title>
      <link href="http://ana-balica.github.io/2014/06/26/packing-light-is-hard/" />
      <summary type="html">&lt;p&gt;Especially for girls. I used to pack up a giant travel luggage, even if I was going to be out for 2 days. &lt;a href=&quot;http://www.imdb.com/title/tt3388032/?ref_=ttep_ep7&quot;&gt;“I dress according to the moods I sense in the room. As such, I must have options.”&lt;/a&gt; And my options were huge, same as my entire closet.&lt;/p&gt;

&lt;p&gt;Times change and here is my first attempt to pack light for a 3-day trip. Start small with short trips and develop your personal mini-perfect-kit for longer journeys – that’s my motto.&lt;/p&gt;

&lt;h2 id=&quot;checklist&quot;&gt;Checklist&lt;/h2&gt;

&lt;p&gt;Without even considering other options, I have bought a backpack. Handbags are a lot more uncomfortable to carry. Suitcases? That isn’t going to be light. I have a &lt;a href=&quot;http://www.deuter.com/de/en/city/gogo-80146-74.html&quot;&gt;Deuter GoGo&lt;/a&gt; with a volume of 25 litre in a girlish magenta arrowcheck color. Going beyond 30 litre already starts feeling big and not casual at all. The dimensions are also relevant to the airplane company that will allow you to take the bag on-board as hand luggage. The GoGo model is designed for city and traveling and lies within reasonable price range. I have purchased mine for 40 EURO. The killer feature of Deuter backpacks are the airstripes, which make your trips comfy, non-sweaty-back and hence enjoyable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/packing/deuter.jpg&quot; alt=&quot;Deuter backpack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I usually have blind faith that I will be able to get some work done, therefore I always carry my laptop. It’s 14 inch display laptop weighing 1.31kg + the charger, whose weight is never specified by the manufacturer (they really should start doing that). If you don’t do constant work on your laptop and you use it to check facebook or skype, than a phone will do much better. A smartphone today is a super space saver. In the best case scenario it replaces the following accessories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;camera&lt;/li&gt;
  &lt;li&gt;laptop or tablet&lt;/li&gt;
  &lt;li&gt;books, newspapers, magazines, guidebooks&lt;/li&gt;
  &lt;li&gt;physical map&lt;/li&gt;
  &lt;li&gt;notebook&lt;/li&gt;
  &lt;li&gt;music player&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moreover it has a GPS and quite often represents an entertainment device. Oh, I forgot, you can make calls also. Along with the smartphone, I usually take a pair of earphones and my cable charger. Actually this time I will skip the charger and the power adapter, since I am visiting a friend and every house has a collection of micro USB cables. The point is to get maximum usefulness from multipurpose devices.&lt;/p&gt;

&lt;p&gt;During a 3-day trip I don’t think I will get much reading done, so I am leaving my Kindle at home. At the same time I am not totally detached from my collection of books, since Kindle app syncs with your Amazon account and &lt;em&gt;viva le cloud&lt;/em&gt; – I can read from my phone. Less convenient, but still better.&lt;/p&gt;

&lt;p&gt;Next important step is the choice of shoes. It was one the most scrutinizing background jobs that lasted for 3 days in my mind. After solid market analysis, I have come up to the conclusion called &lt;a href=&quot;http://ca.shop.ecco.com/en_CA/802143.html&quot;&gt;Ecco Sport Biom Lite 1.2 Marry Jane&lt;/a&gt;. They look as if my grandma bought herself a pair of shoes to go to a health resort. Grandma will always choose cozy shoes and so they are. Being extremely light they offer a perfect foot support. Don’t go for converse or skate shoes, after 5-7 hours of walking you will see the difference.&lt;/p&gt;

&lt;p&gt;I can wear them with trousers, shorts, skirts or dresses. They look equally okaish. The only annoying thing about Ecco Biom Marry Jane is that they are made of nubuck, which makes it hard to remove the stains. In one month or so I have made them look shabby and not so pretty anymore. Anyway totally worth the money.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/packing/ecco.jpg&quot; alt=&quot;ecco shoes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Today I had the risk to buy the “neck-pouch-that-says-I-have-my-most-important-belongings-right-here-steal-it-asap”, in other words &lt;a href=&quot;http://www.amazon.co.uk/Samsonite-Kangaroo-Neck-Pouch-Graphite/dp/B005VQCSAS&quot;&gt;Samsonite Kangaroo Neck Pouch&lt;/a&gt;. I put in it my passport, travel tickets, credit cards, cash, coins. Most of my clothes lack any pockets, so I think it will become also a phone holder. Real reviews coming up after the upcoming trip.&lt;/p&gt;

&lt;p&gt;Everything else sums up to this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;two t-shirts&lt;/li&gt;
  &lt;li&gt;pair of shorts&lt;/li&gt;
  &lt;li&gt;pair of flip-flops&lt;/li&gt;
  &lt;li&gt;swimming suit (I know I will be at a swimming pool)&lt;/li&gt;
  &lt;li&gt;bag with ladies stuff, tooth brush, razor and medicine (take only unusual kind, don’t carry any Strepsils with you – you can buy those in any drugstore)&lt;/li&gt;
  &lt;li&gt;3 pairs of panties&lt;/li&gt;
  &lt;li&gt;5 pairs of low socks&lt;/li&gt;
  &lt;li&gt;pair of skin color tights – wear them with the shorts in cold weather&lt;/li&gt;
  &lt;li&gt;comb – I have long hair&lt;/li&gt;
  &lt;li&gt;anti-perspirant – it is ginormous, definitely should find something more miniature&lt;/li&gt;
  &lt;li&gt;solution for cleaning contact lenses in a green bottle&lt;/li&gt;
  &lt;li&gt;mirror, marker for unexpected hitchhiking, labello lipstick, lighter, rolling paper and other small stuff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/packing/travel-kit.jpg&quot; alt=&quot;Travel Kit&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The little bottles of 100ml are simple, yet brilliant. You can buy a 4-pack from IKEA. I use them for shampoo, soap, solution. And the most awesome part is that you can take them on-board of an airplane.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/packing/ikea_bottle.jpg&quot; alt=&quot;IKEA bottle&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Thank goodness it’s summer and my backpacks weights only 4 kg.&lt;/p&gt;

&lt;h2 id=&quot;406-not-acceptable-items&quot;&gt;406 Not Acceptable items&lt;/h2&gt;

&lt;p&gt;Along with the checklist, there is a list of stuff I don’t take with me in the trip. I am not talking about a basketball ball or a frying pan, but about the things that I used to take. And so those are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;makeup – since I don’t use any, easy to do, but I know some girls might find it difficult living without at least basic makeup&lt;/li&gt;
  &lt;li&gt;hair products – I didn’t have the shampoo in my checklist, because I know I will be borrowing it from my host&lt;/li&gt;
  &lt;li&gt;books – occupy a lot of space and cause back pain&lt;/li&gt;
  &lt;li&gt;camera – if you are not a photo expert, smartphone camera probably will do&lt;/li&gt;
  &lt;li&gt;manicure set – 3 days, remember?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To conclude, captain obvious is ready for her trip. Wish me good luck and intriguing adventures!&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2014/06/26/packing-light-is-hard/</id>
      <updated>2014-06-26T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Why travel?</title>
      <link href="http://ana-balica.github.io/2014/06/23/why-travel/" />
      <summary type="html">&lt;blockquote&gt;
  &lt;p&gt;And Siobhan says people go on holidays to see new things and relax, but it wouldn’t make
me relaxed and you can see new things by looking at earth under a microscope or drawing the
shape of the solid made when 3 circular rods of equal thickness intersect at right angles. And I
think that there are so many things just in one house that it would take years to think about all of
them properly. And also, a thing is interesting because of thinking about it and not because of
being new.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now I feel abashed to say I travel to see and discover new things. If I insist on being honest with myself, than it becomes clear I lost any interest in the surroundings long ago. The reason might be the likelihood of old European cities – somehow they all look the same.&lt;/p&gt;

&lt;p&gt;People (including myself) travel to show off in front of friends and family. Everybody enjoys sharing the beautiful moments of their life. You should have something to put on Instagram and brag about it. Otherwise what’s the whole point of visiting Tour Eiffel if you’re the only one knowing about it? I don’t necessarily see anything wrong with that – people, social animals, are predisposed to share with their peers and expect their positive acknowledge.&lt;/p&gt;

&lt;p&gt;Traveling is stupid and &lt;a href=&quot;http://blog.penelopetrunk.com/2009/08/17/4-reasons-travel-for-fun-is-a-waste-of-time/&quot;&gt;a waste of time&lt;/a&gt;. Why then do I keep planing my next trip?&lt;/p&gt;

&lt;p&gt;I love pinpointing my TripAdvisor map with new visited places and I feel good about myself. But this isn’t the main reason. Traveling drives challenge.&lt;/p&gt;

&lt;p&gt;Everybody chooses different challenges. Some prefer extreme spots, others do stand-up comedy. By definition I consider myself an non-shy introvert with a mediocre creative impulse. Even being brave enough, it is still troublesome for me to ask for directions from unknown people on the streets, to maintain a lovely chit-chat with newly met people and to not look at them suspiciously. I remember that one time when I was crusading in circles around an area, because I was too afraid to ask for directions. Obviously that day I was one hour late for my first German language course.&lt;/p&gt;

&lt;p&gt;When I go on a trip, I have this fear of getting lost, not being able to make my way to the final destination, being despised by people around, lose my flight, etc. Somehow during journeys I push myself to become brave, confident and powerful. New circumstances trigger my survival mode.&lt;/p&gt;

&lt;p&gt;My favorite part of traveling is the transit from source to destination, being done particularly alone. I have these stories when a handle from my heavy bag rips off and I have to drag it for a long time, when I address the fast passing crowd to help me buy a ticket because the ticket-lady doesn’t speak anything else besides Polish, when I arrive at 5AM in Kiev and have less than 10 UAH to get from the bus station to the airport in time, when a Greek speaking Romanian allows me to wait inside the train wagon and calls my friends to pick me up, because it’s 2AM, cold and dangerous outside.&lt;/p&gt;

&lt;p&gt;I pull myself together and do something I would never do. And since in my native city I know how to get around, I don’t even try to get out of my comfort zone.&lt;/p&gt;

&lt;p&gt;Maybe it doesn’t make any sense to you, but it does for me. There is something about traveling, even now in the era of Internet, Google Earth and Google Street View. I choose to shape my life and personality with the power of inner and outer discovery.&lt;/p&gt;

&lt;p&gt;I travel to challenge myself. Why do you travel?&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2014/06/23/why-travel/</id>
      <updated>2014-06-23T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Autoversioning static assets in Flask</title>
      <link href="http://ana-balica.github.io/2014/02/01/autoversioning-static-assets-in-flask/" />
      <summary type="html">&lt;p&gt;Whether you are actively developing a web application or just occasionally making
small changes, you will most probably face the problem with browsers caching static
content you have (JavaScript, CSS, images). Basically it means that your users will
see outdated version of your app and won’t be aware of the brand new feature you
were developing so passionately for the last week/month/year.&lt;/p&gt;

&lt;p&gt;That’s why versioning exists and you will see how easy it can be done in an automatic
way.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/autoversioning/script_version.png&quot; alt=&quot;script version&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;requisites&quot;&gt;Requisites&lt;/h2&gt;

&lt;p&gt;The solution to caching problem can be implemented using any programming language,
tool, framework, etc. Just to show you an example, I picked up &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt;,
which comes bundled with &lt;a href=&quot;http://jinja.pocoo.org/docs/&quot;&gt;Jinja2&lt;/a&gt; templating language
for Python.&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works?&lt;/h2&gt;

&lt;p&gt;Let’s say you have a CSS file and you included it in your HTML file. Now the trick
is to give a different name to the CSS file when you are linking it to the template.
But it must really tedious to change both the name of the stylesheet on hard disk and
in the HTML. Therefore by using query string while linking in the HTML, we force
the browser to reload the file and forget about the cache. At the same time there
is no need to change the name of the file for real.&lt;/p&gt;

&lt;p&gt;The version must be a unique number. Consider any of those:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;file last modified timestamp&lt;/li&gt;
  &lt;li&gt;hash of the last commit&lt;/li&gt;
  &lt;li&gt;hash of the file&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-to-code-it&quot;&gt;How to code it?&lt;/h2&gt;

&lt;p&gt;Most of the templating languages have filters. For example, in Flask and Jinja2
it is very easy to create a custom filer. Suppose you have configured Jinja2 to load
templates and it works fine. Now it’s the time to create the custom filter.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;some_app&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;


&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;template_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;autoversion&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;autoversion_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# determining fullpath might be project specific
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;fullpath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;some_app/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:])&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getmtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fullpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;OSError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;newfilename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;{0}?v={1}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newfilename&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&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 &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ url_for(&apos;static&apos;, filename=&apos;js/script.js&apos;)|autoversion }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So we use a decorator to create a custom filter. The usage is exactly the same as
for any other standard filter, by using a pipe. The first and only parameter that
our function accepts is the path to the static file.&lt;/p&gt;

&lt;p&gt;Some manipulations are required in order to get the relative path to the file.
For instance, we strip the first slash, otherwise &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.path.join()&lt;/code&gt; will consider
it an absolute path and will return this path. Then we need to get the timestamp
of the last modification of the file, which is going to be a floating-point number that represents
&lt;a href=&quot;http://docs.python.org/2/library/os.path.html#os.path.getmtime&quot;&gt;the number of seconds since the epoch&lt;/a&gt;.
If you want you can surround it in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;try-except&lt;/code&gt; clause in case the file doesn’t
exist. The later is easy - just preppend the timestamp to the filename and return it.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;A filter gave us an elegant and simple solution. Use the filter for any static
files, whose contents will be updated sooner or later, but the name will stay
the same.&lt;/p&gt;

&lt;p&gt;If you want to see the filter implemented into a real project, then you can
take a look at this &lt;a href=&quot;https://github.com/ana-balica/codee_blog&quot;&gt;blog’s github repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;update&quot;&gt;Update&lt;/h2&gt;

&lt;p&gt;Thanks to my friends, I have found out that query string to static assets is &lt;strong&gt;not&lt;/strong&gt;
generally a good option.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://developers.google.com/speed/docs/best-practices/caching&quot;&gt;“Don’t include a query string in the URL for static resources.”&lt;/a&gt;
It says that most proxies will not cache static files with query parameters.
Consequently that will increase the bandwidth, since all the resources will be
downloaded on each request.&lt;/p&gt;

&lt;p&gt;“To enable proxy caching for these resources, remove
query strings from references to static resources, and instead encode the parameters
into the file names themselves.” But this implies a slightly different implementation :)&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2014/02/01/autoversioning-static-assets-in-flask/</id>
      <updated>2014-02-01T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Erasmus for Moldova</title>
      <link href="http://ana-balica.github.io/2013/09/24/erasmus-for-moldova/" />
      <summary type="html">&lt;p&gt;I will not tell you what is Erasmus Mundus in official terms, history background
or program conditions. What I want to share is opportunities that exist for Moldovan
students to enter an exchange program in one of the EU countries.&lt;/p&gt;

&lt;p&gt;This article might be interesting for Undergraduate, Master, Doctorate, Post-doctorate
and Staff levels. Though I can give more insight for Bachelor and Masters
students.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/erasmus/erasmus.png&quot; alt=&quot;Erasmus Mundus&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Republic of Moldova is not part of the EU, so it is participating in a special
project within Erasmus Mundus, called &lt;a href=&quot;http://ewent.meil.pw.edu.pl/&quot;&gt;EWENT&lt;/a&gt;. And
now starts the interesting part…&lt;/p&gt;

&lt;h2 id=&quot;so-what-is-ewent&quot;&gt;So, what is EWENT?&lt;/h2&gt;

&lt;p&gt;Seriously, do you want me to copy-paste from their official website? Generally
most of the information can be found there, read it carefully. The information
is in English, though there is also some in Russian. FYI if you have difficulties
understanding the English version, you need to think twice before enrolling to
exchange programs, which are held in English obviously.&lt;/p&gt;

&lt;p&gt;On the &lt;em&gt;Courses&lt;/em&gt; page you have a list of faculties available from EU partner
universities. Don’t rush into decisions, if you didn’t find your faculty.
Many courses are shared among faculties. For example, if you study Industrial Design,
you might find a lot of courses from Construction Engineering, Civil Engineering,
Product Design. I can tell from my experience that even thought I picked up Information
Technology, half of my courses are not from FIT (Faculty of Information Technology).
That’s somehow frustrating that Faculty of Mechanical Engineering has Artificial
Intelligence and Neural Networks, Python for Computational Sciences, Java, C# programming
and many other IT related courses.&lt;/p&gt;

&lt;p&gt;Also it is a good idea to contact the local coordinator from the university you
are interested in, if you have questions.&lt;/p&gt;

&lt;p&gt;Take a look at the scholarships and what other costs the program covers (insurance,
plane tickets). And if it says 1000€, then you will get monthly this exact amount
of money. Usually for normal Erasmus, students get paid much less, so you can
consider yourself lucky.&lt;/p&gt;

&lt;h2 id=&quot;who-is-eligible&quot;&gt;Who is eligible?&lt;/h2&gt;

&lt;p&gt;You must be a student or an employee to a high education institution (like a university)
and not necessarily from UTM. Of course you need to have a Moldovan citizenship and
must have not resided nor carried out some main activity (study, work) for more
than a total of 12 months over the last five years in one of the European countries.
I thought this last statement might be important for those who already have been
to some exchange programs. Also you can conclude that a double citizenship is not
a problem, as long as your “main” country is Moldova.&lt;/p&gt;

&lt;p&gt;Don’t hesitate even if you are in your last year, it’s totally fine to come to
Erasmus and write your thesis here (actually will experience that in my next
semester :D).&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;That might be not exactly obvious to everybody, why go to Erasmus at all. So I say
Erasmus is awesome, because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;it’s a fresh look at studies&lt;/p&gt;

    &lt;p&gt;It’s a new university, new professors, different courses, classes, cafeteria,
  dorms.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;it’s a new country to get to know&lt;/p&gt;

    &lt;p&gt;I am pretty sure that during a semester or two you will know where best food
  is served or where do I borrow a bike for the weekend.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;you travel around the world (or EU at least)&lt;/p&gt;

    &lt;p&gt;Everything is much closer and accessible than it is from Moldova.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;you make new friends&lt;/p&gt;

    &lt;p&gt;There are 500 international student here at CVUT in Prague.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;you are cared about&lt;/p&gt;

    &lt;p&gt;Local coordinator, students, student organizations will guide you through the
  most important steps to provide some accommodation, necessary documents, transport
  pass, etc.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also any of those points can be extended with lots of cool moments that are awaiting
for you.&lt;/p&gt;

&lt;h2 id=&quot;how-can-i-apply&quot;&gt;How can I apply?&lt;/h2&gt;

&lt;p&gt;The official application is on &lt;a href=&quot;http://ewent.meil.pw.edu.pl/app/&quot;&gt;EWENT&lt;/a&gt;. Mind
the deadlines and watch for the opening of the registration. As for the Erasmus
period 2013/2014 the application was open until the start of January 2013.&lt;/p&gt;

&lt;p&gt;Until then start preparing all the documents and contact our local coordinator
Mariana Vrîncean (her email is on the website too). She can prepare some university
documents for you and give you feedback on your application. Keep in touch with
Mariana, because she can provide a lot of useful information. Moreover she
participates in the decision making process, so it is good if she got to know you.&lt;/p&gt;

&lt;h2 id=&quot;what-can-i-do-to-be-selected&quot;&gt;What can I do to be selected?&lt;/h2&gt;

&lt;p&gt;For short:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;meet the application deadline&lt;/li&gt;
  &lt;li&gt;be sure all the documents are uploaded and in order&lt;/li&gt;
  &lt;li&gt;pay attention to the Motivational Letter, talk about our interests (in studies,
research, development), list your strong parts, mention what would you like to
do during Erasmus and what impact will it have on your future career&lt;/li&gt;
  &lt;li&gt;have a decent CV. It totally depends on your personal achievements, but usually
it is important to prove that you are a proactive persona.&lt;/li&gt;
  &lt;li&gt;your marks - no, you shouldn’t be a genius from the top 5 university students.
I even doubt that grades have any serious weight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality there’s is no general recipe of how students get selected. We can only
guess what is appreciated more and what is skipped from the grading.&lt;/p&gt;

&lt;h2 id=&quot;i-am-an-erasmus-student&quot;&gt;I am an Erasmus student&lt;/h2&gt;

&lt;p&gt;Happy news! You were selected.&lt;/p&gt;

&lt;p&gt;The organizers of EWENT from Poland will be responsible for your Learning Agreement,
which you need to sign. Also after you will get your visa, they will send you your
Erasmus insurance and round-trip plane tickets.&lt;/p&gt;

&lt;p&gt;From now on much of the activity depends on the hosting university. They must
send you necessary documents to get a visa. They can ask you to pick up courses.
There might be lots of other details. In my case I was contacted also
by the student organization ISC. They kindly provided a contact person that picks
you up at the airport and helps you with accommodation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; the website layout or some details might be outdated to the moment you are
reading, so be sure to make yourself familiar with the latest news from
&lt;a href=&quot;http://ewent.meil.pw.edu.pl/&quot;&gt;EWENT&lt;/a&gt;.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2013/09/24/erasmus-for-moldova/</id>
      <updated>2013-09-24T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>OMG! git reset --hard</title>
      <link href="http://ana-balica.github.io/2013/08/28/reset-hard/" />
      <summary type="html">&lt;p&gt;I bet you know that jaw-dropping command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset --hard &amp;lt;commit-hash&amp;gt;&lt;/code&gt;. Remember that first time you lost all that code? No? Well, good for you you didn’t.&lt;/p&gt;

&lt;p&gt;Fair enough the command is considered potentially dangerous. I have even seen blogposts about git reseting that make it hard to detect the command in-need (even if the user came for a full delete/erase/destroy this commit and the data it contains). The authors add lots of explanations around, so you need to read first and then type the &lt;strong&gt;correct&lt;/strong&gt; command. No copy-paste, no tl;dr allowed.&lt;/p&gt;

&lt;p&gt;In fact as I learned from &lt;a href=&quot;http://git-scm.com/book&quot;&gt;Pro Git&lt;/a&gt; the dreadful harm is reversible…&lt;/p&gt;

&lt;h2 id=&quot;lost-my-commits&quot;&gt;Lost my commits&lt;/h2&gt;

&lt;p&gt;So let’s take an example. Suppose you just have started a new project and your history looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git &lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;f1c16f4 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;HEAD, master&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; second &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ana-balica]
743c90d first &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ana-balica]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;* &lt;strong&gt;ls&lt;/strong&gt; is an alias for some pretty formatting&lt;/p&gt;

&lt;p&gt;Now you type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset --hard 743c90d&lt;/code&gt;, which resets your HEAD at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;743c90d&lt;/code&gt; commit. But actually that last commit is not lost. For a recovery all you need to know is the SHA of that lost commit. Create a new branch starting with this commit, rebase or merge your master branch with the new branch that contains the commit and you are saved.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git branch recover-branch f1c16f4
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git rebase recover-branch&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It’s good if you have the SHA of the lost commit(s). If not, try those steps in the following order:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;check the terminal output, at some point you have typed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt; and maybe you have the hash&lt;/li&gt;
  &lt;li&gt;try &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reflog&lt;/code&gt; - it records your branch tip changes. Look for the commit name if you remember it. Mine looks like that:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git reflog
743c90d HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;4&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: reset: moving to 743c90d
f1c16f4 HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;5&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: commit: second
743c90d HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;6&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: commit &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;initial&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: first&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log -g&lt;/code&gt; if you still can’t comprehend which is the one&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lost-stagging-area&quot;&gt;Lost stagging area&lt;/h2&gt;

&lt;p&gt;Worse then reseting to a commit in the past, it is reseting the HEAD - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset --hard HEAD&lt;/code&gt;. But don’t worry if those were in your staging area, which means your index knew about them. Type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fsck --lost-found&lt;/code&gt;. It checks the validity of objects in the database and therefore you will see your dangling blob there. You can open it and check it’s contents. For recovering all that data simply dump it’s contents to the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git show 898910b &amp;gt; test.txt&lt;/code&gt;, where the SHA is the blob’s SHA.&lt;/p&gt;

&lt;h2 id=&quot;lost-unstagged-area&quot;&gt;Lost unstagged area&lt;/h2&gt;

&lt;p&gt;The horror is here! At this point you have made some changes to your files, never &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt;ed them, and then the magic happen and wiped away all that. Must be a crisis in your life, you are doomed, life doesn’t make sense any more…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/git-reset/scream.jpg&quot; alt=&quot;The Scream&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Maybe you are lucky and you can find the light at the end of tunnel. Check that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;maybe Ctrl+Z?&lt;/li&gt;
  &lt;li&gt;see if your smart IDE has any internal version control system, personally I use PyCharm and it is very easy to view and recover from history. Protect yourself, use an IDE ;)&lt;/li&gt;
  &lt;li&gt;are the changes recorded anywhere else? For instance if your project is located in Dropbox (I know that’s stupid if your have version control, but who knows), then you can see previous versions on Dropbox website and restore to any version you want. A new version is recorded on a new save. Don’t leave it for tomorrow, because only the last 30-days versions are stored in the cloud.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have some other ideas on code recovery, feel free to share :)&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2013/08/28/reset-hard/</id>
      <updated>2013-08-28T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>SiCamp Moldova 2013 speculations</title>
      <link href="http://ana-balica.github.io/2013/07/29/sicamp-moldova-2013-speculations/" />
      <summary type="html">&lt;p&gt;Social Innovation Camps are ok. Moldova also has one, I wonder why it’s not marked on the map of Global SiCamps and no words about it even &lt;a href=&quot;http://sicamp.org/global/camps-around-the-world/&quot;&gt;here&lt;/a&gt;. Seemingly we are apart from the rest of the world as usual.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/sicamp/sicamp_map.jpg&quot; alt=&quot;SiCamp Map&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;get-it-working&quot;&gt;Get it working&lt;/h2&gt;

&lt;p&gt;This year teams were encouraged to get some real working done. I suppose that includes launching the application live. As for me it’s so hard to deploy it when you know the app is half done. But that’s sometimes the right thing to do, because otherwise you will be having lots of those “nice” apps in your repositories, that will rust there till the end of the world. So just launch it.&lt;/p&gt;

&lt;p&gt;Nevertheless I hate hurry projects, maybe it’s better to &lt;strong&gt;fail fast&lt;/strong&gt; and get a prototype done. Reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the working app will keep reminding about itself so you don’t abandon it&lt;/li&gt;
  &lt;li&gt;users will tell you what’s best, so you get some real feedback&lt;/li&gt;
  &lt;li&gt;you already started solving that noble social problem - get yourself a beer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are the SiCamp projects really going to hold on? We will see.&lt;/p&gt;

&lt;h2 id=&quot;mentors&quot;&gt;Mentors&lt;/h2&gt;

&lt;p&gt;Mentors on such events are a pain in the ass. That’s what they do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;giving lots of ideas - it’s 48 hours and about 20-25 hours of real productive work and it’s hard to stay focused when every single mentor has an overwhelming conglomeration of ideas in his head. The ideas might be very useful, but usually each person’s perspective is killing a strong fixed aim of the team. The best way is to give mentors a single person from the team to fuck with his ears.&lt;/li&gt;
  &lt;li&gt;giving great ideas about the stuff they are not experts in - i assume this happens because of the status they got. Maybe they are trying their best to be useful, but sometimes it’s just not working for anybody.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;in-the-end&quot;&gt;In the end&lt;/h2&gt;

&lt;p&gt;I have no idea if the event is worth going to or continued to be organized. When you look at the big picture, it absolutely plays no role. People that will be promoted to the status of “they changed the world”, will probably do it anyway without SiCamps. Thinking less globally, one can see lots of benefits in creating and participating to such events.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2013/07/29/sicamp-moldova-2013-speculations/</id>
      <updated>2013-07-29T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Custom Python Markdown Extension</title>
      <link href="http://ana-balica.github.io/2013/07/16/custom-python-markdown-extension/" />
      <summary type="html">&lt;p&gt;&lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt; is awesome. It’s a pleasure to use it and it’s a pleasure to extend the Python Markdown module to fit your needs. Along with a bunch of official extensions, the module contains a nice &lt;a href=&quot;http://pythonhosted.org/Markdown/extensions/api.html&quot;&gt;API&lt;/a&gt; for writing your own extensions.&lt;/p&gt;

&lt;p&gt;The API is clean and comprehensible. The reason of writing this article is that maybe somebody else will bump into the same problems like me and might find some of the solutions good enough to be used.&lt;/p&gt;

&lt;h2 id=&quot;problem-statement&quot;&gt;Problem statement&lt;/h2&gt;

&lt;p&gt;Right now I am writing in Markdown. When I want to insert an image I am doing the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;![My Image](/static/img/my_image.png)&lt;/code&gt;. I specify the relative path, because when I switch to different domain names, I want to have the same picture and no broken links. So I figured it out there can be 2 ways to solve that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;render the template before markdown does. Use your templating language for inserting a variable that will be your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MEDIA_URL&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;write a markdown extension that will fix your links&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this moment I would choose the first solution. But I implemented the second one, so I want to share some basic knowledge.&lt;/p&gt;

&lt;h2 id=&quot;my-setup&quot;&gt;My setup&lt;/h2&gt;

&lt;p&gt;I use &lt;a href=&quot;http://pythonhosted.org/Flask-FlatPages/&quot;&gt;Flask-FlatPages&lt;/a&gt; for rendering articles. Internally Python &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;markdown&lt;/code&gt; module is used, and that means that you build your own extension easily.&lt;/p&gt;

&lt;h2 id=&quot;consists-of&quot;&gt;Consists of&lt;/h2&gt;

&lt;p&gt;The extension must have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a class that will represent the extension and needs to inherit from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;markdown.extensions.Extension&lt;/code&gt; and implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extendMarkdown&lt;/code&gt; method&lt;/li&gt;
  &lt;li&gt;a function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;makeExtension()&lt;/code&gt;, since you will be having per module one single extension. When you will specify the name of the extension (i.e. to the configuration variables of Flask FlatPages or directly when creating the Markdown instance), it will import the module and call that function. Here I am just quoting the documentation.&lt;/li&gt;
  &lt;li&gt;some kind of processor that will perform the manipulations with your markdown text&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lets-start-coding&quot;&gt;Let’s start coding&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;makeExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot; Return an instance of the AbsoluteImagesExtension &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AbsoluteImagesExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This function also accepts a list of configs. It is useful for us, since we want to get a base URL or a media URL which we will prepend to the image source links.&lt;/p&gt;

&lt;p&gt;There are different flavors of processors: &lt;strong&gt;pre&lt;/strong&gt;processor (before code is sent to Markdown core), &lt;strong&gt;tree&lt;/strong&gt;processor (being an &lt;a href=&quot;http://effbot.org/zone/element-index.htm&quot;&gt;ElementTree&lt;/a&gt; object), &lt;strong&gt;post&lt;/strong&gt;processor (you got your output string already). For my needs I have decided that an ElementTree is a good way to easily extract &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags and insert the changed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbsoluteImagesTreeprocessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Treeprocessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot; Absolute Images Treeprocessor &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;imgs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getiterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_external&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;make_external&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urljoin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;base_url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startswith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;http://&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run()&lt;/code&gt; is mandatory. The syntax is straight forward and the implementation is pretty naive. Also pay attention that we have the access to the config.&lt;/p&gt;

&lt;p&gt;And finally the extension class:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbsoluteImagesExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot; Absolute Images Extension &quot;&quot;&quot;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;base_url&apos;&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;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                         &lt;span class=&quot;s&quot;&gt;&quot;The base URL to which the relative paths will be appended&quot;&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;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extendMarkdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;md&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;md_globals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;absolute_images&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AbsoluteImagesTreeprocessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;md&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;absolute_images&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getConfigs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;md&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;treeprocessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;absoluteimages&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;absolute_images&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;_end&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;md&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;registerExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;blockquote&gt;

&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self.config&lt;/code&gt; should be a dictionary and store values of the form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;param_name: [param_value, description]&lt;/code&gt;. In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extendMarkdown()&lt;/code&gt; we are adding our treeprocessor class to Markdown TreeProcessors by specifying it’s name, an instance and where to insert it - before the end.&lt;/p&gt;

&lt;p&gt;The extension lives here - &lt;a href=&quot;https://gist.github.com/ana-balica/5944798&quot;&gt;https://gist.github.com/ana-balica/5944798&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;enabling-the-extension&quot;&gt;Enabling the extension&lt;/h2&gt;

&lt;p&gt;For Flask do something like that - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FLATPAGES_MARKDOWN_EXTENSIONS = [&apos;absolute_images(base_url=http://this-important-url)&apos;]&lt;/code&gt;  in the config. First Markdown will search for the extension in the module directory - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;markdown.extensions&lt;/code&gt;. If you don’t want to keep it there for some reasons, you can make the extension name contain dots (then Markdown will import it as-is) or prepend to the extension filename &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mdx-&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mdx-absolute_images&lt;/code&gt;). But be careful that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mdx-&lt;/code&gt; notation is discouraged from being used.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2013/07/16/custom-python-markdown-extension/</id>
      <updated>2013-07-16T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>Welcome to Design Patterns</title>
      <link href="http://ana-balica.github.io/2013/07/03/welcome-to-design-patterns/" />
      <summary type="html">&lt;p&gt;There are many recommended books and articles to be read on Design Patterns. High variety leads to a problem of choice. So based on the magic of rational randomization I decided to read and &lt;strong&gt;understand&lt;/strong&gt; &lt;a href=&quot;http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124&quot;&gt;Head First Design Patterns&lt;/a&gt;. I am a Head First virgin, so I even read the pre-introduction with explanations on metacognition, pretty pictures and redundancy. So far, so good.&lt;/p&gt;

&lt;p&gt;The reason of writing all this down is to overflow my brain with redundancy, “do my homework” by summarizing everything read in a chapter and maybe leave a note for future me and all other Internet readers about something important. Moreover that’s going to be a shortcut on the book (though the book is funny).&lt;/p&gt;

&lt;p&gt;One chapter → one article. And the first one is called &lt;em&gt;Welcome to Design Patters&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;encapsulation&quot;&gt;Encapsulation&lt;/h2&gt;

&lt;p&gt;The first announced Design Principle in the book is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Identify the aspects of your application that vary and separate them from what stays the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the guru of all Design Patterns. That means that all patterns are trying to accomplish this in some way or another. It is very important to separate what varies from what stays the same, since changes are too frequent in IT world.&lt;/p&gt;

&lt;p&gt;The examples in the book are based on ducks. We will examine a very similar situation based on the Design Puzzle. Initially we have a very simple application that is made of a simple character hierarchy.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/design-patterns/uml_simple_inheritance.png&quot; alt=&quot;UML simple inheritance&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s a very inflexible hierarchy and will lead to many problems over time:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;What if Queen doesn’t fight? Should you overwrite the method in this class?&lt;/li&gt;
  &lt;li&gt;Are there going to be more characters that don’t fight? Will you overwrite the behaviour in every class?&lt;/li&gt;
  &lt;li&gt;Trolls fight different from Kings!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ok, that’s the moment when you should &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHIFT+Delete&lt;/code&gt; your code. Kidding :) You need to apply that one first principle and conceptually do the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/design-patterns/encapsulation.png&quot; alt=&quot;Encapsulation&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;interface&quot;&gt;Interface&lt;/h2&gt;

&lt;p&gt;That green spot represents all the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fight/Weapon&lt;/code&gt; Behaviours. It’s not a good idea to create just a bunch of classes, since you will lose the ability to use polymorphic behaviour and will hard-code each behaviour to each character. Create an interface. Side-note: here the interface doesn’t mean necessarily a Java interface - it’s a conceptual interface, a special class that holds the public declarations and has no proper implementation (also not always true, think about abstract classes in C++ which can contain implementation).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Program to an interface, not to an implementation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/design-patterns/interface.png&quot; alt=&quot;Interface&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s what we have done after learning that interfaces give you lots of flexibility. In your Character class you will create a property of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WeaponBehaviour&lt;/code&gt;. Here, let me show you the code.&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;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Character&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nc&quot;&gt;WeaponBehaviour&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;weaponBehaviour&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;setWeaponBehaviour&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WeaponBehaviour&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&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;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;weaponBehaviour&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&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;fight&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;weaponBehaviour&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;useWeapon&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;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WeaponBehaviour&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;useWeapon&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;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;KnifeBehaviour&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WeaponBehaviour&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;useWeapon&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;c1&quot;&gt;// an implementation of a fight with a knife&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;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Queen&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Character&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Queen&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;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;weaponBehaviour&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;nc&quot;&gt;KnifeBehaviour&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;Moreover by having our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WeaponBehaviour&lt;/code&gt; setter, we can successfully teach our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Characters&lt;/code&gt; to learn how to use new weapons at runtime.&lt;/p&gt;

&lt;h2 id=&quot;composition&quot;&gt;Composition&lt;/h2&gt;

&lt;p&gt;A perfect inheritance is a IS-A relationship. It is actually more than just a IS-A according to L principle from SOLID. Nevertheless what we have done here is eliminating IS-A and using HAS-A, which is composition.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Favor composition over inheritance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It gave us all those benefits of &lt;strong&gt;behaviour change at runtime&lt;/strong&gt; and the encapsulation of a set of algorithms. Now not only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Character&lt;/code&gt; descendants will be able to fight and use weapons, but also any other class can be taught by the power of composition.&lt;/p&gt;

&lt;p&gt;By the way, all that talk about fighting characters is a patters called &lt;strong&gt;Strategy&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from client that use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Strategy is a behavioural pattern. If you want to learn more, &lt;a href=&quot;http://www.vincehuston.org/dp/strategy.html&quot;&gt;check this out&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/design-patterns/patterns_rule.jpg&quot; alt=&quot;Patterns rule&quot; /&gt;&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2013/07/03/welcome-to-design-patterns/</id>
      <updated>2013-07-03T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>xkcd getter</title>
      <link href="http://ana-balica.github.io/2013/04/25/xkcd-getter/" />
      <summary type="html">&lt;p&gt;Some time ago I had an assignment to implement a crawler. Now I understand that I didn’t do the right thing, since a crawler is a program that will follow links in a systematical manner on every page. What I did is called a spider - a program that downloads web pages. Well, you can take your spider, add some parsing, extract the necessary links, follow them, download web pages and basically this is a crawler.&lt;/p&gt;

&lt;p&gt;Nonetheless I still have that spider written in Python. It suffered many changes, since initially it was implemented using sockets, so far now it uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urllib&lt;/code&gt;. Since I enjoy reading &lt;a href=&quot;http://xkcd.com/&quot;&gt;xkcd&lt;/a&gt;, this website became my target.&lt;/p&gt;

&lt;p&gt;The idea to create this post came out of this &lt;a href=&quot;http://xkcd.com/859/&quot;&gt;comic&lt;/a&gt;:&lt;/p&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;
  &lt;img src=&quot;http://imgs.xkcd.com/comics/(.png&quot; alt=&quot;xkcd comic n# 859&quot; style=&quot;width: 300px;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Tried my spider on it and it didn’t crash, gave me the title, the caption and the picture - yey!&lt;/p&gt;

&lt;h2 id=&quot;text-or-screencast&quot;&gt;Text or screencast&lt;/h2&gt;

&lt;p&gt;If you are a visual person, then you can watch the screencast below. It describes every single line of code written. Important: the version of the script used in the screencast is a bit outdated, some design solutions were changed, but if you are interested mainly in parsing, then the video is eligible to be watched.&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/BmLDo8mR4Nk?list=PL_6_YrF4ZAJ-Sj34pZUmFeTl9AiBrJz6f&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;If you don’t like watching looong screencasts (like me), then here is a short overview of the script. Also you can find the source code &lt;a href=&quot;https://gist.github.com/ana-balica/5454270&quot;&gt;right here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;You will need:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Python 2.7&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://lxml.de/&quot;&gt;lxml library&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;optionally a browser extension to check you xpaths. I am using &lt;a href=&quot;https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl&quot;&gt;XPath Helper&lt;/a&gt; for Chrome&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;downloader&quot;&gt;Downloader&lt;/h2&gt;

&lt;p&gt;Create a separate class that will hold the download functionality. Here is the snippet:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&apos;&apos;&apos;
  Class to retreive HTML code
  and binary files from a
  specific website
  &apos;&apos;&apos;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;browser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urllib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Bad connection&apos;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Bad header response&apos;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;save_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;wb&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Pass to the constructor the URL where from to download the contents. There are 2 methods, from which only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;download()&lt;/code&gt; represents the interface of the class. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urllib.urlopen()&lt;/code&gt; method opens a socket for you establishing a connection. It is a good idea to wrap this part of code into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;try/except&lt;/code&gt; since it can raise an exception if the connection cannot be made (many reasons for that). Afterwards check if the server responded with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200 OK&lt;/code&gt; and in case of success get the contents. Those contents is the HTML code of the page.&lt;/p&gt;

&lt;p&gt;There is also a scenario when the downloaded content is an image (binary file). For that we need explicitly to pass the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_image=True&lt;/code&gt; parameter. An image will be saved on the local machine in the current directory (where the script is placed).&lt;/p&gt;

&lt;h2 id=&quot;parser&quot;&gt;Parser&lt;/h2&gt;

&lt;p&gt;Parser class is a not a generic class. It is build specifically for parsing &lt;a href=&quot;http://xkcd.com/&quot;&gt;xkcd.com&lt;/a&gt;. If you plan on extending the spider, then it might be a good idea to create an interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Parser&lt;/code&gt; and let other classes implement that interface.&lt;/p&gt;

&lt;p&gt;Since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xkcdParser&lt;/code&gt; class is a bit long, we will examine it in chunks.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;xkcdParser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&apos;&apos;&apos;
  Class for parsing xkcd.com
  &apos;&apos;&apos;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://xkcd.com/&quot;&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;caption&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;downloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://xkcd.com/(\d+)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string(//div[@id=&apos;ctitle&apos;])&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_caption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;caption&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string(//div[@id=&apos;comic&apos;]/img/@title)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_comic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string(//div[@id=&apos;comic&apos;]/img/@src)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;downloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Keep the URL of the website in a class attribute. Besides the constructor there are a bunch of methods here.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set_last_comic_nr&lt;/code&gt; is… well self-explanatory. Why do we need it? Because we plan on allowing the user to specify the number of the comic and also generate a random number in a specific range. Not the best solution to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Downloader&lt;/code&gt; object inside the method, but it works for this short spider.&lt;/p&gt;

&lt;p&gt;After you get the contents, you need to parse them. Two solutions (might be more, but the most mainstream) are xpaths or regular expressions. If you go to the home page of &lt;a href=&quot;http://xkcd.com&quot;&gt;xkcd.com&lt;/a&gt; then below the image you will see a permanent link for this comic and it has the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; we are looking for - the id of the most recent comic. Using the inspector we can check that this part of HTML is not wrapped into a tag, the text is placed between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&lt;/code&gt;s after an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ul&lt;/code&gt;. That’s definitely not a well-formed XML mark-up.&lt;/p&gt;

&lt;p&gt;Even in this case it is possible to get the data with the following xpath - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;//div[@id=&apos;middleContainer&apos;]/text()[preceding-sibling::br][1]&lt;/code&gt;. That will return the following string - ‘Permanent link to this comic: http://xkcd.com/1203/’, which again should be parsed with regular expressions.&lt;/p&gt;

&lt;p&gt;I’ve taken a shortcut. My regexp searches for one or more digits after the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://xkcd.com/&lt;/code&gt; through the whole DOM and groups those digits. Regular expressions are slow, in my case it was necessary to build a whole automata out of the contents, therefore you need to avoid them as often as possible.&lt;/p&gt;

&lt;p&gt;The other 3 methods are already using xpaths to search for the title, caption and path to the image through the contents of the page. The method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_comic()&lt;/code&gt; also instantiates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Downloader&lt;/code&gt; object and downloads the image.&lt;/p&gt;

&lt;p&gt;The xpaths are fairly simple, but anyway let’s examine of them. How about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string(//div[@id=&apos;comic&apos;]/img/@src)&lt;/code&gt;? English translation is the following -&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;search through the DOM for a div with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; that equals ‘comic’&lt;/li&gt;
  &lt;li&gt;inside that node search for an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;img&lt;/code&gt; tag&lt;/li&gt;
  &lt;li&gt;get the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt; attribute of that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;img&lt;/code&gt; tag&lt;/li&gt;
  &lt;li&gt;strigify everything you have found - if you don’t use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; function, then xpath will return an array with every matched element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the code looks like that:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;xkcdParser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_current_comic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_caption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_comic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_comic_by_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;The comic number should be an integer&apos;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;downloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;downloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_caption&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_comic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_random_comic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_comic_by_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comic_nr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We need 3 more methods: get the latest comic, get a specific comic and get a random comic. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_current_comic()&lt;/code&gt; actually has a problem, because it hides the loading of contents. Since we call that method that will set last comic number, we know that it will also set the contents ad there is no need to download the page again. Still, prefer a different implementation for that.&lt;/p&gt;

&lt;p&gt;Before downloading a comic with an id, first check the data that you get from the user - if it’s an integer and if it’s in range, perform the download, setting of title, caption etc. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_random_comic()&lt;/code&gt; uses the method above, initially generating a random number.&lt;/p&gt;

&lt;p&gt;Aaaand we are done!&lt;/p&gt;

&lt;p&gt;You can get the entire snippet by accessing this gist - &lt;a href=&quot;https://gist.github.com/ana-balica/5454270&quot;&gt;https://gist.github.com/ana-balica/5454270&lt;/a&gt;&lt;/p&gt;

</summary>
      <id>http://ana-balica.github.io/2013/04/25/xkcd-getter/</id>
      <updated>2013-04-25T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
    <entry>
      <title>CLI and GUI git</title>
      <link href="http://ana-balica.github.io/2013/04/21/cli-and-gui-git/" />
      <summary type="html">&lt;p&gt;To be clear from the very beginning, I vote for CLI git to start with. There’s nothing better than understanding what exactly you are doing and not just try and click every available button. Just imagine yourself connecting to a remote server that doesn’t have your favorite GUI client.&lt;/p&gt;

&lt;p&gt;During my interaction with git (which started not so long ago), I’ve developed a hybrid workflow. There are lots of git clients and to be honest, I haven’t tried many of them, so I’ll just present the one I’m familiar with - &lt;strong&gt;gitg&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;

&lt;p&gt;Visualizing your tree in git is definitely a very useful thing. To achieve the following you can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--graph&lt;/code&gt; argument. If you leave the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log&lt;/code&gt; command then the long commit messages will make it hard to read the topology.&lt;/p&gt;

&lt;p&gt;Use pretty formatting and create an alias for that:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; log &lt;span class=&quot;nt&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;format:&lt;span class=&quot;s2&quot;&gt;&quot;%C(yellow)%h%Cred%d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; %Creset%s%Cblue&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; [%cn]&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--decorate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Therefore the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git ls --graph&lt;/code&gt; will output the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;se&quot;&gt;\*&lt;/span&gt;   46be671&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Merge branch &lt;span class=&quot;s1&quot;&gt;&apos;development&apos;&lt;/span&gt; of github.com:author/repo into development&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]
|&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
| &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; fe8bef7&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;commit nr 5&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]
| &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;   b801dc6&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Merge branch &lt;span class=&quot;s1&quot;&gt;&apos;development&apos;&lt;/span&gt; of github.com:author/repo into development&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]
| |&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
| | &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; ace6bdb&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;commit nr 4&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]
| &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; | 2fd916a&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;commit nr 3&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]
| &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; | 7419237&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;commit nr 2&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; | | fd0c4bf&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;commit nr 1&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;author]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Not bad, but a GUI client makes it better. Basically it’s the same branch topology , but it offers an intuitive way to crawl though commits, see the details, files that were changed, the branch pointers.
&lt;img src=&quot;/assets/img/git/gitg1.png&quot; alt=&quot;gitg - history tree&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;diffs&quot;&gt;Diffs&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git diff&lt;/code&gt; shows changes between working tree, commits, branches, etc. It can take lots of arguments and is very flexible. In case you just don’t want to remember all those possibilities, the client will provide snippets with diffs for lots of scenarios. It becomes handy when you want to review what you are about to commit or what what do you want to add to your staged area, what is inside your stashes, what have you committed long ago.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/git/gitg2.png&quot; alt=&quot;gitg - see the diffs&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;stash&quot;&gt;Stash&lt;/h2&gt;

&lt;p&gt;I use stashing all the time. And I also try not to keep them there for a long time. So mainly I do something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git stash
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;some stuff here
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git stash pop&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop&lt;/code&gt; a stash, this means that you apply your stash to the current working tree and also drop it from the stash list. That’s a handy shortcut.&lt;/p&gt;

&lt;p&gt;If you want to check the diffs inside your stash type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git stash show -p stash@{0}&lt;/code&gt;. Not the most pretty stash name (while typing you need to reach for @ and curly braces), so I find it quite nice to visualize the list of stashes and the diffs in gitg. The annoying part is always choosing the branch where to apply the stash, there’s no ‘please make the current branch default for stashes’.&lt;/p&gt;

&lt;h2 id=&quot;blame&quot;&gt;Blame&lt;/h2&gt;

&lt;p&gt;The client git is pretty straight-forward and has only the ability to blame an entire file. Hence it does &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git blame &amp;lt;filename&amp;gt;&lt;/code&gt;. Still useful, though personally I think would be nice to get a link to the commit from the blame section.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/git/gitg3.png&quot; alt=&quot;gitg - blaming&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;patch&quot;&gt;Patch&lt;/h2&gt;

&lt;p&gt;Very often I find myself willing to add to the staged area only several lines from a file. Then I do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add -p&lt;/code&gt; and add just the hunks that I want. With gitg I choose the Commit tab and the file I want to patch and simply by holding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CTRL&lt;/code&gt; and clicking on the lines, I can choose exactly what I want to stage.&lt;/p&gt;

&lt;p&gt;The client has this nice feature to stage specific lines, but at the same time it can be quite annoying when you got big chunks of code and you want to make it fast. Some git clients allow to select lines and stage them all at once, unfortunately not gitg.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;At the beginning I though that GUI git is going to be presented as a very handy tool, but eventually I got convinced that it barely associates with the CLI power.&lt;/p&gt;
</summary>
      <id>http://ana-balica.github.io/2013/04/21/cli-and-gui-git/</id>
      <updated>2013-04-21T00:00:00+00:00</updated>
      <author>
        <name>Ana</name>
      </author>
    </entry>
  
</feed>
