Monthly Archives: December 2016

How we work in NiteoWeb

NiteoWeb is a distributed team of Web experts spread around the World. While we do rent office space in Ljubljana, Slovenia, most of us work remotely. Here’s a quick overview of how we go by our days.

Communication

Instant messaging is done through Slack on different channels (operations, support, development etc.). We have daily standups at 9AM UTC on Google Hangouts when everyone has a minute or two to say what they’re working on and if they need any help. Once a week, Dejan has “catch ups” (better known as 1-on-1) with everyone on the team to keep himself in the loop.

About once or twice a year we fly the whole team somewhere nice and we’ll have an “IRL” (in-real-life) meetup. Here we discuss company status, projects and the future in a group setting.

Then there are ad-hoc in-person meetups that happen about once or twice a month, as needed.
Some of us might get together to watch a talk at a local conference or we go to lunch together to discuss project work.

Project and Company Management

Project and task management is currently done with either Plan.io (being slowly discontinued) or GitHub. Support handles tickets through GrooveHQ. We also have an internal document system (intranet) we call “intra”, running on Plone, where all our company processes and documents are stored.

We track cash flow with Xero. Finance reports are published to intranet on a monthly basis and are viewable to all full-time team members.

Monthly company newsletter covers the main events of the month and is a great reference point for digging deeper into parts of the company one does not know that well.

Development

NiteoWeb runs several SaaS projects, serving a few thousand customers. We use several techniques, libraries and services that allow us to make several deploys to production every day. That does not mean that we do not test code before shipping it. Rather, we have a workflow that runs a variety of checks and automatic tests and makes it very fast and easy to test new features in staging environments.

And even if we do push buggy code to production, we only push it to a fraction of users to minimize impact. The outcomes are great: happy users, since they get features and fixes fast. And maybe even more importantly, happy developers, since the code is actually being used minutes after being merged rather than being stuck in a bureaucratic production deployment workflow. Nejc has given numerous talks on the subject.

Setting Goals and Deciding What To Work On

We subscribe to the 12-Week Year philosophy for planning and goals. Every beginning of the quarter we review what we’ve done and if we hit all goals. Then we plan for the next 12 weeks (everything is of course viewable on our intranet). The time interval is just short enough for actual week-to-week plans while also being long enough to get things done.

We’re constantly updating and improving our work processes and will be updating this post as it happens.

If you like how we work and would like to join us, see our Careers page.

Strings in Python 2 and Python 3

The goal of this post is to show you how to properly use encode and decode in python 2 and in python 3. This post will be based on small examples that will (hopefully) make you better understand how strings work in python 2 and python 3.

A bit of background on unicode and UTF-8:

Unicode has a different way of thinking about characters. In Unicode, the letter “A“ is a platonic ideal. It’s just floating in “heaven”. Every platonic letter in every alphabet is assigned a magic number by the Unicode consortium which is written like this: U+0639 (in python “\u0639“).

UTF-8 is a system of storing your string of unicode code points (those magic “U+number“) in memory using 8 bit bytes.

One of the common questions for python 3 is when to use bytestring and when to use strings as an object? When you are manipulating string (e.g. “reversed(my_string)“) you always use string object and newer bytestring. Why? Here is an example:

my_string = "I owe you £100"
my_bytestring = my_string.encode()

>>> print(''.join([c for c in reversed(my_string)]))
001£ uoy ewo I
>>> print(''.join([chr(c) for c in reversed(my_bytestring)]))
001£Â uoy ewo I

 

The first print is what we expect but the second is not. And why is that? Well the “reversed“ function iterates over a sequence which in second case is bytestring which is b’I owe you \xc2\xa3100′. We can also verify this by checking the length of “my_bytestring“ and “my_string“:

>>> print(len(my_string))
14
>>> print(len(my_bytestring))
15

 

If I always just add “.encode()“ everything will be fine right? No! For start you should never call encode without specifying which encoding to use because then the interpreter will pick for you which will “almost” always be UTF-8 but there are some instances where this won’t be so and you will spent a lot of time finding this bug. So ALWAYS specify which encoding to use (e.g. “.encode(‘utf-8’)“). Example:

>>> print('I owe you £100'.encode('utf-8').decode('latin-1'))
I owe you £100

 

The other problem which is even bigger with “sprinkling” “.encode()“ is that if you already have encoded string you will get error (in python 3) or even worse (in python 2), you will do string operations on bytestring.

In python 2 “str“ is for strings of bytes and “unicode“ is for strings of unicode code points. The problem is that python 2 implicitly converts between types… sometimes. It allows you things like this:

>>> print((u'I owe you £100'.encode('utf-8') + 'Plus another $100').decode('latin-1'))
I owe you £100Plus another $100

 

This will quickly raise error when “Plus another $100“ becomes something that is not ASCII. If you try this in python 3 you get “TypeError: can’t concat bytes to str“.

If you need your code to run both on python 2 and python 3 then a rule of thumb is to first write a code for python 3 and then try it in python 2.
References: