Things Every CS Student Needs To Know

I’ve interviewed and hired new computer grads. I’ve help a few prepare for interviews as they approach the end of school. You’d think after 4 years of learning, they’d know all the basics skills they need to do the job of a software engineer.

But it isn’t so.

So as a small service to humanity, here’s my list.

Source Control

If I was a professor my students would turn in all of their assignments via Git. Because in the real world, that’s how they turn in all of their work.

It boggles my mind that CS students haven’t had to use and become proficient in some form of source control. It isn’t like the concept is new, I was working on Mircosoft’s SourceSafe for the Mac in the 1990s. The dominate software in that area, like all areas of development, changes every half decade, the concept is always there.

Also they should have encountered git on their own as they work on open source projects, but that lack is for another point.

Agile/Scrum

I say Agile/Scrum, but I mean the Scrum framework. Agile is a philosophy and students should be exposed to it. In 80% of cases, the first day they start a programmer job they are going to be on a Scrum Team. Could be another kind of Agile framework, like Kaban, but most likely it will be Scrum. If you are hired by a company that doesn’t do some agile methodology it’s a red flag.

Scrum is also a great system to use in those group projects people dread so much. It’s transparency and daily accountability can help keep everyone working.

Tactical Programming

Tactical Programming is how you write a line of code, name a variable, or structure a function. I’ve written an article about it and this blog has a whole category (Tactical) dedicated to it. But most schools don’t seem to talk about it at all.

Initiative

When I went to the interview for my first job, I went with source code to a program I had written on the side while in school.

When I interviewed programmers for my video game company, I asked them to show me something they had created. Only one of the candidates could do that. He got the job.

People want to hire people who love to code. Who want to do it so much they will do it on their own time.

They want to hire people who they know can do the job because they have already done it.

Many companies also ask for your Github account ID so they can see if and what you’ve contributed to open source projects.

Truth be told there are a lot of programmers who lack these skills that have been doing it for awhile. Those folks need to up their game, but I kind of feel it is the schools letting down the new grads.

Flask/WTForms Create and Customize Form From Model

I’ve been spending a lot of time working on a project using Flask. I banged my head against incomplete examples and docs for how to create a Form directly from a Model. Since I wasn’t able to find a complete example, I thought I’d write one up now that I’ve figured it out.

Problem: You have a large model and want to make a form to create or edit the model, but don’t want to have to create every form field in WTFform.

Context: I’m using this under Flask, using the WTForm extension. I’m also using Flask-Bootstrap for layout and want to be able to use its helper method to render the entire form.

In my app I need to create a new user/member for a club. You don’t need to know the specifics, just know there is a User object that includes not only all the standard authentication info, but also member kinds of information like address (A whole other blog post in itself), phone, date joined, rank, etc. Also every user can be part of multiple Clubs and has one Role defined via foreign key to a Role model.
Multiple Forms Page
I also have two ways to add users to a club. You can create the user manually via form, or you can upload a csv file and I’ll create the users from there and add it to the club. I decided to put the forms for both of these methods on the same page and allow the user to pick which one they wanted to use. But I wanted individual Routes/View methods to handle each form, which means there is one view method that creates both forms, but each form’s POST call goes to a different route.

I’m writing this post after implementing the manual entry form.

Solution:

A quick Google search will bring you to this snippet (Automatically create a WTForms Form from model) on the Flask site. Without it I wouldn’t even have know where to start, but it left a number of things to be desired.

As with most things in Flask, the first thing you need to do is create the view method in your views.py.

@main.route('/member/update/', methods=['GET', 'POST'])
@permission_required(Permission.MANAGE_CLUB)
def add_member_from_form():
    member_edit_form = AddMemberForm()
    if member_edit_form.validate_on_submit():
        new_user = User()
        member_edit_form.populate_obj(new_user)
    db.session.add(new_user)
    db.session.commit()
    return render_template('club_add_members.html',
        club=None,
        member_edit_form=member_edit_form)

First I created the route to the object. Since we’re going to be processing a form I added the POST method, though ultimately I’ll be removing it. Then I added the decorator to make sure only users with the proper permissions can do the add at all.

In the method I need to create the form. If you looked at the example post above, the form class is created right here, but in my app all the forms classes are created in a forms.py. So what you see here is normal usage of a form in a view method.

It is how we created this form that is what this post is all about, so let’s go over to forms.py and see what we had to do to make AddMemberForm().

First the imports, because too many tutorials leave that part out.

from flask.ext.wtf import Form
from wtforms.validators import DataRequired, Length
from wtforms.ext.sqlalchemy.orm import model_form
from ..models.user import User
from .. import db

You need to import the Form base class from the WTForm for later use, and you need to import that validators you want to use in your new form. You also need to import model_form from whatever ORM you are using, in my case that’s SQLAlchemy. model_form is where the magic happens.

Of course if you are going to create a Form from a Model you kind of need the model, in my case User.

You are also going to need your apps database session, called db in my case, if you need any foreign key based fields, which I did.

Note your import “paths” for these last two will vary depending on the location of forms.py and your model modules.

Now to create a form all you need to do is this:

AddMemberForm = model_form(model=User,
        base_class=Form,
        db_session=db.session)

That will create the AddMemberForm class and you can import it into your views.py with this line, just like any other form.

from .forms import NewClubNumberForm, AddMemberForm

Now to add it to my template so it shows up.

{% import "bootstrap/wtf.html" as wtf %}
... import the WTForm support from flask-Bootstrap ...
{{ wtf.quick_form(form=member_edit_form,
action=url_for('.add_member_from_form')) }}

One thing to note about this snippet. I didn’t want the form to just post back to the same view method. I wanted it to got to a specific other method on submit. I accomplished that by setting the action= value to point to the route I wanted the form to go to. This parameter is mentioned in the quick_form docs in the parameter list, but not in the documentation just below it.

If you were following along right now, you’d have run into a problem with your form. It wouldn’t have a submit button. Yep, model_form doesn’t add a submit button, but you can fix that by adding this line of code after your create the form.

AddMemberForm.submit = SubmitField('Create')

Which also shows you that you could add fields to your model form to do anything you wanted. They just wouldn’t be interpreted by the model.

Just following the Flask snippet example I was able to create a form on the page, but it had fields like password_hash, date_added etc. Fields I didn’t want the user to edit, so I had to hide those.

You can modify what fields model_form generates using the exclude_properties= parameter. Just create a simple list with the names of the fields you don’t want to see.

I submitted my form at this point and SQLAlchemy threw an exception because some of my required database fields hadn’t been set when I clicked submit. I guess it would me nice if model_form was smart enough to know when something was required and add a validator to enforce it, but it’s not.

You can add arguments to any field of the model with a dictionary via the field_args= parameter. Below is the complete code for creating the form with validators.

exclude_properties = ['password_hash', 'confirmed', 'date_added', 'full_address']
field_args = {
    'role': {'get_label': 'name'},
    'email': {'validators': [DataRequired()]},
    'username': {'validators': [DataRequired()]}
}
AddMemberForm = model_form(model=User,
        base_class=Form,
        db_session=db.session,
        exclude=exclude_properties,
        field_args=field_args)
AddMemberForm.submit = SubmitField('Create')

The role field_are value is also something interesting it took me a long time to figure out so I should mention it. When I first displayed the field for my one to many relationship between User and Role the form had a popup menu with the values ”, ”, ”. What that meant was WTForms or Bootstrap-WTF was using the __repr__ value for the name. This was not right. Digging into the code it is calling a method called get_label to return what it should use for the label. Well get_label looked a number of places for the label and finally use asks the object for its representation. Turns out you can set what get_label uses. That’s what we do here to get it to use the name field of Role.

That’s where I am right now and just wanted to write it up while still fresh on my mind. I expect there will be more to come. For one thing I need to let them create a password, which will involve adding a PasswordField to the form and then handling it by hashing the password and putting it in the password_hash.

Connecting to The Cloud Free WiFi Service in the UK

Problem: Unable to connect to The Cloud free wifi for the first time. Browsers spin till they time our and give you an error about DNS.

Context: The Cloud is a free wifi service in the UK at various coffee shops including Cafe Nero.

According to the instructions it is as easy as 1, 2, 3 to connect and signup. Even the brochure’s Mac trouble shooting basically says, “Just connect”. But for me it never was able to connect.

