Tuesday, January 30, 2018

Pushing Forward

One of my biggest challenges with retooling myself into being a software engineer is to focus on the kind of knowledge I'll need.  On the one hand, I need to know the things that someone who has a Computer Science degree would know, and on the other, I need to be able to perform at my position.  I've had some time over the past week where work is light due to training, and I have been using my off hours to study.  But, what to study?  Should I be poring over my new tome, Cracking the Coding Interview, or should I be trying to take up C#?  After all, LinkedIn tells me C# developers make way more than I'm making now.  How about getting better at MVC?  What about that Neural Network Udemy course?  I'll be using neural networks at work soon and I'd like to be prepared.  So far, I feel like Seven of Nine from one of my favorite episodes of Star Trek Voyager.  

Seven of Nine, one of my favorite characters from any of the Star Trek series (sorry, Michael Burnham), tries to enhance her intelligence by downloading copious amounts of data directly into her brain.  She is flooded with information, and while it does prove useful in the short term, in the long term, she has so much information floating around in her cranium that she doesn't know what to do with it.  Before long, she conjures up fantastic tales of how Captain Janeway is really working with Starfleet Intelligence.  Good stuff.

I want to use my time effectively.  I quit teaching in the beginning of 2017 and set out to be a software engineer.  I did it mainly because it was always a secondary skill I had never taken the time to cultivate, and to be perfectly blunt, software and programming is where the economy is heading.  If the wave is rising and everyone is surfing, I want to be there.  Of course, everyone hears about the software engineer making $500,000 at Google.  I have no idea if I'll reach that point, but I do want to gain the skills and knowledge necessary to really rise up.  So, how to make the best use of my time?

The first thing is to realize I've developed lots of soft skills over the years.  I'm a great communicator, strong willed, and creative.  The second thing to realize is that it's not about knowing lots of different computer languages, it's about design.  I'm an engineer after all.  So what I've been doing is focusing on skills that translate from language to language.  I've been trying to understand Big O thoroughly, and to understand the different data structures and algorithms.  I've been trying to identify how to use design patterns, when they're useful, and when they're not.  

The other thing is to pat myself on the back about the major projects I've been working on.  I programmed all functionality for tracking employee utilization, including dashboards and designing the database.  I've worked on front end user interface using JQuery, making web pages look crisp and clean with Bootstrap, and utilizing MVC.  I've programmed interfaces to grab API data and a very complicated import process that involved a SQL script with 6 joins.  

My goal for the next 6 months is to master the basics of computer science, and Cracking the Coding Interview should be great for accomplishing this goal.  I want to learn one more language, C#, really well.  I feel like I'm well versed in Visual Basic and Python, and a third language would round things out nicely.  I know some JQuery and Javascript, but I think knowing them enough to get what I want done is good enough for the moment.  I also know have picked up a bit of Assembly and Ladder Logic at my job from working with PLCs, which won't get me many accolades, but could be used for industrial applications.  

The main thing to remember is patience.  Rome wasn't built in a day.  I am pushing myself a ton to become smarter, more skilled, and better at this new craft.  I've decided it's what I want to do.  

Monday, January 22, 2018

Chain of Responsibility Pattern

When I first started programming I read a book about design patterns called "Head First Design Patterns."  Let me tell you, it was mostly over my head.  Don't get me wrong.  I definitely recommend the book.  But for a beginner, it is not.  The thing is, you're warned early on as a programmer that design patterns are seductive.  You'll start trying to apply the pattern, even when a pattern isn't really necessary.  I did this a lot, of course, because using a design pattern makes you feel like a real programmer.  You feel like a wizard looking through his bookshelves for just the right spell to change your friend back into his human form after being transformed into a polka dotted flamingo by the local witch.

Seriously, Internet?  Seriously?

The thing is, the problem comes first, and the design pattern usually needs to be tweaked before it's actually useful for your specific problem.  Well today, I finally used a pattern successfully at work (much to the relief of my boss) and I think my design will stand the test of time.  My problem was simple: an approval process.  For our company, we need a process to be able to move documents around.  Say you have Billy in Engineering.  Billy needs to look at the specs of the car before passing off the specs to Mike, the machinist.  Mike will look at the specs, start hammering and welding to get the metal all in place, and then he'll send his truck full of parts to the factory where Leila the foreman will receive the materials.

So at first blush, I thought that a simple linked list would be able to handle this scenario.  Each link in the chain would just be an employee.  The list would know which direction it was going, and that would be that.  No need for a design pattern.  However, I thought about the problem some more and came up with scenarios that may break my plan.


What if Leila the foreman, ever so meticulous and exacting in standards, says that the pipes she received are the wrong size?  How can she kick the process back to Mike?  What if it needs to be kicked back all the way to Billy in Engineering?  How would the process know to kick something three steps back?  Even worse, what if there is more than one gatekeeper?  What if after Leila receives the parts, she must report to Andrew the accountant, Mayvin from documentation who needs to make sure her lovely Excel spreadsheets are filled with parts information, and Ezekiel the shift manager who has to line up guys to start building the machine.  If and when all 3 of these people are finished is when the process moves on to Gabriel the head manager, calmly sipping coffee in his office.

My linked list wouldn't necessarily account for that, nor would it account if there were stipulations for each step in the process.  Wouldn't it be convenient if the step in the process that had to do with Mayvin knew that she needed to upload her Excel sheet of the spare parts list?  Then, the Excel file could be available to people later on in the process.  Mayvin doesn't need to know exactly who is looking at her Excel file, but at least it's available in case Justin the line man working on the plant floor needs to know how much a sprocket is running these days.

So, to lay out my problem, what I need is:

1. A way to separate each part of the process from the whole.  That way, when I create a brand new process, I'm just moving pieces around or creating new ones.  It's like letter blocks. You can take the letters T-E-A-M and make them M-E-A-T.
2. Having multiple gatekeepers in a rung.  Heck, why not multiple rungs?  I could possibly have some complex processes.  Maybe there are two different branches that are going and then they meet at a certain point 5 steps down the line?
3. Keep track of the overall progress.  Since I can have a process that can be simple or short, I cannot hard code the actual process.  I don't want to lock it in either.  What if later on down the line, while the process is still going, someone makes an alteration?  What happens if poor Ezekiel gets fired Christmas day?
4. The process should be reversible.  There should be a way to back up the process at any point in case something changed.
5. A flexible way to handle requirements at a given step.  The minimum would need the user to "okay" that their step has been handled, but there should be a gentle reminder for them as to what they should be doing, or to make files or info available to people later down the chain.

Tall order.  However, I believe I hit pay dirt.  First off, I think the problem lends itself to a tree data structure with each "Approver" as a node in the tree.  How to handle the actual approval process?



Welcome to the Chain of Responsibility pattern.

Well, a version of it any way.  In the original design pattern, it's a way of separating the thing that is making a request from the objects that handle it.  That means if I want to buy a fancy new office chair, and I have to ask purchasing for approval, I send my request to a handler.  The handler will ask the concrete handlers what to do.  My chair is $100.  The first concrete handler (let's say the secretary) only deals with purchases less than 50 dollars because that's what's in petty cash.  She'll call her manager, and he'll deal with the purchase of my expensive office chair.  The request gets kicked down the line until someone deals with it.  I decided for my workflow, I'd use this pattern as a form of inspiration.

Each person in the chain is an "Approver."  They know the previous person in the chain (0 if there they are at the head) and they know the next person in the chain.  After all, Billy just needs to know to let Mike know he's done.  Past that is no concern of his.  The approver's know what they have to do before they can declare themselves "approved."  The Approval Process object is quite simple.  It will instantiate all of the approvers that belong to it.  It doesn't know what order they go in, and doesn't need to.  It can iterate through all of the approvers that belong to it, and ask them if they are done.

The Approval Process object is now highly flexible because you can remove or add approvers at will.  The process has no idea in what order they go in, so none of that is hard coded.  All it needs to do is get them together.  It can have a function to get all of the approvers in whatever order they are in, using their ids to create a tree, and then ask them if they are complete.  The approvers know who their parent node and child node is, and I can get all nodes that share parent and child, so I can get a tier and separate out branches if this is a multi branch process.

I decided to decouple it even more, so that the requirements for an approver were decoupled from the approver itself.  That way, the requirement for each approver can be tweaked and edited without having to make a new object.  It could even be reused.

I know, this isn't quite chain of responsibility, but the design got me thinking along the same lines, I think it's flexible enough it can be used for anything from purchase order requests (which would totally be chain of command), to workflow for a major project.  Feeling good about my life as a coder today.

Tuesday, January 16, 2018

