Thursday 17 December 2009

Validation

It can be quite hard to tell whether your programming skills are up to scratch if you're not doing so professionally or otherwise producing code that will be scrutinised by others, such as for an open-source project, or being taught in a classroom environment. You can't help but think "Am I doing a good job?", and it's difficult to get outside validation.

So today, when I came across a blog post referring to the FizzBuzz Test I thought I'd have a go. I decided to use Python as that's the language I know best, but I was a bit concerned about being a bit rusty as I haven't done much Python coding for a while due to concentrating on other things. As it turns out I needn't have worried. Here's the code I came up with:

def fizzBuzz():
for i in range(1,101):
if i % 3 == 0 and i % 5 == 0:
print "FizzBuzz"
else:
if i % 3 == 0:
print "Fizz"
elif i % 5 == 0:
print "Buzz"
else:
print i

fizzBuzz()

Not too shabby, and if this blog post is correct, it puts me ahead of a few people who are already working as full-time programmers! After doing that, I felt a bit better about my skills.

I wrote a Python script a few months back when at work we had to use one Excel spreadsheet among many, many people to update some details. If you've used Excel a lot, you may know that this can be a recipe for disaster - if you have sharing disabled, only one person can use it at once (and inevitably someone will go to lunch with it open), and if it's enabled you run the risk of someone overwriting what you've just entered. In frustration I wrote the following Python script to allow me to update the file without going into it. Please note that it requires the xlrd and xlwt modules:

# Spreadsheet Updater
# Written to allow an Excel spreadsheet to be updated automatically without opening it manually

from Tkinter import *
import xlrd, xlwt, datetime, tkMessageBox

class Application(Frame):
"""GUI application that takes data to be input into a spreadsheet. """
def __init__(self, master):
""" Initialize Frame. """
Frame.__init__(self, master)
self.grid()
self.create_widgets()

def create_widgets(self):
""" Create widgets to get information to enter into spreadsheet. """
# create instruction label
Label(self, text = "Enter details for a new entry in the current spreadsheet (saved as Current Month)").grid(row = 0, column = 0, columnspan = 4, sticky = W)

# Policy Number
Label(self, text = "Policy/Scheme Number").grid(row = 1, column = 0, sticky = W)
self.policy_no = Entry(self)
self.policy_no.grid(row = 1, column = 1, sticky = W)

# System
Label(self, text = "System Number").grid(row = 2, column = 0, sticky = W)
self.system = Entry(self)
self.system.grid(row = 2, column = 1, sticky = W)

# Log Ref
Label(self, text = "Log Number").grid(row = 3, column = 0, sticky = W)
self.log_ref = Entry(self)
self.log_ref.grid(row = 3, column = 1, sticky = W)

# Name
Label(self, text = "Name").grid(row = 4, column = 0, sticky = W)
self.ph_name = Entry(self)
self.ph_name.grid(row = 4, column = 1, sticky = W)

# Reason for Change
Label(self, text = "Justification for change").grid(row = 5, column = 0, sticky = W)
self.reason = Entry(self)
self.reason.grid(row = 5, column = 1, sticky = W)

# Incorrect Data
Label(self, text = "Incorrect Data").grid(row = 6, column = 0, sticky = W)
self.incorrect = Entry(self)
self.incorrect.grid(row = 6, column = 1, sticky = W)

# Correct Data
Label(self, text = "Correct Data").grid(row = 7, column = 0, sticky = W)
self.correct = Entry(self)
self.correct.grid(row = 7, column = 1, sticky = W)

# Spacer to separate Correct Data from Validated
Label(self, text = "").grid(row = 8, column = 0, sticky = W)

# Admin Validated
Label(self, text = "Have Admin validated change?").grid(row = 9, column = 0, sticky = W)
self.validated = StringVar()
admin_validate = ["Yes", "No"]
admin_column = 1
for entry in admin_validate:
Radiobutton(self, text = entry, variable = self.validated, value = entry).grid(row = 9, column = admin_column, sticky = W)
admin_column += 1

# Admin Informed
Label(self, text = "If not validated, Hand off to Admin method done?").grid(row = 10, column = 0, sticky = W)
self.informed = StringVar()
admin_inform = ["Yes", "No", "N/A"]
admin_inform_column = 1
for entry in admin_inform:
Radiobutton(self, text = entry, variable = self.informed, value = entry).grid(row = 10, column = admin_inform_column, sticky = W)
admin_inform_column += 1

# Admin details
Label(self, text = "Admin Details").grid(row = 11, column = 0, sticky = W)
self.admin_details = Entry(self)
self.admin_details.grid(row = 11, column = 1, sticky = W)

# Processor
Label(self, text = "Owner").grid(row = 12, column = 0, sticky = W)
self.processor = Entry(self)
self.processor.grid(row = 12, column = 1, sticky = W)

# Create a submit button
Button(self, text = "Click to submit", command = self.update_spreadsheet).grid(row = 13, column = 0, sticky = W)

def update_spreadsheet(self):
""" Create a Python list containing all the values from the application, plus the date, and append it to the spreadsheet. """
# get the date
raw_date = str(datetime.date.today())
year = raw_date[0:4]
month = raw_date[5:7]
day = raw_date[8:10]
date = str(day + "/" + month + "/" + year)

# get policy number
policy_no = self.policy_no.get()

# get system
system = self.system.get()

# get log ref
log_ref = self.log_ref.get()

# get name
ph_name = self.ph_name.get()

# get reason for change
reason = self.reason.get()

# get incorrect data
incorrect = self.incorrect.get()

# get correct data
correct = self.correct.get()

# get Admin Validated
validated = self.validated.get()

# get Admin Informed
informed = self.informed.get()

# get Admin details
admin_details = self.admin_details.get()

# get processor
processor = self.processor.get()

# create a Python list to hold the elements for adding to the form
new_entry = [date, policy_no, system, log_ref, ph_name, reason, incorrect, correct, validated, informed, admin_details, processor]

# If an element is empty, bring up a warning and break out
all_complete = True

for entry in new_entry:
if entry == "":
all_complete = False
break

if all_complete == True:
try:
self.write_to_spreadsheet(new_entry)
self.confirm_message()
except:
self.fail_message()
else:
self.incomplete_message()

def write_to_spreadsheet(self, new_entry):
""" Method to import the contents of the spreadsheet to memory, then save it again, overwriting the original. """
# Import the spreadsheet as a Python list with a nested list for each individual row
book = xlrd.open_workbook("Current_Month.xls")
sheet = book.sheet_by_name("Sheet1")

entries = []

for i in range(50000):
# if the first cell of the current row is empty, break out of the loop
try:
entry = []
for cell in sheet.row_values(i):
entry.append(cell)

entries.append(entry)

except(IndexError):
break

entries.append(new_entry) # Add the new entry to the spreadsheet

# Write the resulting list back to the spreadsheet
new_book = xlwt.Workbook(encoding="utf-8")
new_sheet = new_book.add_sheet("Sheet1", cell_overwrite_ok = True)
i = 0
for entry in entries:
j = 0
for item in entry:
new_sheet.write(i, j, item)
j += 1
i += 1

new_book.save("Current_Month.xls")

def confirm_message(self):
# Display a message confirming input processed
tkMessageBox.showinfo("Confirmed!", "New entry confirmed!")

def fail_message(self):
# Display a message warning input failed
tkMessageBox.showerror("Error!", "Error in writing to spreadsheet!")

def incomplete_message(self):
# Display a message if not all fields are completed
tkMessageBox.showwarning("Incomplete!", "Warning! Form not completed in full!")

# main
root = Tk()
root.title("Spreadsheet Updater")
app = Application(root)
root.mainloop()


Sadly, it doesn't show up well in Blogger - the ends of some lines are chopped off. I was quite proud of it - it does the job I wrote it for, which is all I can ask, and it looks fairly elegant to me. Sadly, I wasn't able to use it at work as it would have required everyone who needed to access the spreadsheet to have Python installed, and I was not able to get this (I won't go into why, but I do understand the reasons I was given, and they were pretty good, and potentially I could have done the same thing in VBA, if I knew it, without needing to install any software).

This put a damper on what I would like to have done next - written a second script to export the contents of the Excel spreadsheet to an SQLite database, then created an amended version of the updater to update the database instead of the spreadsheet, then finally written another script to export the contents of the database to another spreadsheet, thus enabling us to use a database to record the data in the first place (a much better solution!) while still retaining the option of getting it in spreadsheet form if necessary.

So I had this code just lying around, without a use. I've therefore submitted it to Useless Python - as at right now it hasn't been accepted yet, but hopefully it will be. I'm looking forward to people's feedback about it - for that matter, please feel free to comment here! I would welcome any constructive feedback.

In the last couple of years I've learned HTML, and a fair bit of Python. Earlier this year I finished my CIW Foundation course, and then spent a couple of months studying C. Even though I kind of got stuck on pointers, I learned quite a bit, and now any programming language whose syntax is based on C is a lot easier.

I'm also beginning to understand why so many experienced programmers say that they can learn a new language in a week or so. I'm now studying JavaScript and much of the syntax is almost identical to that of C, so it's very easy to pick up the core language itself. Also, a lot of concepts are common to virtually all programming languages - if/then statements, while and for loops are near-universal, for example, so you only have to learn them once.

I've now bought the books for the CIW Master Enterprise Developer certification, and it means I'm going to have to learn JavaScript, Perl, PHP and Java, as well as classic ASP and SQL. Assuming I complete it, I will have qualifications to validate my abilities, but for my money that's not what makes a great programmer.

A great programmer is someone who writes code that does the job efficiently, but is also elegant and easy to understand. Qualifications can't tell you how elegant or efficient your code is, nor how readable it is. And this is where it gets really hard to get validation - you can know your code works, but it's very difficult to know if it's good code if you don't have a wealth of experience.

No comments: