Python Classes

It has taken me quite a while to begin to visualise and understand how classes work in Python. The thing with learning is that you can look at the same thing for days, weeks and months on end and then one day it randomly starts to make sense. This is completely normal and it appears to be how most people learn. I was recently creating a Django application by following along with a tutorial on  and suddenly classes in Python started to make a little more sense to me. I decided I would write about it today in order to help solidify the little bit of insight I had around classes in Python.

There are two key concepts that classes in Python possess - properties and methods.


Properties are the words you would use to describe the class. Let's say that you want to create a class for Blog posts. The properties are the typical things that every blog post will have in common. When you think of a typical blog post you will notice that each blog post will typically have a title field, a body field for the content of the post, an author field and a date time field. So the Blog Post class properties would look like this:


Blog Post

date and time



The methods are the typical actions that would be carried out on the class. In our example of the blog post we need to start thinking about common actions that would be carried out on blog posts. Typical actions for blog posts would be create, delete and save.

The methods on the Blog Post class would look like this.

Blog Post


Methods in Python contain executable code within them to carry out the action. The parentheses denote the fact that a function will be executed when the method is called.

I hope this helps to make the properties and methods within a typical Python class a little clearer to you.


Transition to PyCharm

Transition to PyCharm

The time has come to transition from using my  trusty iTerm and Sublime Text applications to using an IDE (Integrated Development Environment) called PyCharm. I would see this as transitioning from using a bicycle with training wheels to riding a motorcycle. It is my expectation that initially it will be difficult for me to find my balance when using PyCharm and that there will be some teething problems but in the long term I know that this adaption will allow things to run that bit more smoothly.

Clarity via Seperation

Prior to using PyCharm, I have been using two separate programs to run my Python scripts. I used Sublime text editor to write the scripts and iTerm2 to run the scripts. As a beginner it was useful to separate the components parts, in this way I could more clearly see what each component was capable of doing on its own. It also allowed me to reduce the effects of information overload and find my initial balance. Nevertheless this strategy, the practicalities of which were given to me by my programming mentor, for beginner mind clarity does come with some trade offs. The biggest trade off being a decrease in long term speed and effectiveness.

Merging back to One

PyCharm is an IDE which means that everything is self contained and runs within the same window. Basically my terminal and text editor are now both in the same application. This means that I no longer have to navigate from one application to the other in order run the simplest of scripts. I can now write and execute the script in the same environment. As I have only begun the transition this is purely a surface level understanding of the pros and cons and how the transition from one to the other looks.

Useful Tip: When you go to download PyCharm, I have been advised not to worry about purchasing the Pro version, the Community Edition is more than adequate to get started with.

Do you use PyCharm or are you thinking about using it? Did this blog post help to clear anything up for you? If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.


Simple Butter CMS Blog Integration for Flask

What is Butter CMS?

Butter CMS can be used to integrate a blog into your existing web app e.g. Flask or Django app. Butter CMS can alternatively be used as a CMS alternative to Wordpress. The beauty of Butter CMS is that it allows you to code in the programming language you know e.g. Python, Ruby on Rails etc. You can also create a CMS with customisable fields that make it user friendly for non technical people to work with. The functionality you have is according to whether you choose the Blog Engine, CMS or Free Presonal use plan.

For the purposes of integrating a simple Blog into my existing Flask app I chose to go with the Free Personal Plan. My goal was to use Butter CMS as a way to learn more about how API's work. I have found Butter CMS's API documentation to be user friendly, simple and to the point.


My goal was to add a Blog integration to my Flask Portfolio app using the Butter CMS API.

Step 1

You can sign up for a Butter CMS account for free here.

The Setup is relatively simple. You can choose Python as your language so that you use Python specific syntax:

I have put a red line through my API Key, you will find your API key under Settings.

Step 2

If you want to integrate Butter CMS into your existing Flask app then go to the Butter CMS Flask  Github Repository. Here you will find the files you will need to add to your app along with some instructions to execute.

Step 3

In your Flask app create a blog tab in your html menu. You can do this by adding another link to your menu in index.html or whatever html file you are using as your base template.

Step 4

As indicated on the above GitHub repository, copy the buttercms folder into the Flask app and register it as a blueprint by inserting the following piece of code into your file, or whatever you have called the controller file.

One thing that isn't mentioned is that you will also need to add an app route in your file in order to render the blog.html file that can be found within the buttercms folder:

Step 5

You can style the Blog to look like your app by editing the blog.html file. By default the individual blog post styling is inherited from blog.html.

Step 6

Hide API Key. You can learn about hiding the API key in my post Hide API Key for Heroku App.

Step 6

Deploy the app to Heroku so that the online app will now include the Blog section.

Step 7

You can now add new posts to your Blog by creating them in ButterCMS. The post is pulled into your Flask app via the Butter CMS API.


I have found Butter CMS support to be very responsive and you can even arrange a pair programming session with one of their developers if you feel lost.


Have you a better understanding of Butter CMS? Did this blog post help to clear anything up for you? If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.

Automate the Repetitive Stuff

Blue Arsed Flies

Speed can sometimes get a bad reputation. A large amount of unforced errors come from us as people trying to execute things like blue arsed flys. In any project there is a large amount of patience and attention to detail that is needed in order to avoid costly redo's. Nevertheless, speed is highly valuable when it is used in the spirit in which it was intended.

The Value of Speed

Speed simply means being more efficient with my time.  The reason Usain Bolt has won so many titles is simply because he can run 100 and 200 sprints faster than any other man on the planet. The key elements here are that his speed serves a purpose and that his speed is built on practice.

Automate the Repetitive Stuff

One of the initial things I noticed when I began to learn to code was just how fast the professionals do things. From navigating in terminal windows to typing and auto completing, everything seemed to be lightning fast to me. It would be easy for me as a beginner to think that these guys are just naturals and I will never be on their level, but thankfully I have the reference of language learning to let me know that this is the equivalent to how Spanish used to sound to me.

After a couple of months, with the help of my coding mentor, I began to see that there were certain areas that I could get quicker at. The key benefit of this speed is that it frees my thinking to focus on more higher level thinking.

Action Steps

The areas I chose to focus on were typing and terminal navigation. Before I began to code I never learned to type properly. This meant that I was only ever using a couple of my fingers to type and this greatly slowed down my long term efficiency. The past few weeks I have seen myself improve on this. I have spent 30 to 60 minutes each day on websites like Ratatype. I have found that listening to music allows me to do this with a lot more ease.

Another thing I initially had great difficulty with was navigating in the terminal window. The terminal window is basically a text based way of navigating the operating system with a lot more functionality and power than any GUI (Graphical User Interface). Initially I was in the habit of dragging and dropping files into the terminal window but I consciously took the decision to stop doing this. The problem was that I began to rely on the Finder window to help me visualise where I was in the Terminal window and when I didn't do this I spent a lot of time and energy trying to visualise where I was in the Terminal window. Initially this transition was difficult but now I am a lot more comfortable with navigating in the Terminal window.

Have you automated anything repetitive? What are your thoughts on the importance of speed? If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.

Hide API Key for Heroku App

Assign Variable on local machine

Open Terminal or iTerm. Enter the command env. This will give you a list of the environment variables that already exist.

You can edit environment variables by using an editor like nano or vim. You can find instructions here on how to edit the script using the bash or zsh shell.

In order to store the new value in the local environment with the zsh shell then you will need to edit the .zshrc file.

When editing with vim I didn't find quitting vim very intuitive, here you can find a list of the basic quit commands.

The variable is stored in a dictionary called os.environ.

To return the value of the new variable you set you can run the following commands within the Python shell:

import os


Or you can view the variable in the shell by running:

echo $'your_key_name'

The Python code in my Flask Portfolio file that refers to the local environment variable "Butter_CMS_Auth":

Assign Hidden Variables in Heroku

Now that the app is running on my local machine without including the API Key in my it is time to deploy the app to Heroku. But first we must find a way to refer to the BUTTER_CMS_AUTH key in Heroku, otherwise Heroku won't know what the below line is referring to:

client= ButterCMS(os.environ["BUTTER_CMS_AUTH"])


In Heroku under 'Settings there is a section called 'Config Variables'. Here you can assign your API Key to a variable name. You should use the same variable name as what you have previously used for the app to run locally on your Mac i.e. I used BUTTER_CMS_AUTH as the variable name.


If you want to see a list of the local variables on Heroku, you can use the printenv command when you are logged into Heroku CLI like below:


In here you should see your newly assigned variable name. When this is done you are good to go to deploy your Flask app online without having to worry about your API key being available in a public domain.


Are you struggling with hiding your API key? Did this blog post help to clear anything up for you? If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.


Buggy Python Code: The 10 Most Common Mistakes That Python Developers Make

About Python

Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components or services. Python supports modules and packages, thereby encouraging program modularity and code reuse.

About this article

Python’s simple, easy-to-learn syntax can mislead Python developers – especially those who are newer to the language – into missing some of its subtleties and underestimating the power of the diverse Python language.

With that in mind, this article presents a “top 10” list of somewhat subtle, harder-to-catch mistakes that can bite even some more advanced Python developers in the rear.

This Python found himself caught in an advanced Python programming mistakes.

(Note: This article is intended for a more advanced audience than Common Mistakes of Python Programmers, which is geared more toward those who are newer to the language.)

Common Mistake #1: Misusing expressions as defaults for function arguments

Python allows you to specify that a function argument is optional by providing a default value for it. While this is a great feature of the language, it can lead to some confusion when the default value is mutable. For example, consider this Python function definition:

>>> def foo(bar=[]):        # bar is optional and defaults to [] if not specified
...    bar.append("baz")    # but this line could be problematic, as we'll see...
...    return bar

A common mistake is to think that the optional argument will be set to the specified default expression each time the function is called without supplying a value for the optional argument. In the above code, for example, one might expect that calling foo() repeatedly (i.e., without specifying a bar argument) would always return 'baz', since the assumption would be that each time foo() is called (without a bar argument specified) bar is set to [] (i.e., a new empty list).

But let’s look at what actually happens when you do this:

>>> foo()
>>> foo()
["baz", "baz"]
>>> foo()
["baz", "baz", "baz"]

Huh? Why did it keep appending the default value of "baz" to an existing list each time foo() was called, rather than creating a new list each time?

The more advanced Python programming answer is that the default value for a function argument is only evaluated once, at the time that the function is defined. Thus, the bar argument is initialized to its default (i.e., an empty list) only when foo() is first defined, but then calls to foo() (i.e., without a bar argument specified) will continue to use the same list to which bar was originally initialized.

FYI, a common workaround for this is as follows:

>>> def foo(bar=None):
...    if bar is None:		# or if not bar:
...        bar = []
...    bar.append("baz")
...    return bar
>>> foo()
>>> foo()
>>> foo()

Common Mistake #2: Using class variables incorrectly

Consider the following example:

>>> class A(object):
...     x = 1
>>> class B(A):
...     pass
>>> class C(A):
...     pass
>>> print A.x, B.x, C.x
1 1 1

Makes sense.

>>> B.x = 2
>>> print A.x, B.x, C.x
1 2 1

Yup, again as expected.

>>> A.x = 3
>>> print A.x, B.x, C.x
3 2 3

What the $%#!&?? We only changed A.x. Why did C.x change too?

In Python, class variables are internally handled as dictionaries and follow what is often referred to as Method Resolution Order (MRO). So in the above code, since the attribute x is not found in class C, it will be looked up in its base classes (only A in the above example, although Python supports multiple inheritance). In other words, C doesn’t have its own x property, independent of A. Thus, references to C.x are in fact references to A.x. This causes a Python problem unless it’s handled properly. Learn more aout class attributes in Python.

Common Mistake #3: Specifying parameters incorrectly for an exception block

Suppose you have the following code:

>>> try:
...     l = ["a", "b"]
...     int(l[2])
... except ValueError, IndexError:  # To catch both exceptions, right?
...     pass
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
IndexError: list index out of range

The problem here is that the except statement does not take a list of exceptions specified in this manner. Rather, In Python 2.x, the syntax except Exception, e is used to bind the exception to the optional second parameter specified (in this case e), in order to make it available for further inspection. As a result, in the above code, the IndexError exception is not being caught by the except statement; rather, the exception instead ends up being bound to a parameter named IndexError.

The proper way to catch multiple exceptions in an except statement is to specify the first parameter as a tuple containing all exceptions to be caught. Also, for maximum portability, use the as keyword, since that syntax is supported by both Python 2 and Python 3:

>>> try:
...     l = ["a", "b"]
...     int(l[2])
... except (ValueError, IndexError) as e:  
...     pass

Common Mistake #4: Misunderstanding Python scope rules

Python scope resolution is based on what is known as the LEGB rule, which is shorthand for Local, Enclosing, Global, Built-in. Seems straightforward enough, right? Well, actually, there are some subtleties to the way this works in Python, which brings us to the common more advanced Python programming problem below. Consider the following:

>>> x = 10
>>> def foo():
...     x += 1
...     print x
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment

What’s the problem?

The above error occurs because, when you make an assignment to a variable in a scope, that variable is automatically considered by Python to be local to that scope and shadows any similarly named variable in any outer scope.

Many are thereby surprised to get an UnboundLocalError in previously working code when it is modified by adding an assignment statement somewhere in the body of a function. (You can read more about this here.)

It is particularly common for this to trip up developers when using lists. Consider the following example:

>>> lst = [1, 2, 3]
>>> def foo1():
...     lst.append(5)   # This works ok...
>>> foo1()
>>> lst
[1, 2, 3, 5]

>>> lst = [1, 2, 3]
>>> def foo2():
...     lst += [5]      # ... but this bombs!
>>> foo2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'lst' referenced before assignment

Huh? Why did foo2 bomb while foo1 ran fine?

The answer is the same as in the prior example problem, but is admittedly more subtle. foo1 is not making an assignment to lst, whereas foo2 is. Remembering that lst += [5] is really just shorthand for lst = lst + [5], we see that we are attempting to assign a value to lst (therefore presumed by Python to be in the local scope). However, the value we are looking to assign to lst is based on lst itself (again, now presumed to be in the local scope), which has not yet been defined. Boom.

Common Mistake #5: Modifying a list while iterating over it

The problem with the following code should be fairly obvious:

>>> odd = lambda x : bool(x % 2)
>>> numbers = [n for n in range(10)]
>>> for i in range(len(numbers)):
...     if odd(numbers[i]):
...         del numbers[i]  # BAD: Deleting item from a list while iterating over it
Traceback (most recent call last):
  	  File "<stdin>", line 2, in <module>
IndexError: list index out of range

Deleting an item from a list or array while iterating over it is a Python problem that is well known to any experienced software developer. But while the example above may be fairly obvious, even advanced developers can be unintentionally bitten by this in code that is much more complex.

Fortunately, Python incorporates a number of elegant programming paradigms which, when used properly, can result in significantly simplified and streamlined code. A side benefit of this is that simpler code is less likely to be bitten by the accidental-deletion-of-a-list-item-while-iterating-over-it bug. One such paradigm is that of list comprehensions. Moreover, list comprehensions are particularly useful for avoiding this specific problem, as shown by this alternate implementation of the above code which works perfectly:

>>> odd = lambda x : bool(x % 2)
>>> numbers = [n for n in range(10)]
>>> numbers[:] = [n for n in numbers if not odd(n)]  # ahh, the beauty of it all
>>> numbers
[0, 2, 4, 6, 8]

Common Mistake #6: Confusing how Python binds variables in closures

Considering the following example:

>>> def create_multipliers():
...     return [lambda x : i * x for i in range(5)]
>>> for multiplier in create_multipliers():
...     print multiplier(2)

You might expect the following output:


But you actually get:



This happens due to Python’s late binding behavior which says that the values of variables used in closures are looked up at the time the inner function is called. So in the above code, whenever any of the returned functions are called, the value of i is looked up in the surrounding scope at the time it is called (and by then, the loop has completed, so i has already been assigned its final value of 4).

The solution to this common Python problem is a bit of a hack:

>>> def create_multipliers():
...     return [lambda x, i=i : i * x for i in range(5)]
>>> for multiplier in create_multipliers():
...     print multiplier(2)

Voilà! We are taking advantage of default arguments here to generate anonymous functions in order to achieve the desired behavior. Some would call this elegant. Some would call it subtle. Some hate it. But if you’re a Python developer, it’s important to understand in any case.

Common Mistake #7: Creating circular module dependencies

Let’s say you have two files, and, each of which imports the other, as follows:


import b

def f():
    return b.x

print f()

And in

import a

x = 1

def g():
    print a.f()

First, let’s try importing

>>> import a

Worked just fine. Perhaps that surprises you. After all, we do have a circular import here which presumably should be a problem, shouldn’t it?

The answer is that the mere presence of a circular import is not in and of itself a problem in Python. If a module has already been imported, Python is smart enough not to try to re-import it. However, depending on the point at which each module is attempting to access functions or variables defined in the other, you may indeed run into problems.

So returning to our example, when we imported, it had no problem importing, since does not require anything from to be defined at the time it is imported. The only reference in to a is the call to a.f(). But that call is in g() and nothing in or invokes g(). So life is good.

But what happens if we attempt to import (without having previously imported, that is):

>>> import b
Traceback (most recent call last):
  	  File "<stdin>", line 1, in <module>
  	  File "", line 1, in <module>
    import a
  	  File "", line 6, in <module>
	print f()
  	  File "", line 4, in f
	return b.x
AttributeError: 'module' object has no attribute 'x'

Uh-oh. That’s not good! The problem here is that, in the process of importing, it attempts to import, which in turn calls f(), which attempts to access b.x. But b.x has not yet been defined. Hence the AttributeError exception.

At least one solution to this is quite trivial. Simply modify to import within g():

x = 1

def g():
    import a	# This will be evaluated only when g() is called
    print a.f()

No when we import it, everything is fine:

>>> import b
>>> b.g()
1	# Printed a first time since module 'a' calls 'print f()' at the end
1	# Printed a second time, this one is our call to 'g'

Common Mistake #8: Name clashing with Python Standard Library modules

One of the beauties of Python is the wealth of library modules that it comes with “out of the box”. But as a result, if you’re not consciously avoiding it, it’s not that difficult to run into a name clash between the name of one of your modules and a module with the same name in the standard library that ships with Python (for example, you might have a module named in your code, which would be in conflict with the standard library module of the same name).

This can lead to gnarly problems, such as importing another library which in turns tries to import the Python Standard Library version of a module but, since you have a module with the same name, the other package mistakenly imports your version instead of the one within the Python Standard Library. This is where bad Python errors happen.

Care should therefore be exercised to avoid using the same names as those in the Python Standard Library modules. It’s way easier for you to change the name of a module within your package than it is to file a Python Enhancement Proposal (PEP) to request a name change upstream and to try and get that approved.

Common Mistake #9: Failing to address differences between Python 2 and Python 3

Consider the following file

import sys

def bar(i):
    if i == 1:
        raise KeyError(1)
    if i == 2:
        raise ValueError(2)

def bad():
    e = None
    except KeyError as e:
        print('key error')
    except ValueError as e:
        print('value error')


On Python 2, this runs fine:

$ python 1
key error
$ python 2
value error

But now let’s give it a whirl on Python 3:

$ python3 1
key error
Traceback (most recent call last):
  File "", line 19, in <module>
  File "", line 17, in bad
UnboundLocalError: local variable 'e' referenced before assignment

What has just happened here? The “problem” is that, in Python 3, the exception object is not accessible beyond the scope of the except block. (The reason for this is that, otherwise, it would keep a reference cycle with the stack frame in memory until the garbage collector runs and purges the references from memory. More technical detail about this is available here).

One way to avoid this issue is to maintain a reference to the exception object outside the scope of the except block so that it remains accessible. Here’s a version of the previous example that uses this technique, thereby yielding code that is both Python 2 and Python 3 friendly:

import sys

def bar(i):
    if i == 1:
        raise KeyError(1)
    if i == 2:
        raise ValueError(2)

def good():
    exception = None
    except KeyError as e:
        exception = e
        print('key error')
    except ValueError as e:
        exception = e
        print('value error')


Running this on Py3k:

$ python3 1
key error
$ python3 2
value error


(Incidentally, our Python Hiring Guide discusses a number of other important differences to be aware of when migrating code from Python 2 to Python 3.)

Common Mistake #10: Misusing the __del__ method

Let’s say you had this in a file called

import foo

class Bar(object):
    def __del__(self):

And you then tried to do this from

import mod
mybar = mod.Bar()

You’d get an ugly AttributeError exception.

Why? Because, as reported here, when the interpreter shuts down, the module’s global variables are all set to None. As a result, in the above example, at the point that __del__ is invoked, the name foo has already been set to None.

A solution to this somewhat more advanced Python programming problem would be to use atexit.register() instead. That way, when your program is finished executing (when exiting normally, that is), your registered handlers are kicked off before the interpreter is shut down.

With that understanding, a fix for the above code might then look something like this:

import foo
import atexit

def cleanup(handle):

class Bar(object):
    def __init__(self):
        atexit.register(cleanup, self.myhandle)

This implementation provides a clean and reliable way of calling any needed cleanup functionality upon normal program termination. Obviously, it’s up to foo.cleanup to decide what to do with the object bound to the name self.myhandle, but you get the idea.


Python is a powerful and flexible language with many mechanisms and paradigms that can greatly improve productivity. As with any software tool or language, though, having a limited understanding or appreciation of its capabilities can sometimes be more of an impediment than a benefit, leaving one in the proverbial state of “knowing enough to be dangerous”.

Familiarizing oneself with the key nuances of Python, such as (but by no means limited to) the moderately advanced programming problems raised in this article, will help optimize use of the language while avoiding some of its more common errors.

You might also want to check out our Insider’s Guide to Python Interviewing for suggestions on interview questions that can help identify Python experts.

We hope you’ve found the pointers in this article helpful and welcome your feedback.

This article is originally posted in Toptal.

Numbers in Python

There are two main types of numbers in Python that you need to be aware of as a beginner Pythonista.


Integers are positive or negative whole numbers. Integers do not include decimal numbers. You can assign a variable to a whole number and then use that variable to return the number.

Examples of integers

2, 89, -450


Floats are numbers that include a decimal point. Floats do not include numbers that do not include a decimal point i.e. integers.

Examples of Floats

2.54, -98.0


You can also add, subtract, multiple or divide two numbers, either integer or float together by using their variables:








There is also an extra operator called floor division (//) which will round down a division that isn't a perfect integer:

Python Strings


Strings are constructed in Python by enclosing letters or numbers within quotation marks. E.g. both "this" and "123" are strings. A string can also be a complete sentence wrapped inside quotation marks "this is also a string".

Single or double quotations can be used but they can't be mixed. E.g. "this" and 'this' are valid but not "this'.

Escape Characters

But what if the word itself contains a comma? Well, I'm glad you asked. In such a case you could simply choose to wrap the string in double quotes:

"This was a tricky one but now it's OK because I have double quotations"

With the inital hurdle jumped, it's on to the next question. What if there are quotations marks within a sentence that also contains a single quotation mark? In such a case you can use the escape character, otherwise know as the backslash character:

"Will said that \"the tricks of the course get progressively deceptive\" that's something I tend to agree with"

The backslash effectively says 'Hey Python, you can ignore the quotation marks or any commas as it isn't the end of the string.

String Concatenation

String concatenation is just a fancy way of saying adding two strings together. If you want to have a space between the words then you need to insert a space either at the end of one string or the beginning of the next:

"Hello" + "World" = "HelloWorld"

"Hello " + "World" == "Hello World"

String concatenation is also useful when you want to add numbers in sequence rather than by value:

"1" + "45" = "145"


Important String Methods

There are a lot of different string methods. The following are the methods I have found the most useful to know about as a beginner:

string.lower()  - turns all string elements in a string into lowercase

lower_string = "lowErcasE"

lower_string.lower() = 'lowercase'

string.upper() - turns all string elements into uppercase

upper_string = "UppErcasE"

upper_string.upperer() = 'UPPERCASE'



Strings are iterable which means that you can you can return each member of a string one at a time. You can use the element's index to do this. An index is the location of the element in the string. Indexes in programming are zero based, they start at 0, this takes a little getting used to but will come more natural to you with practice.

string1 = "hello"

string1[0] will return "h"


String Manipulation

The length of a string can be calculated using the len() method.

len(string1) = 5

The count() method counts instances of a character or space in a string:

string1.count('e') = 1


String Slicing

Parts of a string can be returned using string slicing. Slicing can take a start and an end index value. The key thing to keep in mind is that the slice will return the starting index and go up to but not including the stop index. This takes a little bit of time, patience and practice to get used to.

The first index is included by using either 0 or a blank space and the last index is included with a blank

string1[:] = "hello"

string1[1:3] = "el"

string1[:-1] = "hell"


Join String

The join() method joins a string with an element like a space.

join_string = "Hello World"

comma= ", "

comma.join(join_string) = "H,el,l,o ,W,o,r,l,d"

Strip String

The strip() method returns a copy of the string in which the characters specified at the beginning and end of the string are removed, useful for white space removal:

split_string = " Hello "

split_string.split() = "Hello"


Remove All Whitespace

test = "this is a whitespace test"

"".join(test.split()) = "thisisawhitespacetest"

Add Whitespace

test2 = "this is a whitespace test"

"".join(test2.split()) = "this is a whitespace test"


Another useful thing to keep in mind are the list of Python keywords that shouldn't be used as variables. A variable is the name you a assign to a value.


my_variable = "Done for today"

variable  is my_variable

= is assign symbol

"Done for today" = value



Are you new to Python? Did you find this blog post useful? Have you any questions? If so I would love to hear from you in the comments section below or by dropping me an e-mail.

Areas for Improvement - Week 28

You can't more to where you want to go if you don't know where you are or what direction to head in. With this in mind here are a few areas for improvement that I am working on:


Clever Programmer published a useful video this week on Why Being Faster will Make you More Money. I would tend to agree with him, it makes logical sense that if you can work with more speed, without sacrificing precision, then you will be more effective in what you do. In this video he mentions the website Nitro Type Race  I have played this a couple of times now and I have found it an enjoyable way to practice my typing speed. My current speed is about 50 wpm so there is a lot of room for improvement. I have decided to go to this website at least once a week to increase my typing speed in the long run.

Navigate the OS with Terminal

Up until last week I have been using the Finder window to drag and drop to where I want to be within terminal. I have been doing this with the misunderstanding that this is more efficient than navigating to a folder within the terminal window. It has been pointed out to me by my Python mentor that this isn't more efficient. The effect has also been that I am not as comfortable in the terminal window. When I paused to think about it, I realised that he was right. I am not used to navigating to a folder without going to Finder to drag and drop the folder path into terminal and so I have to think a lot more when I am within terminal. When I wasn't using terminal to navigate to folders I found that it was hard for me to visualise where exactly I was in the terminal and how I could navigate to the folder I wanted to be in. I also was using less terminal commands less frequently, commands like ls to list the contents of a folder and  cd with the folder path to navigate to a folder. As a result these commands are less likely to be in my muscle memory and automatic way of thinking.

Python Functions within Flask

One of the key areas I am currently struggling to come to terms with is incorporating a self contained Python function within a Flask app. This week I have been working on incorporating an API into my Flask app. I have chosen to work on a Google Maps integration. I followed a few videos on Youtube which showed me how to create the following Google Maps API script:

This script works exactly how the videos show but when I go to incorporate it into my Flask app I run into a few issues. First of all the function needs to be split because the input comes from a form in a html file rather than from the address variable within the function. I find that this takes a bit of getting used to as my focus and attention are automatically split across a wider area.

In the Flask app the Python function is written in an file below:

The input comes from the user within a form on the google_maps.html file:

Return, Print issue

In my original Python function on GitHub you will notice that there are a few places where the print statement is used. These statements provide some extra detail to the user like the API Status. The function returns the following result:

The issue with my function in Flask is that I can't use the print statement within the function to add more details. Instead I need to assign the answer to a variable called result that will then print the answer to the screen using the corresponding {{result}}, see Jinja2 templating, variable on the google_maps.html page

So there you have it, the key areas I am working through on Week 28 of my Python learning journey. If you have an insights, recommendations or questions then feel free to leave a comment or send me an email.



Hackerrank Tuple Thought Process

Today I decided to tackle the Tuples problem set on Hackerrank. It is categorised as Easy but it was quite a challenge for me. The following is how I arrived at a solution and what my thought process looked like.

Tutorial Section

There is a section called Tutorial at the top of the problem set. You can use this to find out more about what a tuple is and what it can and can't do. After you have submitted your solution or attempted a couple of times, the Discussion section is often worth a look.

Rephrase the Question

Questions on Hackerrank have a tendency to be wordy and difficult to comprehend. I have a feeling this ambiguity is intentional and it is probably good preparation for interviews on the job market. Before I even begin to tackle the problem, I now spend time simplifying the question so that I can more easily assimilate what is being asked.


Create a tuple of integers and return the hash of these numbers.

Task Breakdown

  1. Accept input from user in the form of a string.
  2. Convert string to list of integers.
  3. Convert list to tuple
  4. Return the hash value of tuple.

Tuple Properties

As I haven't been dealing with Tuples on a regular basis, the characteristics of a tuple are not freely available to me from memory, so a little digging was required. Here are 3 points worth noting about tuples.

  1. The key difference between a list and a tuple is that a tuple is immutable, which means we cannot modify a tuple, a list by contrast is mutable.
  2. The parentheses are optional, the below values are the same:

    my_tuple = (1, 2, 3)

    my_tuple = 1, 2, 3

  3. A comma is needed after a single element, otherwise Python will think it is an integer or a string:

          a_tuple = (1,)

          an_integer = (1)

          a_string = ("1")

When to choose a Tuple over a List

Lists are generally used over tuples due in large part to the versatility of lists. However, a tuple would be useful if you want to iterate over a very large list quickly and you do not wish the items of the list to change. A tuple also takes up less space in memory. This can be observed by importing the sys module and using the getsizeof function, the size is measured in bytes:

Here is a useful video by Socractica on tuples.

Problem Solving Process


In the problem itself we are given the following code block:

if __name__ == '__main__': n = int(input()) integer_list = map(int, input().split())

You can ignore if __name__ == '__main__':  because it doesn't directly impact the code.

The int(input()) function takes input from the user in integer form, again it doesn't directly impact the solution and the reason is given in the discussion section.

I needed clarification on what the split method does, which I found here.

I then needed to read about what the map function does.

From the problem itself you can see that a list has been assigned. The next steps are to create a tuple and then return the hash. As stated in the question the hash is a built in function in Python so it is not necessary to import a new module.

Once you have attempted the problem or even solved it, you can find a comprehensive breakdown of the problem under the discussion section I have referred to.


Something I have found useful is running the solution in my text editor and terminal window while solving the problem. This allows me to get real time feedback and it allows me to print output that I would like to see, e.g. the contents of the list or the tuple before the hash is returned.


Did you find this post useful? Do you use Hackerrank? If so I would love to hear from you in the comments section below or by dropping me an e-mail.



Useful Shortcuts for Mac Users

1. Use Spotlight to navigate your Mac. This means you can hide the dock when not in use (under Dock Preferences). This gives you more screen space to work with. Navigating with the Spotlight shortcuts also will quicken speed over time.

Spotlight = cmd + spacebar


2. Multiple Desktops

The 13" screen can be quite limiting when you are coding. If you don't want to splash out on a second monitor then you can use the multiple desktop functionality that Mac OS has. Click the F3 button on your keyboard and you should get this:

Multiple Desktops

Now simply drag your application into the second desktop. The best way to navigate is by using four finger swipe on the trackpad or alternatively you can press ctrl + left arrow or ctrl + right arrow.

3. Browser

Open new tab = cmd + t

Highlight the URL = cmd + l

4. Sublime Text for Mac

Delete line = cmd + backspace 

Organisation Tools for Mac


Magnet is a window manager downloadable from the App Store. Magnet saves me the hassle of manually organising my screen each time I turn on my Mac. I can simply click on the drop down commands that effortlessly order my screen in a matter of clicks. Magnet costs €1.09 the last time I checked the Mac App Store.

Window split in three screens with Magnet.


Screen Organisation in a matter of a few clicks

Screen Organisation in a matter of a few clicks


The Subtle Art of Pseudocode and Winging It

Split Logic and Syntax On a recent 1 to 1 call with Rafeh Qazi I discovered the importance of pseudocode for programmers. Coding isn't easy for any beginner so it would make sense that we would try and make the process as simple as possible for ourselves. This sounds highly rational, but our emotional mind often overpowers our rational mind. The emotional mind has a tendency to try and wing things even though the rational mind knows that this doesn't lead to consistency or any meaningful progress.

The Problem Set

I will paraphrase the problem set that Qazi gave me as follows:

Create a function that detects if a word ends with ing. If it does then change the word to it's infinitive, e.g. building would become to build. Otherwise return not a gerund


What Winging it Looks Like

If you were wondering, here is the end result:


gerund_infinitive function in chaos

As you can see from the above code, when I tried to wing it under time constraints my brain tried to remember everything I had learned so far and there was a mismatch of information. I knew how to iterate backwards over a string  but I didn't know how to stop. For some reason the fact that the list counts backwards from -1 and not zero still doesn't come naturally to me. This is in spite of the fact that when I take a few minutes to think about it logically it makes sense to me again. When under a time constraint I also failed to recognoise that letter could only be equal to a single letter not three.

Pseudocode - Simplicity amidst Chaos

Thankfully there is an answer to this madness. Pseudocode splits logic and syntax so I can deal with one challenge at a time. It may surprise people outside the field of programming to hear that human logic is the hard part. Even as a beginner, I can see that the syntax begins to write itself once my brain comes to terms with it. The brain comes to terms with a new syntax from practice and repetition. My conviction behind this belief stems from language learning. Here is an example of the same problem with pseudocode. In Python you can write comments in your code by putting the # symbol before the text:

gerund_infinitive with pseudocode

Problem Breakdown

As you can see in the comments section in the above code, we broke the problem down into each of it's component parts. The simplest thing to begin with is to return the not a gerund statement. This means that any words that don't end with ing won't even make it past the not a gerund statement.

If however they do make it past this initial check, they will move onto the next stage, which is the else statement. As a beginner I still tend to get this logic backwards, perhaps because the wording of the problem still throws me off balance. The best way for me to remember the logic is to come up with an analogy. The subconscious mind thinks in pictures so I am far more likely to remember an analogy.

I imagine I am trying to get into an exclusive nightclub called the ING. There are 2 bouncers at the door checking ID's. This is an exclusive club and they want to stand out, so instead of checking for age they are checking to see if my last name ends in ing. If it doesn't they won't let me in. I decide to chance my arm but when I get to the door they turn me away because I am a Murphy. That's it night over before it even began! Some of my other friends get in and leave me outside, 'nice to know who your friends are' I think to myself. I then think 'screw them all, I will start my own nightclub and show them all!!'

Can you see the powerful emotions we create from stories and analogies? We don't tend to forget emotions as easily as logic.

The last part is the else statement. If the word has made it this far then the word does end with ing. So now we need to remove the letters ing? Well not exactly. Let's go back to the analogy for an explanation here.

Seeing as the person has made it into the nightclub because there surname ended with ing, it would be a little silly if we discarded the criteria they got in with. We want uniqueness in our nightclub but we don't want to take some of our clients identity away to get this. So, we decide they can keep their ing but as everyone else has ing in their surname we will just print their name badges up until the ing part.

Thankfully the 'to ' part is constant so we can now just concatenate the string with 'to ' + <string> . Concatenation  is the term that is used to describe adding items together. It stems from the latin verb concatenare which means to link together. It is important to have the trailing space after 'to ' within the string so that you get the result 'to build' and not 'tobuild'


Did you find this blog post useful? Have you used analogies in the past to help you remember things? If so I would love to hear from you in the comments section below or by dropping me an e-mail.

Playing Darts with Turtle

Let's Play Darts 

The dart board challenge on is a nice challenge where anyone can follow along. It helps to give you a glimpse at the power and precision behind the Python programming language, without any prerequisite knowledge of programming. It is also a great way for a beginner to relax and have fun while messing around with Python commands.

The dart board challenge uses Turtle. You can learn more about the PythonTurtle environment here.

If you would like to try out the challenge for yourself then head on over to the Bullseye Challenge.

Beginner Play with

Building Momentum

Learning something new is quite often about building a sense of momentum. When we can see tangible results it gives us more of an incentive to continue and persevere past further obstacles. Momentum is especially important in the initial stages. At the beginning we are often prone to a feeling of overwhelm. This overwhelm comes at us from a variety of places. It can come from the imposter syndrome, that sense of I don't belong here, which ironically is a common experience. Overwhelm can also be felt when we look at the road ahead instead of focusing on the steps we can take today. Unfortunately, there are people in every field who will try and make things appear more difficult than they are, in order to feed their own ever expanding ego and sense of self worth, and this can also leave us with a sense of overwhelm.


It was a couple of months ago that I had one of these early momentum experiences with Python. Up until this point I was ignorant to the existence of the Turtle module. Looking back on it I probably didn't have much of an understanding of what a module is. The great thing is that you don't need to fully understand what a module is in order to use one. You just need to see how you can use it and naturally as you stick with the long term goal you will become curious enough to understand the concept at a deeper level. I discovered the Turtle module as part of the Learn Python for Beginners Course.

If you don't feel ready to venture too far into learning to code then there is a great online IDE called trinket. The great thing about trinket is that it leverages the turtle module. You can run or edit some basic code and create drawings with it. You can then share your output just like the one I have shared with you at the bottom of this page. You can use this resource as a complete novice and come away with a feeling of being a programmer.

The code comes as a template with a working graphic. I made some very simple customisations to my graphic. I edited some of the on screen messages, I edited the font size and I increased the speed of the turtle icon with the speed module. In order to increase the speed I simply went on Google and searched for "Increase speed of turtle in Python" and I clicked on this article:

Turtle Graphics for Tk

I then searched for the word speed in the article by using cmd + F on the Mac and entering the search word speed. My second result for speed returned:

  • “fastest”: 0
  • “fast”: 10
  • “normal”: 6
  • “slow”: 3
  • “slowest”: 1

To use the slowest speed you enter


Did you find this blog post useful? I am continuously looking for ways to improve on the content so that my readers have the best experience possible. If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.

A Gateway to Programming

Initial Obstacle Believe it or not, the biggest initial obstacle I faced when learning Python was installing the basic tools I needed. HTML and CSS were more accessible to me by the simple fact that I didn't need to install anything in particular to start learning. However, learning a programming language like Python was different. I felt like I needed to do some homework before I even began to learn.

Python 2 and Python 3

When you start to learn Python you will see that you are met with two different versions. From what I can gather so far there is little difference between the two. The most obvious distinction I have seen is the difference in how print works. Print is used to print output to the screen. In Python 3 print is a function whereas in Python 2 it is a statement:

Python 2 print statement:

print "Hello World"

Python 3 print function:

print("Hello World")

As you can see the only syntactical difference is the brackets needed to execute the print function in Python 3

You can read more about the differences between Python 2 and Python 3 here.


At the most basic level you will need to first install a verion of Python on your Mac or PC. You can go to to download either Python 2 or Python 3. You will then need a text editor and either terminal on the Mac or command prompt on Windows. A popular text editor that I like to use is Sublime Text .

Where I ran into confusion was the fact that my Mac already came pre-installed with Python 2. Therefore when I wanted to run a script I was often running the wrong version of Python. It was only recently that I was able to write a post about the key difference when running a script in terminal when I was trying to use the tkinter module. I also had to do what seemed like a lot of reading and poking around because programming was still very foreign to me.


I later learned about online IDE's like repl and Codeskulptor . As a beginner programmer or someone who is just curious about programming, these tools are invaluable. These tools mean that you can play with Python online. You can run your first "Hello World" program without a single installation. If I were to begin again I would start tinkering around with online IDE's as my first port of call.


Did you find this blog post useful? I am continuously looking for ways to improve on the content so that my readers have the best experience possible. If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.


My Very First Python App - A Digital Bookmark

Persistence without Focus or Direction When I first began to study Python programming a few months ago, creating an app, no matter how simple, seemed like a pipe dream. While I was beginning to understand some of the Pythonic concepts in theory, I didn't know how to apply them. I battled on with broadly unrelated books, articles and courses, but this inevitably lead to a lack of focus and belief on my part. I knew the principles behind learning something new, but it seemed like I spent a lot of time in persistence mode while being out of sync with the focus and incremental progress that I also needed.

Connect the dots with Python OOP

Prior to taking the Python OOP Course I had read a little bit about object oriented programming but not an awful lot sank in. I was still coming from a place of trying to comprehend what a function, class and method was. This course has given me a sense focus and direction that I previously didn't have. I firmly believe in starting small, keeping things as simple as they possibly can be, and building on my skill sets from a solid foundation. I feel this course has given me this along with the practicalities of tangible apps to start a portfolio with. The great thing about this course is it's ROI on time and money. A student could easily get through the course in a matter of hours. Personally, I have chosen to gradually work my way through it while working on solving other problems and using other resources for learning Python. My first real app that I have made as part of this course is the below version of a digital bookmark.

Digital Bookmark

As part of the Python OOP course, I recently created a bookmark for my favourite websites.  I used the tkinter module to create the window.

Screen Shot 2017-04-21 at 09.31.10

Bookmark Customisations

I made two main customisations from the tutorial I followed.

  1. Change background colour.
  2. Include an image.

To do this I had to do my own research. It would be much easier for me to stick to exactly what I am shown but that is not what I am encouraged to do, and I won't be able to retain the principles behind what I am learning if I do so. While my mind can sometimes be lazy, I find that it is often open to making small tweaks. Below is a description of the two adjustments I made, while my mind was telling me this seems like too much work:

Background Colour

To change the background colour of the window I simply had to add this line of code:


Sometimes the most noticeable changes are the easiest to implement :)

Adding an Image

I imported the PhotoImage module from tkinter in order to insert the GIF image.

from tkinter import PhotoImage

P1 = PhotoImage(file="image.gif")

I initially wanted to use a JPEG image but it wouldn't work for me. From what I read it seems to be easier to insert a GIF image in tkinter. I don't fully understand why this is but I felt that it wasn't necessary at this stage to pursue the answer any further. Once I saw that the GIF image appeared, I then spent my time positioning the image to where I liked it best.


I used the .grid method to position the elements in the bookmark window. There are 3 main ways to position in tkinter

  1. Pack
  2. Grid
  3. Place

When using the .grid method the window is divided into grids with unique coordinates for row and column. The positioning is relative. For items to appear horizontally the row value remains constant while the column values increment, for items to appear vertically the column values remain constant while the row values increment. Here is a table to demonstrate this logic when inserting buttons in a window with the .grid method:

Vertical Buttons Horizontal Buttons
column=0 row=0 column=0 row=0
column=0 row=1 column=1 row=0
column=0 row=2 column=2 row=0
column=0 row=3 column=3 row=0

Here is a tutorial on tkinter positioning, that goes into more detail.

DRY (Don't Repeat Yourself) example

The Cleverprogrammer landing page and the Cleverprogammer Blog have the same beginning to the URL. The only difference is that there is a /blog in the blog URL. Therefore, in the course, we created a variable called URL and to direct to the blog we simply used the variable name URL + /blog.

View the Source Code here

So there you have it, with my first app in Python now completed, I am looking forward to seeing what problems and apps I can tackle next :)

Did you find this blog post useful? I am continuously looking for ways to improve on the content so that my readers have the best experience possible. If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.

80/20 Python & Garden Peas

The Birth of the Pareto Principle The seed of the 80/20 principle germinated, of all places, in an Italian pea garden. It was peahere that the economist Vilfredo Pareto observed that only a 'vital few' of the pea pods in his garden produced the majority of peas. He went on to use this principle to demonstrate that 80% of the land in Italy was owned by 20% of the population.


I believe there is truth in the maxim

 how you do anything is how you do everything

Ever since applying the 80/20 rule to language learning I frequently view the world through this lens.

Python 80/20 in action

When I learn something new I start by reading around the topic and taking some online courses. Usually these courses are short and free, but not always. This period could last anywhere from a few weeks to a few months, depending on the difficulty of the topic, how natural it comes to me and my current level of knowledge in it. For Python, I spent about 3 months before I made my 80% decision. Generally I will spend enough time to catch a glimpse of the 'bigger picture', I then look to focus about 80% of my learning on one resource. The other 20% is divided among a handful of other resources, that alternate and change as my level of knowledge increases.

80% 'in' is often a wiser move than 'all in'

For the sake of clarity, 80/20 isn't an exact measurement, it is a quick and relatively accurate ratio. Our brains are hardwired to make sense of the world through generalisations. If our brains were incapable of doing this, then the world would appear to be a much more difficult and scary place for us to live in. Instead of using this mechanism to ingrain stereotypes deeper into my head, I have chosen to leverage this innate capacity, when I scan the world with 80/20 goggles on.

The main reason I don't go 'all in' on a single resource is that I find that this approach often leaves me 'blinkered'. Even if I have the best mentor in the world, he/she is only human, and humans can only experience their own thinking no matter how hard we may try. Therefore, even if he/she is Six Sigma gold and makes a handful of mistakes per million, that could still be a few mistakes more than I may need to personally make.

I also believe that when I have a narrow focus of  attention on one single person or area, it leaves me wide open to becoming a victim of a dogmatic approach. What I look for in a good mentor is that they not only encourage me to use my common sense but they also recommend resources that they have found valuable themselves. This demonstrates that they are a team player and that they are doing the best they possibly can to help their students.

My 80/20 Python Plan

My goal for learning Python is to become a more effective problem solver, create personal projects, freelance and potentially become a Software Developer. With these goals in mind, I have included the below table of my 80/20 learning plan. My learning is centered around Clever Programmer because the platform is in alignment with my personal goals.

80 20
Cleverprogrammer SoloLearn
Project Euler
Code Fights
Talking to Friends/ Meetup Groups


Did you find this blog post useful? I am continuously looking for ways to improve on the content so that my readers have the best experience possible. If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.

tkinter, Tkinter in a Graphical World

Screen Shot 2017-04-12 at 18.09.32 I successfully ran my first import of the tkinter module this week. tkinter is a module I have been aware of in the past but it isn't something I was able to use until now. The code I wrote as part of the Python OOP course allowed me to create the above GUI (Graphical User Interface) window with the word Banana. This may not look like much but I think it is incredible how quick and simple this can be created in Python. While it is simple I don't want to give you the false impression that it is easy. Even while taking a course, I find that a beginner mind, will tend to find mistakes for you. It is almost like perseverance is a shadow that follows you around every corner until you learn to see through its self created nature. The biggest obstacle I have encountered so far reappeared once again, when I was trying to import the tkinter module. I followed the code exactly as it was writtenScreen Shot 2017-04-12 at 17.59.35 in the course video. I must have rechecked these 7 short lines of code about 20 or 30 times and I spent some time trawling the internet for an answer. I was left feeling frustrated, but knowing that I wasn't going to quit, I decided to deflect my attention to solving problems in the 'easy' section on HackerRank. I generally find HackerRank problems tricky but not too tricky. This strategy allows me to keep building on the invisible force of nature that is momentum.

It may have helped if I were able to assimilate the ImportError: No module named tkinter that appeared in terminal but as a novice programmer I don't always find my intuition guiding me to read the error and think of some logical explanations. In this case, the error seems more like an outlier for a beginner programmer rather than a rule to soak into my awareness.


I put tkinter to the back of my mind and I eventually found the answer when on a call with my Python mentor. The mistake was so simple it was almost embarrassing. When trying to run my file , I was attempting to run the below terminal command:


On my MacBook by default this will launch Python 2.

I should have typed:


This would have launched Python 3. My MacBook comes preinstalled with Python 2, I manually installed Python 3 when I began to learn Python. There is also the alternative to make python an alias of python3.  The reason there is an issue in the first place is that in Python 2 the word Tkinter is capitalised and in Python 3 it isn't. The problem I encountered was that the GUI window would fail to launch when I ran the Python script because Python 2 does not recognise tkinter as a module.


When looking back on the process I can see that I was caught in the trap of over complicating a problem that had a simple fix. It is the same feeling a student gets when challenged by a curious philosopher with the below task:

Prove this chair does not exist

In effect, I tried to come up with some complex theory that would explain the existence of the chair. As long as I was looking in this direction I would never find the fix, simply because the more time I spend looking in the wrong direction, the less likely I am to find the simple fix right in front of me. What allowed me to eventually look in the other direction was giving myself distance from the problem by putting it to the back of my mind, and by having a mentor that had already been there and done that.


Did you find this blog post useful? I am continuously looking for ways to improve on the content so that my readers have the best experience possible. If you have any insights, questions or recommendations feel free to leave a comment or drop me an e-mail.