The Magical Adventures of Excel Imports

I was given a project by my manager for a client that seemed simple on its face.  Our client wanted to be able to create an Excel sheet, fill it with data about their investors in a partnership, upload all the data, and then fill the partnership up with all of the financial transactions and data from the import. We would provide the end user with a glorious template.  Just copy and paste the info into the template! The client also wanted the computer to look through our database to see if the investor data was already present, and to just pull that data in case.  So all I would have to do is upload the Excel sheet, store the data into a table, and then sort the data.  Easy stuff, right?

What my manager said the project would be like.


What it was actually like.
I developed a strategy to deal with the import.  First, I used SQL Bulk Copy to take all the data and dump it into it's own special table.  Each upload had a "Batch ID," that way a user could recall a batch if needed.  After the batch was uploaded to the SQL table, I had a stored procedure that checked the other tables for investor data and pulled it in.  The user would be presented with a web page that was divided into two parts: records where the investor and all relevant information was found, and records where that wasn't  true.  For records it couldn't find, the user could manually input the information into a text box, or use a drop down list.  All the user had to do was push a button that said "Import Data" and off to the races!

The best laid plans of mice and men.

I learned the hard way that whenever you program something, you need to have your problem defined very clearly from the outset.  Just because an end user says they want the program to work in a certain way, that's not necessarily what they mean.  You need to have a "success" condition, some way to know that your program is working as intended, and to figure out a way to predict situations and curve balls before they hit you hard and you have to refactor. I didn't take the time to ask the right questions, so the project took an excessive amount of time, and I had to do a lot of last minute refactoring to get it to work the way the client actually wanted it to work.

Also, communication, communication, communication.  

First off, even though we gave the client a template, they ignored it.  We could not get the end user to understand that he/she could not just put in any ol' Excel file and expect the software to work.  This added extra work on my end.  I had to prepare the files for import myself.  I felt like the tax specialist who has someone come in with an old shoe box filled with various family keepsakes, random papers, and dog hair, looking expectantly for you to "make it work."  

It's difficult to deduct the expense of this broken coffee mug sir...

Secondly, I was given a test sheet filled with data.  That's all well and good, but it made me too optimistic about the data I would receive.  The test set I received had all of the fields filled with data.  When they gave me the real Excel sheets they wanted to import, half the data was missing!  How could I find investor data with no ID or client data?  One sheet had financial transactions, but the other sheet had them in an entirely different format.  

Also, I was given the sheets two days before the big client meeting.  I had a chit chat with my boss about timing.

Third, scouring the SQL tables took eons.  I'm working with legacy code, and all the data I needed was in four tables.  Sounds simple, right?  Well the foreign keys got so confusing, I thought I was seeing double. I found myself asking "What the heck is the PartnershipPaymentTypeID?" and trying to make sure if I had to write a new investor that all of the foreign keys matched where they should.  I felt like Indiana Jones raiding a dark temple trying to learn the secrets of the SQL tables.



Fourth, and most importantly, QA took forever.  I hadn't consider that instead of an Excel import, the end user might want to upload pictures of his/her safari to Africa.  That would break my code.  What if instead of writing how much was invested, they instead wrote "Bob was here."  That would break my code.  What if they just enjoy clicking the upload button because they think it's a soothing sound?  That would break my code.

I had to do more prep work in making sure the user input was funneled into acceptable parameters and let them down gently when they stepped out of line.  

All in all I learned a ton from this project.  Sure, I got a lot of flak for the amount of time it took (by flak I mean a chain of expletives).  I also learned that I should always have the mindset that anything I write must be ready for an end user.  I also learned to push back.  Deadlines should be communicated WAY in advance, and I should have someone sit down and help me develop the scope of the project.  I'm getting better, but my stress level will go down as I learn to handle these projects with more finesse.

Tuesday, January 9, 2018

Checkpoint

So I made the transition from History teacher to Software engineer in earnest last year in August.  I had some programming experience before, but totally just for fun, when I worked as a developer for an online text MUD.  I was working at a robotics firm and decided web development and software engineering might be more my speed, rather than doing controls work.  A friend of mine trained me for a few months in software engineering concepts.  It was hardcore, but worth it.  In the end, my current boss took a chance on me; after all, I had no direct programming experience.  He made me Software Engineer 1 and probably didn't think much of me at the time.  Well, I've been at it for almost 6 months now, gotten a raise, and after a lot of scratches and bruises, I wanted to collect my thoughts and go over what I've learned from being in the pit. 