Looking in the console there were errors like this: “5/27/14 1:34:47.149 PM sandboxd[463]: ([598]) ntpd(598) deny file-read-data /private/var/run/resolv.conf”

This does provide a clue, because resolve.conf is basically the file that holds a list of name servers to use for DNS.

Solution: Clear out any custom set DNS name servers in your Advanced network settings.

I had configure my DNS settings to use Google’s DNS, namely 8.8.8.8 8.8.4.4. If you clear this out then The Cloud can set the name servers to what it wants them to be.

Tips For Lowering Indention Levels

Linus Torvalds, the creator of linux, sets his tabs/indentations to 8 spaces. Personally that seems a little wide, but he says some interesting things about why shorter isn’t necessarily better. Me, I’ll stay with 4 because it just looks right. But you still shouldn’t have too many indent levels.

“If you need more than 3 levels of indentation, you’re screwed anyway, and should fix your program.” – Linus Torvalds, Linux Kernel Coding Style

Use Continue

Example:

for item in sequence:
     if is_valid(item):
          if not is_inconsequential(item):
               item.do_something()

Becomes:

for item in sequence:
     if not is_valid(item):
          continue
     if is_inconsequential(item):
          continue
     item.do_something()

Notice you have to flip the values of your if statements making this change. This only works inside a loop and if your language has continue.

Factor Out A New Method

This is true for a lot of things. As I recently heard if a method starts to get over 10-15 lines it starts to feel like maybe I’m doing something wrong.

If your indents are starting to get deep, maybe some of those sub-levels should just be put in their own routine.

On a python related note, Mr Rhodes points out if you need a new routine and you are in a class, your natural thought is to make a new method on the object. But if you aren’t using self – referring to the object in your new method – you can just make a function. These become easier to test and easier to move.

Factor Out An Iterator

Mr Rhodes says iterators are a Python superpower. I don’t understand python iterators yet and didn’t even understand his example, in the interest of completeness, here’s his example.

Example:

for item in sequence:
     for widget in item:
          for pixel in bitmap:
               pixel.align()
               pixel.darken()
               pixel.draw()

becomes:

def widget_pixels(sequence):
     for item in sequence:
          for widget in item:
               for bitmap in widget:
                    for pixel in bitmap:
                         yield pixel
 
for pixel in widget_pixels(sequence):
     pixel.align()
     pixel.darken()
     pixel.draw()

Lastly he talked about going to an argument per line for function calls. I want to write a full post on this idea because it has some cool implications in version control. The short version is once a function call gets to 79 characters, just go right to putting each parameter on its own line.

Shortening Lines & Binary Operations

One of the core values of Python is readability.

I think it’s cool a computer language has values.

To encourage this value it has a set of guidelines on how to format your code called PEP 8. Most of these points are applicable to all languages, so even if you aren’t blessed to use Python you still might want to check it out.

One of the PEP 8 rules is lines shouldn’t be longer than 79 characters. This is also a rule in typography. That’s the length of line that doesn’t require extra mental effort to move back to the beginning of the next line.

Much of this post and the next one are from a talk by Brandon Rhodes entitled A Python Aesthetic: Beauty and Why I Python and available on YouTube. It got me inspired to think about this stuff again and motivated to make these posts.

Here’s a few of tips on how to shorten lines effectively.

Shorten Lines By Adding Variables

As Mr. Rhodes pointed out in the source video, it’s a feature of math that you can assign some part of an operation to a variable and use that to pass on to another operation. Why do programmers seem to want to avoid this?

I don’t know, probably because programmers are lazy. Well some programmers. The same kind of programs that use one character variable names and magic numbers.

But not you right?

Example:

canvas.drawString(x, y, ‘Please press {}’.format(key))

Our first thought is using return to shorten.

canvas.drawString(x, y, 
     ‘Please press {}’.format(key))

But if it has to be two lines anyway….

message = ‘Please press {}’.format(key)
canvas.drawString(x, y, message)

Adding the message variable not only shortens the line, it gives us a variable that tells us what it is. The message is now easily changed, printed for debugging or logged later.

Shortening Long Formulas

In math a binary operation is where the two parameters are on either side of the operator. Like 1 + 1. In a way this is a function, just written differently than a normal function would be, ie. add(1,1).

Sometimes you have a big mathematical formula that stretches past 79 characters. Especially if you use good variable names. Here Mr. Rhodes disagrees with PEP 8 and I agree with him.

Example:

adjusted_income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deductions - student_loan_interest)

PEP-8 says to divide binary operations after the operator. This is bad.

PEP-8 badness:

adjusted_income = (gross_wages + 
     taxable_interest + 
     (dividends - qualified_dividends) - 
     ira_deductions - 
     student_loan_interest)

Donald Knuth says divide before the operator.

Knuth Goodness:

adjusted_income = (gross_wages 
      + taxable_interest 
      + (dividends - qualified_dividends) 
      - ira_deductions 
      - student_loan_interest)

This seems much clearer, and put the operators front and center. Subtractions actually look like the variable is negative.

Source: A Python Aesthetic: Beauty and Why I Python by Brandon Rhodes

Image: Photographer Ron Davis (Me). Model Virginia McConnell.

Remove Comments By Making Them Code

I like comments, probably too much. Lately I’ve been rethinking some comments because they just don’t make sense or work in the real world. But not till I watched this video did I realize you could change them into code.

Make A Comment Into a Variable.

Variable names – good variable names – are self commenting. Extreme Programming uses the phrase “Destroy All Comments”.

Example:

# is window too tall
if window.height > 100:
     fix_window_height()

Becomes:

IsWindowTooTall = window.height > 100
if IsWindowTooTall:
     fix_window_height()

Example:

widget.reset(True)  # forces re-draw

becomes:

force_redraw = True
widget.reset(force_redraw)

Also makes it easier to put in debugging code later because you already have a name for the value to print. True is also a magic number in a sense because we don’t know what it means.

Make Code Section Comments Into Functions

Example:

# open the barn
barn = code.Barn.get()
barn.unlock()
barn.open()
 
# saddle the horse
saddle = code.Saddle.get()
saddle.install(horse)

Becomes:

open_barn()
saddle(horse)
 
def open_barn():
     barn = code.Barn.get()
     barn.unlock()
     barn.open()
 
def saddle(horse):
     saddle = code.Saddle.get()
     saddle.install(horse)

I once asked a boss if we could get people to add a few more comments so it would be easier to tell what code did. His reply was that when consultant programmers who get to work on lots of code they didn’t write come into a new project, they run a script that removes all comments. He said comments are often misleading. I think that’s a little extreme, but if you turn comments into code, that documentation will always be there.

Source: A Python Aesthetic: Beauty and Why I Python by Brandon Rhodes

Tactical Coding

When programmers are taught they are taught about how programs work. They are also taught how structure large projects so the parts work together – architecture or strategic programming.

But I don’t ever remember learning tactical programming. This is how to write code at the function and line level to decrease errors and increase things like understanding and readability.

I remember reading the book Code Complete after just a few years as programmer and being blown away. Why didn’t anybody tell me this stuff. You mean my variable names shouldn’t just be one letter? I should check parameters before using them? If I write the shell of a function first, I probably won’t forget to close a bracket or return a value.

I’ve decided to write a series of blog posts about tactics of coding. They have their own category on the blog now – Coding – Tactical.

Of course that means that all our code must be black, because everything tacticool is black.

Footnote: I like the first edition of Code Complete better than the newest one, but it is still good stuff.

Configuring PyCharm, Django and Vagrant

I’ve written about doing development on virtual machines and how to set up Vagrant to run Django. I’ve also been using PyCharm CE for awhile to do simple Python development. Now I’m doing more Django and decided to upgrade to the Professional Edition of PyCharm because of all its cool Django specific features. JetBrains touts you can use it with Vagrant, and built in features to do that. They have tutorials on configuring PyCharm to work with Vagrant and how to use it with Django, but not how to do both.

Turns out this isn’t as simple as it could be and no one has written a comprehensive tutorial on how to do it.

Here it is.

This tutorial will take you from having nothing to having a new Django PyCharm project running on a Vagrant VM.

Create Your Vagrant Virtual Machine

Since I’ve already written how to create a Vagrant VM to do Django development I’m going to assume you are at the same point you were at the end of that tutorial. You have a vagrant instance created. The vagrant directory shares a folder with the server. This article going to call that folder [VagrantFolder]. Any where you see that substitute your folder’s name.

The application I’m creating during this tutorial is called “session_manager”. You should substitute the name of your app.

Launch PyCharm PE and Set-up Vagrant

This tutorial assumes you are using the Professional Edition of PyCharm, as it is the one that has Django support in it. When you launch PyCharm, you’ll get the typical startup window, with its list of known projects and options to create a new one. Now we are going to tell PyCharm about the Vagrant we just created.

Select Configure->Preferences and select Vagrant on the left side.

The only thing you should have to change here is the value of “Instance Folder”. Point it to your [VagrantFolder].

[learn_more caption=”Side Note: Vagrant Not Per Project” state=”close”] I think it is a little strange PyCharm configures Vagrant separate from a project. 

One of the main reasons I use Vagrant is so each project I’m working on has it’s own VM. This means anytime I launch a project, I’m going to want it to have its own vagrant instance. But with PyCharm, I have to come change this preference every time I change Projects.

Actually this may not be true, since a project is “connected” to the Vagrant instance via the “Python Interpreter”, which is bound to one vagrant instance. [/learn_more] 

Create A New Django Project

Close the preferences and go back to the startup window and select Create New Project.

The Create New Project panel will appear for you to fill in.

  • Project name: The name of your new Django Project. In my case this is “session_manager”
  • Location: Click the button on the right and navigate to [VagrantFolder]/django_shared/
  • Project Type: Click the button on the right and select “Django Project”
  • Interpreter: Leave this on its default. (We’re going to have to change it in a minute anyway but you can’t select a remote interpreter in this box).

Click OK to save.

The Django Project Settings panel appears asking for Django specific configuration:

  • Project name: Your project’s name, in my case “session_tracker”.
  • Application name: This has to be different from your project name. {I thought naming them the same was a time honored – if weird – Django tradition.}. I named mine “session_tracker_app”.
  • Templates Folder: I just leave it on the default.
  • Enable Django admin: I’m leaving this checked for my app.

Click OK to save.

Now PyCharm will do its thing and you’ll have a new Django app/project created in your [VagrantFolder]

[learn_more caption=”Why Can’t I Create A Project With Remote Interpreter?”] While writing this I attempted to create the Python Interpreter first, but the “Config from Vagrant File” didn’t work.

Even if I had managed to create it, you can’t select a remote interpreter in the new project window anyway.

Why can’t I create the Vagrant Interpreter before the project and then select a remote during project Creation?[/learn_more]

Create a Python Interpreter For Our Vagrant

At this point we’ve configured a Vagrant machine and we’ve made a new Django project. We need to launch our VM so we, and PyCharm, can do some configuration.

Select Tools->Vagrant->Up and watch it launch your VM launch in the terminal that appears at the bottom of the project window. If this is the first time, this will take awhile.

We have a VM to run our project on, but PyCharm doesn’t know how to run a project on it. Because my Vagrant is setup to share the “django_shared” folder between the host machine and the VM, our code is on the VM. But if you hit run right now, PyCharm would attempt to run it on your host machine, not the VM. The way to change this, is via the Python Interpreter.

In PyCharm you configure which version of Python to use when running your project. By default this uses your local Interpreter, but we want it to use the one on the VM. We need to create a new Python Interpreter.

Where Is Python Installed? It Matters.

I mentioned PyCharm needs to know which Python to use to run a project. This is true on the VM as much as your local machine. In the next step you are going to be asked where python is installed on the VM.

I’ve done this a couple of times and left that path as PyCharm set it. Using the default “/usr/bin/python” made PyCharm think nothing was installed on the VM and then it would give me errors and make me install packages until it was configured right. One of the things I had to do to make it work was to tell PyCharm to install Django, even though my Vagrant file had installed Django.

That seemed so strange I decided to see where python actually was on my VM. Once I did that and set Python Interpreter Path correctly, PyCharm knew Django was installed and didn’t give me any errors.

If you – like me – do not know where python is installed on your VM do this in PyCharm:

Select Tools->Start SSH Session…

Select “Vagrant at [VagrantFolder]” from the list that appears. A terminal will open at the bottom of the screen.

Then do this:

Last login: Sat Feb 22 21:57:54 2014 from 10.0.2.2
vagrant@lucid64:~$ which python
/usr/local/bin/python
vagrant@lucid64:~$

Copy that path for use in the next step.

Create A New Python Interpreter

  • Open Preferences.
  • Select Project Interpreter -> Python Interpreter on the left side. You should see a list of existing Interpreters.
  • Click the + button at the bottom of the list to create a new one.
  • A popup list of Interpreter paths will appear for you to select from. Pick the option, “Remote…”
  • When you do, you’ll get a new window to configure the Remote Python Interpreter. Click “Fill from vagrant config” and select the Vagrant file from [VagrantFolder]. PyCharm will fill in the values of the form.
  • Name: Give your new interpreter a meaningful name.
  • Python interpreter path: where python is installed on the VM.

Click OK to save.

[box type=”warning”] Vagrant Needs to be Up.

If you didn’t Vagrant Up before this, “Test Connection” won’t work and you’ll get a warning when closing the panel. If that happens, close prefs, and use Tools->Vagrant->Up to launch your VM.[/box]

Now PyCharm should know about your VM’s setup. It should show you a list of installed packages. If you are missing something, error messages will appear at the bottom and you can click them to install what it thinks you are missing. If there are no packages listed, try closing and reopening the Preferences window.

ProjectInterpreterWithPackages

 

Click OK to close the Preferences Window.

Configure Your Project to Use the Correct Interpreter

PyCharm now knows about our VM’s Interpreter, we need to tell our project about it and configure things so it will run our Django application in our browser when we click the Run button.

  • Select Run->Edit Configurations…
  • Select the configuration on the right PyCharm created for us. In my case it was called “session_tracker”.
  • Change “Python interpreter” to our newly created one.
  • A new field will appear. Click the button next to “Path mappings”.  A new window will appear to let you create your mappings.
  • Vagrant shares a local directory with the VM. My Vagrant file is configured so a folder is called “django_shared” in our [VagrantFolder] locally, and “django_shared” in the home directory on the VM are the same. You need to enter the full paths of each of those in the “Edit Path Mappings” window. Click the + button to create a new mapping, then enter the values for the mapping on each side.

[learn_more caption=”I Hate Typing Paths”] I hate typing paths, so to make it easy I navigated to the local directory in the OSX Terminal and typed “pwd”, which spit out the full path. I copied that and pasted it into the left side of the Path Mapping Window.

Then I vagrant sshed into my vagrant box, navigated to the django_shared directory and executed “pwd” again. Copied that value and pasted it in the right side.

If you used my script, this value will always be “/home/vagrant/django_shared”.[/learn_more]

Edit_Path_Mappings

Click OK to save the paths.

Back in the configuration window.

  • Click the checkbox to turn on “Run browser:”. Doing this will open your browser to that location whenever you run the Django application and start debugging.
  • For Host: enter 0.0.0.0

This took me a long time to figure this one out. You have to set your host – which is what gets used by Django’s runserver command – to 0.0.0.0. If you leave it the default, you won’t be able to connect to Django from your machine.

Why? According to this blog post, which gave me the idea, it is “because Django webserver bounds the ip to 127.0.0.1, which is loopback in the Ubuntu guest”.

Click OK to save.

That, finally, is it. If you click run or menu Run->Run, your browser should open and you should see the default Django server message.

I just spent five hours writing this tutorial when I’d sat down to start working on my session_manager Django app. I did it because it took me forever to figure out how to make all this work and I wanted it to be easier for the next guy. Please give me feedback if you do find it useful and of course share it.

Setting Up Django on Vagrant

[box type=”warning”]Since I created this post things broke. Namely checking out the latest versions of the Chef cookbooks introduced a whole rat’s nest of dependencies. I spent a day trying to figure them out, but finally decided to just do provisioning via a shell script.

The repository has been updated so the latest version uses the new shell script. If you want the Chef version, it was tagged “v1WChef”.
[/box]

In a previous post I talked about how to do WordPress Development right by using Vagrant to create a virtual machine to do your development in.

I’ve been wanting to improve my Django skills and have a project I want to use it for, so I plan to use the same principle and do my Django coding in a VM using Vagrant.

Figuring out how to do this quickly, easily and reliably was more complicated than I expected. I owe a great debt to Smiley Creatives’ article “SETUP A DJANGO VM WITH VAGRANT, VIRTUALBOX, AND CHEF” and a comment by juanje on how to create a Chef cookbook to install Django.

My goal was to create something where I could run a script and have a whole new development environment for Django set up.

The Vagrant Django Script

If you don’t care how it works, but just want to use it, then do these steps.

1. Clone the repository to your machine.

I’ve created a git repository on bitbucket.org with all the files you need. Just execute this command.

git clone https://bitbucket.org/rondavis007/django-vagrant-creation-scripts.git

This will create a folder on your machine. This folder is not where you are going to run Vagrant from. Rather it is a source folder for creating another folder to run Vagrant from and do your Django development.

2. Create a Target Folder

Make a directory for your development. Note the path to that directory.For our purposes, we’ll assume you want this directory to be next to the directory just created by the git clone command in step 1.

mkdir VMTEST

3. Run the Create Django VM Script

In the folder that was created by git you will find a script ‘create_django_vm.py’. Execute this script with the path to the directory you created in step 2.

cd django-vagrant-creation-scripts/
python create_django_vm.py ../VMTEST/

If you look in the new directory you’ll see something like this:

-rw-r–r– 1 rondavis 2920 Feb 5 14:39 Vagrantfile
drwxr-xr-x 12 rondavis 408 Feb 5 14:39 cookbooks
drwxr-xr-x 2 rondavis 68 Feb 5 14:39 django_shared

You have a new Vagrantfile, a folder full of Chef cookbooks, and a django_shared folder that will be shared with the VM.

4. Move To Your New Directory and Vagrant Up

That’s it, you are ready to go.

cd ../VMTEST/
vagrant up

That’s it. There will be a bunch of Vagrant launching text, but when it’s finished you can:

vagrant ssh

You’ll find a directory in your home directory named “django_shared”. This is the same as the folder “django_shared” in the directory you just vagrant sshed from.

From here you can do all your django commands on your VM. Edit the files on your host OS, and view the app via your browser.

Running Django On Your VM

Let’s make sure our development environment is able to run Django by duplicating the first steps of the Django Tutorial.

Once you are logged in:

vagrant@lucid64:~$ cd django_shared/
vagrant@lucid64:~$ django-admin.py startproject mysite
vagrant@lucid64:~$ cd mysite
vagrant@lucid64:~$ python manage.py runserver 0.0.0.0:8000

First we move into our shared directory, then we create a new Django project with the django-admin.py script. Then move into the newly created app folder and run the server.

Now go back to your browser and point it to http://localhost:8000/ and you should get the standard Django welcome.

Welcome_to_Django

A special note about the runserver command on your VM. You can’t just use the default ‘manage.py runserver’ because the VM won’t let that be shared. Instead you must tell it to run the server on 0.0.0.0:8000 to let it be seen outside the VM

I think the code that makes all this happen is well documented, so I won’t go over it all here. Let me know if you use this script and how you like it.

Verbose Switch a Cleaning Up Code Example

There are few principle we here at Reactuate Software try to keep in mind when writing code. One is DRY, or “Do not Repeat Yourself”. Another is “Readability Counts”. So when I see code that looks like this, I cringe.

- (IBAction)dayButtonPressed:(id)sender {
    UIButton *b = (UIButton*)sender;
    theDay = b.tag;
    switch (b.tag) {
        case 2:
            monButton.selected = YES;
            tueButton.selected = NO;
            wedButton.selected = NO;
            thButton.selected = NO;
            friButton.selected = NO;
            satButton.selected = NO;
            sunButton.selected = NO;
            break;
        case 3:
            monButton.selected = NO;
            tueButton.selected = YES;
            wedButton.selected = NO;
            thButton.selected = NO;
            friButton.selected = NO;
            satButton.selected = NO;
            sunButton.selected = NO;
            break;
        case 4:
            monButton.selected = NO;
            tueButton.selected = NO;
            wedButton.selected = YES;
            thButton.selected = NO;
            friButton.selected = NO;
            satButton.selected = NO;
            sunButton.selected = NO;
            break;
        case 5:
            monButton.selected = NO;
            tueButton.selected = NO;
            wedButton.selected = NO;
            thButton.selected = YES;
            friButton.selected = NO;
            satButton.selected = NO;
            sunButton.selected = NO;
            break;
        case 6:
            monButton.selected = NO;
            tueButton.selected = NO;
            wedButton.selected = NO;
            thButton.selected = NO;
            friButton.selected = YES;
            satButton.selected = NO;
            sunButton.selected = NO;
            break;
        case 7:
            monButton.selected = NO;
            tueButton.selected = NO;
            wedButton.selected = NO;
            thButton.selected = NO;
            friButton.selected = NO;
            satButton.selected = YES;
            sunButton.selected = NO;
            break;
        case 1:
            monButton.selected = NO;
            tueButton.selected = NO;
            wedButton.selected = NO;
            thButton.selected = NO;
            friButton.selected = NO;
            satButton.selected = NO;
            sunButton.selected = YES;
            break;
        default:
            break;
    }
}

This code is in an iOS app I inherited and it handles this control.FrequencyControl

To me this violates both the concept of DRY and the concept of Readability. It is pretty obvious what the routine does and you can even guess how it works. But the devil is in the details. Yes you know it is turning off all the buttons but the day that is selected. What if one of those case statements was messed up and accidentally had two buttons set to true? The sheer number of repeated very similar values would make it a pain to find.

Plus its just ugly and inelegant.

Here’s the 30 second fixed version:

 
- (IBAction)dayButtonPressed:(id)sender {
    UIButton *b = (UIButton*)sender;
    theDay = b.tag;
 
    monButton.selected = NO;
    tueButton.selected = NO;
    wedButton.selected = NO;
    thButton.selected = NO;
    friButton.selected = NO;
    satButton.selected = NO;
    sunButton.selected = NO;
 
    switch (b.tag) {
        case 2:
            monButton.selected = YES;
            break;
        case 3:
            tueButton.selected = YES;
            break;
        case 4:
            wedButton.selected = YES;
            break;
        case 5:
            thButton.selected = YES;
            break;
        case 6:
            friButton.selected = YES;
            break;
        case 7:
            satButton.selected = YES;
            break;
        case 1:
            sunButton.selected = YES;
            break;
        default:
            break;
    }
}

See how much cleaner that is. There are situation where setting all the controls one way and then immediately setting them to on might cause a flicker, but iOS isn’t one of them.

Since I’m in this code anyway….

Here’s an even more cleaned up version

 
/* --------------------------------------------------------------------------------------------
 
	dayButtonPressed
 
	Description: 
		Action method for the day of the week frequency control.
 
	-------------------------------------------------------------------------------------------- */
- (IBAction)dayButtonPressed:(id)sender
{
    UIButton*   button = (UIButton*)sender;
    theDay = button.tag;
 
    monButton.selected = NO;
    tueButton.selected = NO;
    wedButton.selected = NO;
    thButton.selected = NO;
    friButton.selected = NO;
    satButton.selected = NO;
    sunButton.selected = NO;
 
    switch (button.tag)
    {
        case SUNDAY:
            sunButton.selected = YES;
            break;
        case MONDAY:
            monButton.selected = YES;
            break;
        case TUESDAY:
            tueButton.selected = YES;
            break;
        case WEDNESDAY:
            wedButton.selected = YES;
            break;
        case THURSDAY:
            thButton.selected = YES;
            break;
        case FRIDAY:
            friButton.selected = YES;
            break;
        case SATURDAY:
            satButton.selected = YES;
            break;
        default:
            NSAssert(false, @"Day button Tag and unknown value %d", button.tag);
            break;
    }
}

I had to define some constants but it is much more readable now. I also hate one letter variables, so the button variable got renamed as well.

Added an assert for something that should never happen, namely the value of the tag not being between 1 and 7. NSAsserts are only handled in non-release builds, so there isn’t a chance of it crashing the shipping app.

Also added is my “short” routine header for Objective-C code. It just tells what the method does . It doesn’t bother to tell what the parameters or return values are, because saying it is an “action method” tells an experienced iOS/MacOS programmer all that information.