Welcome to my getting started with Web2py tutorial.
This tutorial assumes very little on the part of the reader, some knowledge of a programming language will certainly help, but if not don’t worry. I’ll take you from installation through to v1 of your application.
If you don’t want to copy from the tutorial, the full source is hosted on github.
Last time we created the Models as well as the Controller and View for the home page. The next page to look at is the Wall. The Wall is specific to a given user and contains their profile details as well as their weet history.
As before we start with in the default.py Controller, add the following method to manage the behaviour for the wall.
# show user's wall, showing profile and posts def wall(): #Determine which user's wall is to be displayed user = db.auth_user(request.args(0) or me) #If user is invalid, return to the home page if not user: redirect(URL('home')) weets = db(db.weets.posted_by==user.id).select(orderby=~db.weets.posted_on,limitby=(0,100)) return locals()
The first thing to do is determine whose wall it is that we need to display. The line responsible is worth a closer look.
user = db.auth_user(request.args(0) or me)
We have already seen db used as a means to access the database but we have not yet come across ‘request’. Request is an object available to all Controller actions and provide details of the http request that instigated the Controller action being called.
In this case we check the first (technically the zeroth) argument of the request. An argument is best described by example
http://127.0.0.1:8000/witter/default/wall/myargument/myotherargument/
In this specific instance the argument denotes the user id and so the line in question checks if a user id has been specified, if not it assumes that the requester are themselves logged in and trying to access their own wall. If neither case is true then the browser is redirected to the home page.
After that we pull out all the weets for the given user and return local variables, which are then made available to the View.
We will need a new View file called default/wall.html. As before you can create it via the application admin page.
Replace the default code with :-
{{extend 'layout.html'}} <h2>Profile</h2> {{=crud.read(db.auth_user,user)}} <h2>Messages</h2> {{for weet in weets:}}{{pass}}{{=name_of(weet.posted_by)}} on {{=weet.posted_on}}:
{{=MARKMIN(weet.body)}}
We’ve met crud before, it provides a nice high level abstraction to access database information, in this instance we are using it to pull the profile information about the user. The next section loops through all the weets generated in the Controller and presents them in chronological order – this very much the same logic as we saw on the home page. You can a look for yourself at http://127.0.0.1:8000/witter/default/wall or just navigate there from the Witter home page using the navigation bar at the top.
Search
For the grand finale let’s look at search.
The purpose of this page is to allow a user to search for their friends and then follow them. In some senses it is the simplest of the pages, but as we shall see it contains some interesting functionality behind the scenes.
Firstly, let’s take a look at the Controller, add the following to default.py
# a page for searching for other users @auth.requires_login() def search(): form = SQLFORM.factory(Field('name',requires=IS_NOT_EMPTY())) if form.accepts(request): tokens = form.vars.name.split() query = reduce(lambda a,b:a&b, [db.auth_user.first_name.contains(k)|db.auth_user.last_name.contains(k) for k in tokens]) people = db(query).select(orderby=db.auth_user.first_name|db.auth_user.last_name,left=db.followers.on(db.followers.followee==db.auth_user.id)) else: people = [] return locals()
The first thing we do is create the search form, we do this like so
SQLFORM.factory(Field('name',requires=IS_NOT_EMPTY()))
The SQLFORM.factory can be used to generate a from an existing database table, or, as in this case can be used to generate a form from scratch. The form is very simple and takes a single input ‘name’.
The rest of the Controller handles the action once the input has been received – this is what the follow is checking for:-
if form.accepts(request):
The remaining code searches for the the search terms amongst other users registered in witter and plugs them into ‘people’, it also determines which of those people the user already follows – the View is going to rely on this follower information.
The Search View
So far so good, now let’s take a look at the View, you’ll need to create a file called default/search.html under the Views section. Replace the default code with:-
{{extend 'layout.html'}} <h2>Search for people to follow</h2> {{=form}} {{if people:}} <h3>Results</h3> {{for user in people:}}{{=A(name_of(user.auth_user), _href=URL('wall',args=user.auth_user.id))}}{{if user.followers.followee:}} Unfollow {{else:}} Follow {{pass}}</div> {{pass}} {{pass}}Much of this will now be familiar – we pull in the standard template, then the form and then iterate over the ‘people’ (if any) returned by the Controller. Where it get’s interesting is the button definitions.
Firstly we check if the searched for user is already being followed by the search, this means the button can offer to follow unfollowed witterers and unfollow the followed. So far so good, but what does this do?
<button onclick="ajax('{{=URL('follow',args=('follow',user.auth_user.id))}}',[],null);$(this).parent().html('Followed')">Follow</button>Before I can answer that I need to explain about AJAX. AJAX stands for Asynchronous JavaScript and XML, but this name is largely misleading since it needn’t be asynchronous and needn’t use XML. In short AJAX is a technique for creating dynamic web pages, it allows pages to be updated without needing to reload the entire page, and it does this by exchanging small amounts of information with the server behind the scenes.
Strictly speaking I could have passed on using AJAX in this tutorial, but it is a really useful technique a very simple to implement.
In layman’s terms the button definition says, when the button is clicked make a poke to another Controller action called ‘follow’ and send the arguments ‘follow’ and the user id. Once this is done replace the button (which read ‘Follow’) to be some text that read ‘Followed’.
A final note about the search View is the use of the css classes ‘row’ and ‘span’. These are provided by Bootstrap which is a a popular front end frame work. Bootstrap is not part of Web2py but Web2py does support it out of the box. In this tutorial I’ve deliberately avoided focusing on the look and feel of the app, but Bootstrap provides all the tools necessary to create an attractive web application.
AJAX Callback
And that’s it for the , however, what about the follow action in the Controller? We’ve not implemented that yet. Here goes, add the following to the default.py Controller:-
# this is the Ajax callback @auth.requires_login() def follow(): if request.env.request_method!='POST': raise HTTP(400) if request.args(0) =='follow' and not db.followers(follower=me,followee=request.args(1)): # insert a new friendship request db.followers.insert(follower=me,followee=request.args(1)) elif request.args(0)=='unfollow': # delete a previous friendship request db(db.followers.follower==me)(db.followers.followee==request.args(1)).delete()The most interesting line is the first one.
if request.env.request_method!='POST': raise HTTP(400)When a browser makes a request to read a web page it uses an HTTP method called GET, this is exactly what you do everytime you point your browser at Google. There are however other HTTP methods, POST being one of them, POST is used to transmit that is expected to change the state of the application. The AJAX call that we initiate in the search,html View is a POST request.
Since this Controller action is there solely to support AJAX calls from search.html, it does not expect to handle HTTP GET requests and rejects them. You can try this for yourself by trying to View http://127.0.0.1:8000/witter/default/follow which should result in a blank page and a error message complaining of a ‘bad request’.
Right so there we have it – all pages are complete, in order to try out the search and folllow/unfollow functionality you’ll need to register to extra users and have them follow each other. Be sure to notice that it is not necessary to refresh the search page every time to make a follow/unfollow request.
So in conclusion what have we achieved?
We created a new web2py application called Witter, created three pages (and an AJAX method) supporting a home page, a user wall and a user search and all backed by a database that will persist the data over time.
Are we done?
Well perhaps, I certainly am.
This tutorial has taken you from nothing at all to a functioning web2py application, that can be extended as you please.
If you are searching for ideas, you might want to move the search functionality into the home page and extend it so that search covers all weets (much like Twitter does). The UI could certainly do with a spruce up (and there are plenty of CSS tutorials out there) and as a final task you could put the thing live, gain awesome traction (due to your custom tweaks) and take over the social media world.
Feedback on this tutorial much appreciated, I’ll leave you with some useful links.
- web2py home page
- web2py online book – the most comprehensive web2py resource online
- web2py mailing list,
- web2py examples
- The Witter source on Github
- Learn Python the Hardway
- Bootstrap – Everything you need to get the site look great
- Selenium – Functional testing for your application
- Web Development Check List http://webdevchecklist.com/
Twitter Clone Tutorial in Web2py Part 2 – The Home Page
Welcome to my getting started with Web2py tutorial.
This tutorial assumes very little on the part of the reader, some knowledge of a programming language will certainly help, but if not don’t worry. I’ll take you from installation through to v1 of your application.
If you don’t want to copy from the tutorial, the full source is hosted on github.
Last time we set up Web2py and created our application, Witter. This time around we’ll down and dirty with writing our own functionality, but before we do that, let’s register ourselves since it will save us a job later.
Register a new user
From http://127.0.0.1:8000/witter Click ‘Login’ on the top right and then ‘Register’, enter your detail into the form and hit submit. Welcome! You are the first ever user of your application.
While this is extremely cool, it will be even cooler once Witter actually does something, and for that we need to work with the Admin interface.
The Admin Interface
The Admin interface can be found at from http://127.0.0.1:8000/admin/default/design/witter and provides access to all the files you will need to create your application, there is a lot to take in, and for now we are are going to focus on three sections that we will be editing extensively – The Models, the Views and Controllers.
Model-View-Controller MVC
Before we go any further I need to explain some theory. Model-View-Controller or MVC is highly popular web application design pattern. This means that over many years of sweat and toil it is generally considered to the be the best way to lay out your code. It is certainly not the only way, and there are many MVC variations, but Web2py is rather fond of the MVC pattern and this is what we’ll use to create Witter.
So what does working with MVC mean?
We let’s start by defining some terms, I’m going to steal directly from wikipedia
Model–view–controller (MVC) is a software architecture pattern which separates the representation of information from the user’s interaction with it.[1][2] The model consists of application data, business rules, logic, and functions. A view can be any output representation of data, such as a chart or a diagram. Multiple views of the same data are possible, such as a bar chart for management and a tabular view for accountants. The controller mediates input, converting it to commands for the model or view.[3] The central ideas behind MVC are code reusability and separation of concerns.[4]
It goes onto to define the role of each component
In addition to dividing the application into three kinds of components, the MVC design defines the interactions between them.[5]
A controller can send commands to its associated view to change the view’s presentation of the model (e.g., by scrolling through a document). It can also send commands to the model to update the model’s state (e.g., editing a document).
A model notifies its associated views and controllers when there has been a change in its state. This notification allows the views to produce updated output, and the controllers to change the available set of commands. A passive implementation of MVC omits these notifications, because the application does not require them or the software platform does not support them.[6]
A view requests from the model the information that it needs to generate an output representation to the user.”
In summary, we define how our data will be laid out in the Models, define how it will be presented in the Views and define how the user can interact and modify it in the Controller.
Right now, you might be wondering why this is all so important. For the moment I’m going to ask you to trust me, and work safe in the knowledge doing so will save you time, effort and save the lives of puppies.
Getting going – the Models
Okay, so we have the application up and running, we are now armed with the necessary theory, it’s time to dive in. This is where is really starts to get interesting.
We’ll start with the Models, we can actually reuse the existing ‘db’ Model file, so click edit and we’ll take a look around. You’ll notice that there is a lot of information here, along with housing our data Model the db file also provides some initialisation and sensible defaults for our application.
By all means take a look through but I want to call two lines of special interest:-
db = DAL('sqlite://storage.sqlite',pool_size=1,check_reserved=['all'])DAL stands for Database Abstraction layer, and provides an API that maps Python objects into database objects. We will make extensive use of the DAL in our application. In this case we are using an SQLite database to back the DAL. Using SQLite will make absolutely no difference to how we write our application since we talk to the DAL not the database. This means that we can swap in and out databases as we please. To start with SQLite is the perfect choice to get going quickly, though we would want something meatier for a production environment.
auth = Auth(db)Auth is a class that implements, the Web2py role based authorisation API, this will allow us to provide for user registration, login as well as restricting access to certain pages. For instance, once I have registered, it will provide me with a form to let me change my password, and at the same time ensure that I am the only person who can view it.
At the beginning of this tutorial I referenced the Web2py stated goal of Security. Auth and the DAL abstract many of these concerns on behalf of the developer. For instance the DAL makes it impossible to succumb to an SQL injection attack.
In addition to the concept of a user, we will need two additional entities – (t)weets and followers.
Add the following to the bottom of the db.py Model file
# a table to store posted weets db.define_table('weets', Field('body','text',requires=IS_LENGTH(140,1),label="What's going down?"), Field('posted_on','datetime',readable=False,writable=False), Field('posted_by','reference auth_user',readable=False,writable=False)) #a table to store follower relationships db.define_table('followers', Field('follower','reference auth_user'), Field('followee','reference auth_user')) #Convenience methods to make code more compact me = auth.user_id def name_of(user): return '%(first_name)s %(last_name)s' % userSo for a weet we store the body that must not exceed 140 characters, when it was posted and by whom.
Separately, in followers, we store which users follow which other users, each relationship has it’s own entry in the same. ‘auth_user’ is reference to the auth_user table defined by Auth and by explicitly calling out the relationship we ensure that it is not possible to add bogus data into the followers table.
We’ll side step ‘me’ and ‘name_of’ for now and revisit them as they come up later.
Save the default.py and click on ‘edit’ that sits on the top nav bar, this will return you to the Witter admin page from here we need to edit the menu.py Model file. This file configures the look of the menu and also houses meta data about the application.
Remove the existing content and enter the following in menu.py
response.title = "Witter" response.subtitle = "Super Awesome Twitter Clone in Web2py" response.menu = [ (T('Home'), False, URL('default','home')), (T('Wall'), False, URL('default','wall')), (T('Search'), False, URL('default','search')), ]This code sets the apps name and sub-title as well as defining the links on the navigation bar.
With the data Model out of the way, it is time to look at Controller file. Once again, save the menu.py and click on ‘edit’ that sits on the top nav bar, under Controllers click edit on ‘default.py’.
default.py also comes with some pre-existing content, you’ll notice a user method – this ties in with the Auth class we came across in the Model exposing functionality to manage user registrations and logins.
So far everything we have seen, has focused on definitions. In the Controllers we will start to use python in anger to determine how our application should behave. I will not attempt to provide an introduction to python in this tutorial but will recommend the Web2py python introduction as well as Zed Shaw’s Learn Python the Hard Way(‘The hard way is easier’).
The Home Page Controller
Our first custom Controller method will be the home page, this is the page from which we can post a weet as well as listing weets from other users that we follow – it also contains our own weets.
Every method in the Controller is exposed by the application, so let’s have a play. Add a new method called ‘home’ like so, adding to the bottom of the file is fine.
def home(): return "Hello from Witter App"Now point your browser to http://127.0.0.1:8000/witter/default/home
You should see a page empty but for your message. Take a look at the url for a moment – witter is the application, default is the Controller file and home is the specific method. This means that we can write multiple Controller methods and reach them via the same URL scheme changing the final element to match the new method name.
Getting the home method working is good going, but if Witter is going to challenge Twitter on the big stage we are going to need to make some changes.
Replace your previous home method with the following, this is the Controller action for the home page.
@auth.requires_login() def home(): '''First point of call, contains all weets and all weets of those you follow''' #configure defaults, so they not appear on the form db.weets.posted_by.default = me db.weets.posted_on.default = request.now #create form with which the user can submit weets crud.settings.formstyle = 'table2cols' form = crud.create(db.weets) #determine who the user follows my_followees = db(db.followers.follower==me) me_and_my_followees = [me]+[row.followee for row in my_followees.select(db.followers.followee)] #Pull all weets to be displayed weets = db(db.weets.posted_by.belongs(me_and_my_followees)).select(orderby=~db.weets.posted_on,limitby=(0,100)) return locals()Woooh! Hold on now, there is a lot going on here. Let’s go through this slowly.
This method uses both ‘db’ and ‘me’ that we defined earlier in the db.py Model. Any variable defined in a Model file is automatically available in all Controllers (and Views). This why we can use these variables without needing to formally import them.
So every time we see ‘db’ we know that some activity against the DAL and therefore the database is going to occur. Similarly every time we see ‘me’ we know it refers to the user who is logged in.
So, back to the home method. The very first line
@auth.requires_login()Is a method decorator that ensures that this page is only accessible to logged in users. Users not logged in, will be redirected to the login page.
Next we assign some default values to fields in the weet entity before using the crud plugin (also defined in db.py) to auto-generate a form for us. This is the form that we will use to post weets. Crud stands for Create, Read, Update, Delete I don’t want to dwell on it too much for now, other than to say it is a useful tool to create forms and validation logic.
Next we need to pull out the weets that those that we follow have weeted, as well as pulling out our own. The final lines act on the DAL to select out the relevant details to pull out only the weets we are interested in.
Finally we return ‘locals()’ this makes the method’s local variables available to the View, which we will go into in just a second. We have one final task before leaving the Controller and that is to replace the index method with:-
def index(): if auth.user: redirect(URL('home')) return locals()The index is the default Controller and is where you end up after naviagting to http://127.0.0.1:8000/witter This method simply checks if you are logged in and if so redirects to the ‘home’ page. If not you are presented with the default landing page that you saw when you first started up Web2py.
Now to learn more about Views
The Home Page View
Remember the View is there to present the information stored in the Model, after processing via the Controller. Separately, as we shall see, it also provides the user a means to interact with the application via the Controller.
In the first attempt at the home method ‘’Hello from Witter App” we made use of the default View. The default is useful for checking that everything is working but for a high quality application such as Witter we will need something more sophisticated.
From the application adminstration page scroll down until you see the Views section and create a new file called default/home.html The path of the file denotes that it is the View of the default/home Controller.
Replace the default code with the following:-
{{extend 'layout.html'}} {{=form}} $('textarea').css('width','600px').css('height','50px'); {{for weet in weets:}}{{pass}}{{=name_of(weet.posted_by)}} on {{=weet.posted_on}}:
{{=MARKMIN(weet.body)}}I’ll explain what the View is doing in second but for now, just save the file and point your browser at http:127.0.0.1:8000/witter/default/home If you are no longer logged in you will be prompted to provide your username and password.
This is your landing page – what a difference! Along the top left we have the Witter navigation controls, which we specified in the menu.db Model and immediately underneath a text area in which to enter weets.
Initially, there isn’t very much to see. The next step is to go ahead and make a weet (you can see weets from multiple users in the picture above). Enter some timeless phrase into the text area and hit submit. The page will refresh and low and behold your weet is preserved for eternity.
So how on earth has this happened? Let’s go back to the default/home.html View.
The View is standard html file and as you might expect contains html tags to mark up the content, but it also contains some lines enclosed by ‘{{ }}’. The contents of these lines are Python and allow you to dynamically create the page content.
The first line draws in the layout.html file, this is base template that provides things like a nav bar and a footer and generally makes our page look a bit more like a website. You can take a closer look from the application admin interface under Views.
Next up, we enter the form as created in the ‘home’ Controller, before modifying the size of the text area in the <script> tags.
Here’s where it starts to get interesting. In the Controller we specified a variable called weets that contained details of all the weets to display on the page.
The View loops through all the weets
{{for weet in weets:}}For each one it displays how weeted, when, and then the body of the weet. The reason this is so interesting is that the content has been created dynamically and is entirely dependent on the weets pulled from the Controller.
So we have out first dynamically generated page on Witter. All that remains is to implement the remaining functionality such as the Wall and the Search page which we’ll pick this up in the next post.
Twitter Clone Tutorial in Web2py Part 1 – Getting started
Welcome to my getting started with Web2py tutorial.
This tutorial assumes very little on the part of the reader, some knowledge of a programming language will certainly help, but if not don’t worry. I’ll take you from installation through to v1 of your application.
If you don’t want to copy from the tutorial, the full source is hosted on github.
Why Web2py?
Web2py is a fantastic web development framework for Python, it focuses on
- Ease of use
- Rapid development
- Security
Additionally it had a excellent documentation and a highly responsive mailing list, these factors combine to make it a great place to start for those new to web development and programming in general.
To give an idea of just how easy it is to get going this tutorial we will build a twitter clone from scratch – nothing too flashy, but enough to demonstrate some core ideas to get you going.
The Twitter Clone – Witter
We’ll call the app Witter and steal other Twitterisms such as weets and weeting.
The app will be made up of three pages
- A home page, that displays all the weets of the user as well as those of anyone they follow
- A wall page, that displays profile details of a given user as well as their weets
- A search page that can be used to find others users and follow and unfollow
Getting Web2Py
There are a number of ways to do this, the easiest is to download the binary packages available for OS X and Windows. The binaries includes everything you need including a Python interpreter and an integrated development environment. Linux users will need to download the source, if you are comfortable with Linux I’m going to assume that you are comfortable with installing web2py.
Once downloaded you have everything you need and it is time to start web2py for the first time.
On OS X you’ll want to copy your newly downloaded file to your Applications folder, then double click just as you would any normal application to launch.
On Windows, copy web2py.exe to Program Files and double click to launch:
When prompted enter an admin password, and click ‘Start Server’ and soon after you will be presented with the web2py welcome app.
This is great place to start, including some useful examples and documentation, for now just click on the ‘Administrative Interface’ button on the right hand side to reach the site view of the administrative interface.
Creating your new application
The first thing to do is to create the new application, on the right hand side under ‘New Simple Application’ enter ‘witter’, this will be the name of our Twitter clone. With a bit of luck you are now looking at the Witter administrative interface – we are going to spend some time taking a tour of this page, but before we do that let’s head to the Witter home page. In a separate tab point your browser to
Congratulations – this is your brand new application, you’ll notice that it looks very similar to the welcome application, it is just using the same default content. We soon get rid of that in the next post as we start in earnest on Witter.
What ‘How your company treats exiting staff’ says about you
Nothing impacts your working life like company culture and yet culture is very difficult to assess. This problem keeps me up at night and I’ve written about it before in ‘Why work at your company?’
The trouble is that in many cases, the company itself does not really know that much about its own culture and even if it did, expressing it in a sincere manner is challenging, in fact most companies don’t even try at all.But how about this as a question to quickly determine a how a company feels about its staff?
“HR hoops aside, what happened the last time someone left your company?”
Seems pretty innocent, no? Every company can answer that question in a positive manner, but I think the variations speak volumes.
For instance, recently we said goodbye to junior (ish) developer, he’d been with the company 18 months and was leaving to pursue a childhood dream to work as an air traffic controller (actually true).
On his last day there was a leaving ceremony where a few words were said in the office and a leaving gift presented, immediately afterwards there was a trip to the pub for those wishing to see him off.
Nothing unusual so far.
But it was the whole office of eighty people that turned out – the parting gifts, while inexpensive, were completely personalised – in this case it was a ‘make your own picture book’ with each picture and audio presenting some sort of in joke – jokes understood by the whole group. In similar situations, gifts have included a ‘time of day’ vs ‘date’ commit plot for a notoriously nocturnal team member, a Wordle of IRC logs for an especially chatty colleague and even a framed 3ware card (his nemesis) for a long suffering sys admin.
The pub trip was not just his team or engineering, but had attendees from across the entire company, and at all levels of seniority. Numbers were high, especially given it was a Friday night.
It was a sad occasion, but in many ways felt like a celebration. ‘Great working with you, can’t wait to see what you do next’ – it’s one thing for your immediate work mates to say this, but how about a whole company?
What struck me was how normal this felt, this is completely standard practice for us. Why wouldn’t we act in this way? On reflection I think that this would be considered unusual at most organisations. Such sends off are not unheard of but usually reserved for especially treasured members of the team. This difference say something about our culture.
By comparison, at my friend’s organisation, a senior (much loved) member of staff of 20 years service cannot even expect their manager to drop into their leaving ceremony. Their reluctance to attend driven by fear of tacit endorsement. It’s the same set up, leaving ceremony followed by pub, but a completely different feel.
How a company treats its exiting employees, speaks volumes to remaining staff. The actions of individuals in response to the leaver, reflect the company’s culture. Since the leaver no longer has any direct value to the company, these actions speak honestly about how the company values people.
So ask yourself, how does your company treat exiting employees and what does it say about the culture? What message are you sending to remaining staff? It is not for management to mandate a leaving procedure, but it is for management to create an environment where people matter.
How to answer ‘What is your greatest weakness?’
So, Mr Johnson, what would you say is your greatest weakness?
Worst. Interview. Question. Ever.
In isolation, it’s an interesting question to ask yourself, it requires a great deal of honesty and openness on the part of the individual and it requires trust that there will not be repercussions for the answer.
Sadly, an interview is a place for none of those things. Candidates need, and are expected to, go out of their way to impress their interviewers and actively admitting weakness is a high risk strategy.
And yet it’s popularity remains, company’s still ask it and candidates still find a thousand and one tortured methods to say “I’m a workaholic”. In a novel attempt to get around this, one company used to ask for your three greatest weaknesses. I’d love to know what they gained from this.
So how should this question be answered? From personal experience, responding ‘My left elbow’ sadly does not work.
In comes down to framing, strengths and weaknesses are pretty much alternate views on the same characteristic. Above a certain level of competence it is rare to find people truely good at certain pairings.
For instance, think those people who you admire for their vision. These people are inspiring, charismatic they lift you up and show you a world that you dimly knew existed but couldn’t quite realise. Wonderful people, but tell me, how are they on detail? How good are they are dotting the Is and crossing the Ts and meticulously going through the minutiae of a project, ensuring that everything is as it should be. Not so much huh?
Clearly there will exceptions but Richard Branson, just isn’t a details kind of guy and nor should he be. Conversely I want an Accountant to be exactly the opposite, they need to get down to the details.
Since the question is now framed in terms of strengths it is much easier to answer. Just figure out what strength of yours you wish to highlight, determine how that makes you weak and then go for it.
Not convinced? Here is an example.
Imagine for instance the Great Remallo, Lion Tamer extraordinaire, sitting for an interview. His CV/Resume contains plenty of past experience dealing with many different types of lion and as the inventor of the lion proof cape he clearly knows his stuff. As the final question of the interview the Circus owner, Mr Top, fires out the big kahuna:-
Mr Top: Mr Remallo I have one final question for you. Tell me, what is your great weakness?
The Great Remallo: Well, Mr Top, if I had one weakness it would be that I seem to have trouble accurately assessing the level of danger I might be in at any given time, even as a small child when I used to play in traffic. Actually it’s something that really helps me as a lion tamer, I should think that if I ever truley understod the peril I put myself in everyday I would be petrified and never even enter the ring.Still not convinced? Let’s try the same question for a Software Developer.
My biggest weakness is that I can’t stand not knowing how things work, it used to drive my family crazy as took everything I owned (and somethings I didn’t) apart in order to see what was going on under the hood. To this day I really struggle to take things at face value if I can’t look and see what is going on. I suppose it’s one of the reasons I became an engineer in the first place, this drive to understand how things works stands me in good stead when wrestling with a gnarly code base or diving deep into library code, bug hunting.
I’m sure you can come up with something better yourself. Just remember if you reframe the question as an opportunity to talk about strengths, it’s then just a question of determining the flip side to that strength and using it as an in.
Anyone else got a good answer to this question?
The Complex, the Complicated and what it means for NASA
When people say ‘Simplifying Complexity’ I hear ‘I don’t know what these words mean’. This isn’t entirely fair, as we shall see, but it gives you an idea of my preconceptions before attending a training session of that title.
The facilitator started off by inviting each member of the group to talk about the influence of complexity in their professional lives. As we went around the room it became clear that for most of the group complexity was a synonym for hard or complicated. Many would agree, including the Oxford English dictionary. However, here was a group dominated by senior members of a very large IT professional services company. These are people for whom complexity science is highly relevant to their professional lives and people for whom there ought to be value in defining Complexity with a big C and in particular differentiating the Complex from the Complicated.
Cynefin
The Cynefin Framework characterises systems (and problem spaces) into five classes – Simple, Complicated, Complex, Chaotic and Disordered. Once the class of a system is identified the framework provides guidance on how to work most effectively with the system. On a personal level I find it very useful in explaining to me not only why an incremental and iterative approach generally works well in software development, it also suggests to me under what circumstances such as approach does not hold. You won’t see NASA using Scrum for instance, more on that later.
Cynefin can be expressed visually like so:-
Credit Wikipedia
The key distinction I see is that of Complex and the Complicated.
- Complicated
An example of a complicated task is building a submarine. It’s definitely not trivial, but if the tasks are broken down sufficiently the problem is tractable and predictable – essentially it becomes a series of Simple tasks. By contrast a Complex task retains its complexity even after being broken down.
- Complex
An example of a Complex task could be to ask a room of people to arrange themselves such that the closest person to them is exactly half the distance from them as that of the 2nd closest. It would be extremely difficult for an individual to orchestrate this task, instead each individual actor must make a small change, observe the consequence and then make a further change based on the feedback.
What does this mean for Software?
Taking a manufacturing production line as an example, once it reaches steady state the system can be described as Complicated and is predictable. This is important because for many years Software Development looked to the world of manufacturing for guidance. In doing so, implicitly defining software development as a Complicated task. The thinking being that with sufficient up front analysis the problem could be solved without a line of code being being written. It is for this reason that the Waterfall model rose to such prominence and was so readily adopted.
More recently manufacturing has been shown to be an inadequate metaphor and that in fact software development is more akin to product design, thereby inhabiting the Complex quadrant. This means that the correct approach, according to Cynefin, is to probe, sense and respond. In effect the iterative and incremental approach practiced by those inspired by Agile and Lean thinking.
So what does this mean for NASA?
If what I say is correct, what does this mean for NASA? After all they have some of the smartest brains on the planet available to think about this sort of thing and yet their processes appear to assume a Complicated rather than a Complex environment.
NASA is an extreme organisation and it is only natural that what works for them will deviate from the common case. Despite the challenging nature of their work I would argue that their domain is Complicated rather than Complex.
Complex systems are characterised by there being many unknowns and an inability to determine the nature of those unknowns at the beginning of the process. In NASA’s case they are genuinely in a position where, for software at least, the problem space is well defined.
For instance, the software runs upon hardware based on Intel’s 386 architecture, hardly cutting edge, but whose behaviour (warts and all) is well understood and has not changed in years. This means that the inputs to the system are well understood and the behaviour deterministic. NASA has managed to turn what would ordinarily be a Complex system (that of software development) into a Complicated system and in doing so their software teams work to vanishingly small defect rates, albeit at enormous cost and at the expense of delivery time. I found this article to be a fascinating insight into their working practices.
In conclusion, Complexity science provides a means to characterise systems, the Cynefin framework provides definitions to differentiate the Complex from the Complicated. Software development is almost always Complex though it was originally assumed to be Complicated. This is why agile and lean approaches have been shown to much more effective than traditional methods that assume a Complicated system such as Waterfall.
Hacker Jobs Interview
I was recently interviewed by London based job board Hacker Jobs. The interview covers a range of subjects but focuses on software development and technical recruitment. There’s nothing too crazy in there but I did manage to get in a quote from Tim Berners-Lee.
Identity and Narrative – Managing Change
People hate change, and the reason they hate change is that they really hate change, and that change is hated because they really hate change…….
I’d love to know who said this
All teams are subjected to continuous environmental change, but it tends to be gradual and hard to perceive at a week by week level. I want to talk about the sharp, often unexpected step changes and go into some strategies to guide a team through the worst.
Before diving in, I want to introduce a model for characterising teams. There are two attributes that I consider critical in determining a team’s ability to function.
- Identity – Who the team perceive themselves to be, what they value.
- Narrative – Why the team exists, what value they bring.
I’m unaware of anyone else talking specifically in these terms but similar thinking appears in Daniel Pink’s ideas of Autonomy, Mastery (both mapping to Identity) and Purpose (narrative) as well as echoes in the higher levels of Maslow’s hierarchy of needs.
Ordinarily, definition of identity and narrative is straight forward. The team will arrive at their own identity over time, while the narrative, for the most part, comes from the commercial arm of the company. In times of change there are no such guarantees. I’ll look at each in turn.
Identity
As an individual, our identity is in part context specific and a function of those around us. The same is true for teams. This means that when the environment changes quickly, it can be difficult for a team to define itself. Definition means identifying the skills and attributes that set it apart and most importantly what it values when compared to those around it.
A manager can help speed this process. They have a birds eye view, they know how their team have defined themselves in the past and have more opportunities to interact with the broader business. The manager ought to be able to spot and highlight specific points that will go and form part of the team’s new, long term identity.
Additionally during upheaval it is for the manager to contextualise the actions and focus of other teams/departments. It’s all too easy to enter into a spiral where ‘everyone apart from us is an idiot’. A team needs to understand how they are different, but they also need to collaborate and work effectively with those around them.
Narrative
Narrative is interesting in that it should be easy to identify. The business is willing to invest in the team for some purpose and that purpose ought to be the team’s narrative.
During times of upheaval this is not a given, and it could take months for a clear narrative to emerge, as the dust settles and the business redetermines the best way for the team to add value.
But waiting months for the new vision is not an option. Put bluntly, if the business cannot provide a compelling narrative quickly then the team manager must arrive at one. Once again it is time to make use of the manager’s elevated view of the organisation to sift through the confusion and draw out something tangible that resonates.
Conclusion
All teams need a sense of identity and a sense of narrative in order to be productive. During times of significant change both of these characteristics come into question. It is up to the team’s manager to act as the catalyst, as the team aims to arrive at new definitions.
Sew Make Do – A Lean Startup Experiment – Part 2, Metrics
Mrs Fragile recently bought a hand made lamp shade online and was disappointed with the results, as a keen crafter she wondered if she could do better, and perhaps even sell some of her own creations.
In doing so I thought it would interesting to incorporate ideas from the Lean Startup Movement as popularised by Eric Ries and document progress through Fragile. The project is named Sew Make Do.
Metrics
A key idea in lean startups is that metrics ought to be actionable. On his blog Ash Maurya defines explains Actionable Metrics
An actionable metric is one that ties specific and repeatable actions to observed results.
The opposite of actionable metrics are vanity metrics (like web hits or number of downloads) which only serve to document the current state of the product but offer no insight into how we got here or what to do next.
Tracking sales is of course an obvious thing to do but it is a very coarse measure. A more interesting metric is to look at how easy it is to convert a potential customer into a real customer. Over time we not only expect sales to increase but also expect to get better at selling such that our conversion rates also increase.
In an ideal world I would like to perform Cohort Analysis. This means tracking individual user behaviour and using it determine key actionable metrics. While more commonly applied in medical research in order to study the long term affects of drugs, common examples in the context of Lean Startups might be tracking user sign up and subsequent engagement over time. If it can be shown that 2 months after sign up users generally cease to engage in a service, it provides a pointer to what to work on next, as well as a clean means to determine if progress is being made.
The in-house analytics provided by Etsy do not provide the means to track the habits of specific users, but they do allow for aggregations of periods of time. This means that some level of analysis is still possible, though cannot be describes as true cohort analysis.
I’ve modelled my funnel like so:-
Of those that viewed the shop
- What percentage favourited the shop or a product. There is no reason to assume that someone buying the product will also favourite it, though at this point it is reasonable to assume some level of correlation.
- What percentage bought a product for the first time
- What percentage are returning paying customers buying a subsequent item.
As you can see from the graph, there is not a lot of data. Throughout the process our absolute views and favourites have increased, though it is interesting to see that our favourited percentage has improved. We put this down to improving the pictures and copy, though without more data it’s hard to make any firm statements.
What I’ve not done is break this down on a per product basis, right now we do not have enough products or traffic to justify it but we’re certainly noticing that some products are more popular.
In a few months times I’ll revisit this post and let you know how things are going. With a bit of luck there’ll be some yellow and green on there.
Sew Make Do – A Lean Startup Experiment
I’ve been an advocate of applying lean thinking to software for some time, and learnt a lot form Eric Ries’s blog. I’ve just finished Ries’s book ‘The Lean Startup’ and naturally am looking for opportunities to apply its ideas in my own work place. However doing so will take time and more immediately I wondered what would happen if I started on something smaller.
Mrs Fragile recently bought a hand made lamp shade online and was disappointed with the results, as a keen crafter she wondered if she could do better, and perhaps even sell some of her own creations. While initially suspicious of my gallant offers to help her run things on lean startup lines so far she’s tolerating my efforts.
I thought it would interesting to document progress through fragile and perhaps receive some feedback/advice along the way. The nice thing is that since this is not a serious venture it should be possible to be more open then would other wise be possible. The project is named Sew Make Do.
Assumptions
We started with the following assumptions to test.
- People would like to buy Mrs Fragile’s lamp shades
- The people that would like to buy the lamp shades are female and in their late 20’s to early 40’s.
- 30cm and 20cm drums will be most popular.
- People will pay ~£28 for a 30cm shade
- People will pay ~£22 for a 20cm shade
- People will suggest custom fabrics to drive product development.
Of these assumptions by far the most risky is No 1. We have no idea if anyone will actually want to buy them. Therefore it makes sense to prioritise testing this assumption. To this end Mrs Fragile set up a shop on Etsy and presented a choice of 3 lamp shades offering a range of styles and sizes. This is our MVP for assumption 1. There is no reason to assume that long term Etsy will be the main distribution channel but it does provide a very quick way to put the product in front of potential customers.
Once, assumption 1 has been tested sufficiently to give us hope to persevere it will be easier to address the remaining assumptions, since all are dependent on sales.
Thoughts on metrics
The lamps shades have been up for a few days now, so far there have no sales but a good number of people have ‘admired’ them. It will be interesting to see if there is a link between the number of views, the number of admires and the number of sales. Longer term it would be interesting to perform cohort analysis on these indicators.
For now though we’re just hoping for the first sale – or possibly our cue to try something else…..