For some background, I do a ton of stuff at my job.  We are working on project management software to assist the company in doing HR and just about everything the company does.  I've basically been handling tracking employee utilization single-handedly, making easy to read charts for the company managers to track their employees.  On top of that, we contract out to a real estate company and create programs that they need for their customers to manage their properties.  In the future we're going to work on predictive maintenance for car factories using neural networks, which I've been knee deep in for months now.  When there is down time I do translation work.  This may sound like a lot.  That's because it is.  It's also given me a bit of perspective on everything.  Well, like I promised, my list of lessons learned over the past 6 months.

1. Fast, cheap, good.  Pick 2.  One of the biggest things I've learned is to stick up for what you can do, but also to be clear about your own limitations.  Getting work done right takes time.  Rarely if ever does a job seems as simple and clear cut as the customer makes it out to be.  There's nothing wrong with saying that a 30 hour job will take 30 hours, and if the customer wants it done faster, they will have to sacrifice something.

2. You're worth something.  I am not a braggart and I do not broadcast my abilities.  Partially, this is because when I was younger, my abilities made me stick out and tended to alienate me from other people.  I speak 7 languages (soon 8), but you wouldn't know it from talking to me.  At work, I felt because I had little experience, that I should be grateful to be given assignments and should accept any deadline given to me.  It made me a door mat.  I was given deadlines I couldn't reach, I was often left to my own devices without assistance, and more work was piled on.  I eventually stood up for myself and said that I'm given too much to do in too little time, and my boss responded with a simple nod and a restructuring of responsibilities.

3. Good programming concepts are like gold.  We use Visual Basic at work.  When I talk with friends who are software developers, they let out a gasp at hearing this.  "No one uses VB anymore!" they'd exclaim in shocked panic (well, maybe not).  True, I feel my knowledge of VB won't put me in any programmer hall of fame, but VB is just a means to an end.  Good programming involves creating a logically consistent and sound set of syllogisms with a clear end goal and no leakage.  During my time with my friend training in computer programming, he stressed to me how important fundamentals were.  Learn the data structures.  Learn the different sorting algorithms.  Understand null handling and type checking.  Separate functions and never repeat code; reuse it.  End users are by definition unpredictable.  Be careful about what you think you know.

4. Always learn.  I'm a lifelong learner and an avid reader, but even I slack off sometimes.  It's better to know more today than you did yesterday.  Each day, I try to learn a new concept, or a new command, or a new piece of VB or Python to understand. The reason is not just knowledge acquisition, but also to train your mind to be flexible enough for new situations.  I've done a lot of programming and have met different challenges, and part of what helps me to keep going is I'm always finding new solutions to problems.

5. Rome wasn't built in a day.  I know, corny.  It's true, though.  There's so much to learn.  And even after you learn it, you need to apply it.  I learned design patterns my first month of programming.  Did I understand them?  Good lord, no.  I was patient, and have gone over the material several times as my skill has grown.  The other day at work, I successfully used the decorator pattern to make creating reports easier.  I chose the pattern not because I set out to use a pattern and to force it to fit to circumstances, but because each report was different and I needed a decorator to handle the dozens of different reports that the customer may need on the fly. 

There's of course more, but I need to get some shut eye, and these were the lessons that stuck out most.  In the end, the amount I don't know outweighs what I do, and with each day I feel more acutely aware of that ratio.  However, I feel this is the job for me.  Why?  The satisfaction I feel at solving complex problems is indescribable.  I love coming up with complex code to hack and slash the data with a chainsaw until it takes the shape I need.  I love presenting end users with software that'll make their lives easier.  The utilization software I came up with saves one of the girls in HR at least 2-3 hours every week of compiling data, not to mention the graphs and extra tables she'd have to make and the emails she had to send.  For the moment, I intend to stay in this for the long run, and see where it'll take me.

Tuesday, August 22, 2017

Long Hiatus - Software Engineer Level 1

So I work at an automation firm now, and hopefully it will provide a good means for me to gain more experience and start learning some good, practical skills for computer programming.  After a few months, my official title is now "Software Engineer Level 1" and working on company software projects.  I was really excited to be transferred into the department, because I'd be around people who know way more than me who I would be able to learn from.

There have been some surprises already.  To build our software, we're using Visual Basic.  I did not know Visual Basic even existed a few weeks ago.  Our team leader is comfortable with Visual Basic and prefers to program in it, so since I'm the new one on the block, I just shrugged my shoulders.  So far, in the past few weeks I've had to do a crash course in MVC in VB.Net, C#, SQL, and Jquery.  I won't be able to use my Python skills for awhile.

Visual Basic was not difficult to learn.  It was annoying to go from Python where variables are automatically typed to VB where you have to declare a variable type yourself.  I was so used to typing "a = 5" and just leaving it that it took me a good while before I got into the groove of it with VB.  I had to also learn a bit about how classes and namespaces are handled, but a lot of the general idea is the same.    I do find VB a bit verbose, but that's coming from slick, clean Python world.

The main thing I'm learning is how to plan out a large program.  The software we're making for the company is pretty big.  We have dozens of objects, we have a big database of all our employee information, dozens of stored procedures, and pretty much everyday, one of the managers drops by our programmer cave, leans in Office Space style, and says that they want to be able to log in to our program on their phone and start their cappuccino maker remotely so it's steaming hot by the time they sit at their desk.

It's difficult to sit down with someone who isn't a programmer, but will be the end user of your product, and translate their needs and problems into code, but also a fun challenge.  You have to identify the things that computers are good at and how to best leverage it to solve the problem:

  • Is it repetitive?  Let a computer do it.
  • Is there lots of relevant data to store and remember for later? Let a computer do it.
  • Need to transform the data multiple times?  Let a computer do it.
People tend to be very helpful in describing what their needs are, but a lot of planning out our new software is anticipating certain needs that maybe the end user didn't think about.  In the end, our software is going to save hours and hours upon hours of time spent doing repetitive tasks and will offer accuracy of information which should improve all facets of the business.  I love efficiency.



Saturday, January 21, 2017

Gaze at my syllogisms!

So I have been hacking away at the Text Adventure (pun intended) and I implemented the wear and wield actions yesterday.  They were far more complicated than I gave them credit for.  The character needs to wear and wield armor, but then I thought about the problem more, and it turned out that actually:

Characters have body slots to wear and wield weapons
Only weapons go in the Main Hand and Off Hand slots and only armor can be worn.
Characters have class constraints as to what they can wear and wield
Some weapons are two handed, some are not
Some characters can dual wield, others cannot
Main hand is always equipped first
Needs to support the use of keywords

I remembered that it is best to unit test first, then build your code.  I literally went through all of my axioms for the system, and then test by test built up the function to make sure it was working properly.  I LOVE pytest fixtures, because they made the testing process a whole hell of a lot easier.  Testing helps you to narrow down what the function is actually supposed to do.  I tried to test vigorously, going for each permutation and thinking about how to narrow down the possibilities so that the player is only allowed possibilities I want.  Yes, there was probably a less verbose, better way of doing all this, but it works and all of my unit tests passed.  Behold, my wield function in all of its syllogistic glory!

class WieldAction():
    def __init__(self,item_repository):
        self.item_repository = item_repository

def do(self,state,itemname):
    player = state.player
    if not itemname:
        print("Wield what?")
        return    for itemid in player.inventory:
        item = self.item_repository.get_by_id(itemid)
        if itemname == item.get_name():
            #Is it a weapon            if item.get_type() != "Weapon":
                print("That cannot be wielded.")
                return            #Does your class allow you to wield this?            elif item.get_weapon_type() not in player.guild.get_allowed_weapon_types():
                print("{0}s are not allowed to wield {1}s".format(player.guild.get_name(), item.get_weapon_type()))
                return            #Druids can't wield metal objects            elif player.guild.get_name() == "Druid" and item.get_material() in ["iron", "steel", "copper", "bronze"]:
                print("Druids may not wield weapons made of metal.")
                return            elif item.get_handed() == 2:
                if player.race.get_body_slot("Main Hand")==0 and player.race.get_body_slot("Off Hand") == 0:
                    player.race.set_body_slot("Main Hand", item.get_id())
                    player.race.set_body_slot("Off Hand", item.get_id())
                    print("You wield the {0} in both hands.".format(item.get_name()))
                    player.inventory.remove(item.get_id())
                    return                else:
                    print("You need two free hands to wield the {0}.".format(item.get_name()))
                    return            elif player.race.get_body_slot("Main Hand") != 0:
                if "Two Weapon Fighting" not in player.get_feats():
                    print("You cannot dual wield.")
                    return                elif player.race.get_body_slot("Off Hand") != 0:
                    offhanditem = self.item_repository.get_by_id(player.race.get_body_slot("Off Hand"))
                    print("You are already wielding {0} in your off hand.".format(offhanditem.get_name()))
                    return                else:
                    player.race.set_body_slot("Off Hand", item.get_id())
                    print("You wield the {0} in your off hand.".format(item.get_name()))
                    player.inventory.remove(item.get_id())
            else:
                player.race.set_body_slot("Main Hand", item.get_id())
                print("You wield the {0} in your main hand.".format(item.get_name()))
                player.inventory.remove(item.get_id())
        if itemname in item.get_keywords():
            #Is it a weapon            if item.get_type() != "Weapon":
                print("That cannot be wielded.")
                return            #Does your class allow you to wield this?            elif item.get_weapon_type() not in player.guild.get_allowed_weapon_types():
                print("{0}s are not allowed to wield {1}s".format(player.guild.get_name(), item.get_weapon_type()))
                return            #Druids can't wield metal objects            elif player.guild.get_name() == "Druid" and item.get_material() in ["iron", "steel", "copper", "bronze"]:
                print("Druids may not wield weapons made of metal.")
                return            elif item.get_handed() == 2:
                if player.race.get_body_slot("Main Hand")==0 and player.race.get_body_slot("Off Hand") == 0:
                    player.race.set_body_slot("Main Hand", item.get_id())
                    player.race.set_body_slot("Off Hand", item.get_id())
                    print("You wield the {0} in both hands.".format(item.get_name()))
                    player.inventory.remove(item.get_id())
                    return                else:
                    print("You need two free hands to wield the {0}.".format(item.get_name()))
                    return            elif player.race.get_body_slot("Main Hand") != 0:
                if "Two Weapon Fighting" not in player.get_feats():
                    print("You cannot dual wield.")
                    return                elif player.race.get_body_slot("Off Hand") != 0:
                    offhanditem = self.item_repository.get_by_id(player.race.get_body_slot("Off Hand"))
                    print("You are already wielding {0} in your off hand.".format(offhanditem.get_name()))
                    return                else:
                    player.race.set_body_slot("Off Hand", item.get_id())
                    print("You wield the {0} in your off hand.".format(item.get_name()))
                    player.inventory.remove(item.get_id())
            else:
                player.race.set_body_slot("Main Hand", item.get_id())
                print("You wield the {0} in your main hand.".format(item.get_name()))
                player.inventory.remove(item.get_id())

Saturday, January 14, 2017

Fighting the Burnout

It can be incredibly easy to burn out.  So far, I've been learning programming since the beginning of the year, going on 2 or 3 weeks, and I'm still going strong.  After a six hour stint in the library though, I start to run out of gas.  I get home, put on Netflix, and my brain feels like mush.  I never realized that programming had such a high cognitive load and took so much concentration and mental energy to do.  I'm loving it so far!  Let's get to what I've been learning.

Today I started learning SQL, which stands for "Structured Query Language."  It's a language used for handling databases, grabbing information, changing them, etc.  I asked some of my (apparently) many programming friends if it was useful.  The answers I got were:

"Meh?"

"I use it at my job sometimes.  I mostly Google what I need."

"If I didn't use it, a meteor might destroy myself and everyone at work.  LEARN IT NOW!"

"The sequel to most movies is usually terrible."

So, given the rave reviews, I decided to start learning it so that I wouldn't be ignorant of something that later on down the line I might find useful.  I'm one of those people where I think today was a good day if I go to bed slightly less ignorant than when I woke up.  So, I fired up Code Academy and started doing SQL.  When I think databases, I think of vast expanses of impenetrable numbers, like the matrix.

Instead, I found out SQL is extremely accessible and easy to understand.  I started doing some of the Code Academy problems, and at one point, it asked me to get all the movies who's IMDB rating is 8 or above.  Without even looking at the helper screen (Code Academy tends to hold your hand), I just typed in:

SELECT id FROM movies
WHERE imdb_rating >=8;

What shocked me was this was CORRECT. I started just laughing at my keyboard.  Without any coaching you can just GUESS what the syntax is!  My goal is to finish Code Academy tonight and then move on to more complicated stuff so I can feel like I have a handle with the language.