Open Side Menu Go to the Top
Register
Best Practices of Code Organization Best Practices of Code Organization

06-09-2017 , 02:26 PM
I'm going to be teaching an introductory programming course for math majors. The primary goal is giving them basic tools and exposure to programming as a tool, and then to give them practical problem-solving experience taking inspiration from Project Euler: https://projecteuler.net/

I'm intending to use a somewhat hackish approach. I don't expect any of these students to go on to do any programming at any sort of professional level, and my intention is to give them the background and freedom to explore rather than trying to set them up for specific future things that maybe have to deal with some of the deeper issues of CS (memory management stuff, for example).

Another reason that I'm doing it that way is because that's how I learned to program. I've never taken a formal course in programming. I grew up playing around in BASIC and got some programming experience as an intern at a lab writing some particle simulation stuff in Fortran. I've since learned Python, R, and C++ (and dabbled in javascript, but never really liked it), but mainly use Python (mathematicians seem to be very favorable towards it if they're not using Matlab/Mathematica).

But I recognize that this background gives me a hole in my understanding from a practical point of view for dealing with specific aspects of coding, and I'd like to try to fill in some of those gaps.

I've heard that good code is actually a bunch of short lines of codes that call functions that do specific tasks (or something like that). My code usually ends up being a bunch of long chunks of stuff that are in the main part of the code and only using functions if there's something that I need to do multiple times from multiple places. But that often leaves me with huge blocks of code that make things a bit harder to follow.

One thing that I want to have as a project for the students to work on is a simple little turtle racing "simulation". I've included a simple code below so you can see what I mean. My intention is to give them this code (or something like it) and then ask them to try to add different types of components. Maybe a wagering system (so you place bets before the race starts) or maybe make an oval track, or whatever. I just want them to have an idea and then try to implement it so that they can have some of that general problem solving coding experience.

I'm crossing my fingers on this next part -- If multiple students come up with different things, I'd want to try merge their ideas together. And that's where having a better idea of good programming practices starts to come in. If you take two first semester students' work and try to merge them, it's almost certainly not going to work, even if they've started from the same baseline code. They will make changes here and there and there's just no way of easily bringing that together.

So what's a good way to approach this? I'm open to ideas on both a practical and pedagogical front.

Code:
import random
import turtle
import time

screen = turtle.Screen()

track = turtle.Turtle()
track.hideturtle()
track.pensize(3)
track.speed(0)
track.penup()

track.goto(-250,-100)
track.pendown()
track.goto(250,-100)
track.goto(250,-50)
track.goto(-250,-50)
track.goto(-250,0)
track.goto(250,0)
track.goto(250,50)
track.goto(-250,50)
track.goto(-250,100)
track.goto(250,100)
track.goto(250,-100)
track.goto(-250,-100)
track.goto(-250,100)
track.penup()

track.goto(0,150)
track.write('Turtle Race!', font=("Arial", 14, "normal"), align='center')


P1 = turtle.Turtle()
P1.penup()
P1.shape('turtle')
P1.color('red')
P1.speed(0)
P1.goto(-268,75)

P2 = turtle.Turtle()
P2.penup()
P2.shape('turtle')
P2.color('blue')
P2.speed(0)
P2.goto(-268,25)

P3 = turtle.Turtle()
P3.penup()
P3.shape('turtle')
P3.color('orange')
P3.speed(0)
P3.goto(-268,-25)

P4 = turtle.Turtle()
P4.penup()
P4.shape('turtle')
P4.color('purple')
P4.speed(0)
P4.goto(-268,-75)

P1x = -268
P2x = -268
P3x = -268
P4x = -268

track.goto(0,125)
track.write('Ready...         ', font=("Arial", 14, "normal"), align='center')
time.sleep(random.randint(2,5))
track.write('                GO!', font=("Arial", 14, "normal"), align='center')

done = 0 
while done == 0:
    P1x = P1x + random.randint(3,10)
    P2x = P2x + random.randint(3,10)
    P3x = P3x + random.randint(3,10)
    P4x = P4x + random.randint(3,10)

    P1.setx(P1x)
    P2.setx(P2x)
    P3.setx(P3x)
    P4.setx(P4x)

    if P1x >= 232 or P2x >= 232 or P3x >= 232 or P4x >= 232:
        done = 1
Best Practices of Code Organization Quote
06-09-2017 , 02:55 PM
I would focus on teaching them procedural programming. I don't think you get a lot of bang for you buck teaching OOP to math students who might never take another CS course.

Aside from that, I recommend taking a look at the Berkeley CS61A textbook and MIT OCW 6.00SC Assignments for ideas. Both are Python courses. The CS61A textbook should have a lot of content that is math-related while still being appropriate for beginners.
Best Practices of Code Organization Quote
06-09-2017 , 05:51 PM
I'm newer to programming but ideas that seems to stick with me:

1. Design simplicity is of the upmost importance (i.e. really simple code that can be reused for multiple purposes and reused in later code ).

2. Code should avoid state as much as possible and when state is necessary code should return predictable and reliable results.
Best Practices of Code Organization Quote
06-09-2017 , 10:06 PM
Quote:
Originally Posted by Jeff W
I would focus on teaching them procedural programming. I don't think you get a lot of bang for you buck teaching OOP to math students who might never take another CS course.
The vast majority of my programming experiences are with procedural programming, so a lot of it will have that feel.

Even as I'm thinking about this Turtle racing thing, the structure that comes to mind is how I would have done it back in BASIC, which is to create a subroutine that draws the track, and then a subroutine for the wagering system, and so forth. I'm not even sure what an object-oriented approach to the program might be.

I think I'm saying what I mean to say here. I could be wrong.

Quote:
Aside from that, I recommend taking a look at the Berkeley CS61A textbook and MIT OCW 6.00SC Assignments for ideas. Both are Python courses. The CS61A textbook should have a lot of content that is math-related while still being appropriate for beginners.
Thanks for the links. I'll check them out.
Best Practices of Code Organization Quote
06-09-2017 , 10:06 PM
Quote:
Originally Posted by just_grindin
2. Code should avoid state as much as possible and when state is necessary code should return predictable and reliable results.
I don't understand what "avoid state" means.
Best Practices of Code Organization Quote
06-10-2017 , 04:27 AM
Quote:
Originally Posted by Aaron W.
I don't understand what "avoid state" means.
I think he means avoid side effects.
Best Practices of Code Organization Quote
06-10-2017 , 06:28 AM
Quote:
Originally Posted by Aaron W.
I don't understand what "avoid state" means.
This is frequent advice in LISP/Scheme (lambda programming) where it's all recursion except for when you use state (assignment statements keeping a state in memory).
Best Practices of Code Organization Quote
06-10-2017 , 07:09 AM
Best way I think to address your post it have this code "evolve" so I would add some brief comments at key points. I will make an attempt.

Code:
import random.            #turtle movement
import turtle             #turtle object
import time               #used for a delay

#for displaying the race
screen = turtle.Screen()

#creare the track the turtles run on
track = turtle.Turtle()
track.hideturtle()
track.pensize(3)
track.speed(0)
track.penup()

track.goto(-250,-100)
track.pendown()
track.goto(250,-100)
track.goto(250,-50)
track.goto(-250,-50)
track.goto(-250,0)
track.goto(250,0)
track.goto(250,50)
track.goto(-250,50)
track.goto(-250,100)
track.goto(250,100)
track.goto(250,-100)
track.goto(-250,-100)
track.goto(-250,100)
track.penup()

track.goto(0,150)
track.write('Turtle Race!', font=("Arial", 14, "normal"), align='center')


#Create race competitors
P1 = turtle.Turtle()
P1.penup()
P1.shape('turtle')
P1.color('red')
P1.speed(0)
P1.goto(-268,75)

P2 = turtle.Turtle()
P2.penup()
P2.shape('turtle')
P2.color('blue')
P2.speed(0)
P2.goto(-268,25)

P3 = turtle.Turtle()
P3.penup()
P3.shape('turtle')
P3.color('orange')
P3.speed(0)
P3.goto(-268,-25)

P4 = turtle.Turtle()
P4.penup()
P4.shape('turtle')
P4.color('purple')
P4.speed(0)
P4.goto(-268,-75)

#starting line
P1x = -268
P2x = -268
P3x = -268
P4x = -268

#get ready to run the race
track.goto(0,125)
track.write('Ready...         ', font=("Arial", 14, "normal"), align='center')
time.sleep(random.randint(2,5))
track.write('                GO!', font=("Arial", 14, "normal"), align='center')

#start the race
done = 0 

while done == 0:
    #competitors move
    P1x = P1x + random.randint(3,10)
    P2x = P2x + random.randint(3,10)
    P3x = P3x + random.randint(3,10)
    P4x = P4x + random.randint(3,10)

    P1.setx(P1x)
    P2.setx(P2x)
    P3.setx(P3x)
    P4.setx(P4x)

    #is the race over
    if P1x >= 232 or P2x >= 232 or P3x >= 232 or P4x >= 232:
        done = 1
One thing that you want to consider is creating a function that runs the race with 2 to N competitors with N having an upper bound.
Best Practices of Code Organization Quote
06-10-2017 , 08:21 AM
Regarding the merging.

You could divide the class in groups or establish some kind of hierarchy
Each student will do their own code but also share with each other and talk what works and what doesn't and perhaps come with a draft then each will code and try different things and then they merge. Now they have turtle_race vs 1 and everyone would continue to develop that.

Finally those drafts from groups would be looked at and merged or which level of merging works for you.

Watched some talks regarding LINUX development and how open source community works/ people take from each other ideas and what works. Like Linus says everyone trusts really a few people and they trusts some folks he would listen and they trust some others who they would take code from etc,. Linux community as I understand have a strict rules of coding practice.

I agree that it is good that you try to explain them what good code looks like but since you are not expecting them to move to software development I would say it is as important that what ever the rules are(may not be the best ones) that they are followed.
There are good coding practises but it is important as well what is good coding practise for your group.

If you want to merge perhaps make sure that code is kept simple and one function does one thing and does it well and functions more or less independently where possible of other functions on their code. That way it is easier to merge.

Others in this forum who actually work on software development and see daily how tens/hundreds of developers work on their code and merge may have some good ideas.

I wouldn't try to merge from 50 code samples, let them collaborate and find what works and you would be more of a maintainer. Collaborating with others would be good lesson from them as well rather than people just working on their code and there would be constant merging rather than one just at the end and what people/groups think are the best ideas /best 'code' resulting to the best end product (or end product the group thinks is best). Obviously it depends what is the final task and complexity and if you want to grade each individuals work.

You could have a clear goal for them. For example they are developing a game and idea is to make it work without bugs and be entertaining with a lot of options so they have an idea what they should aim for and meet the expectations without giving too strict guidelines (no need to go for longs list of user requirements

Last edited by vento; 06-10-2017 at 08:50 AM.
Best Practices of Code Organization Quote
06-10-2017 , 08:25 AM
Quote:
Originally Posted by Aaron W.
I don't understand what "avoid state" means.
When possible, one should avoid storing stateful information. Some exceptions would be:

1. Storing data that cannot be redirived by another method (i.e. direct user input as one example).

2. Storing state helps to improve execution time or improves memory use.

Gaming_mouse has mentioned the paper Out of the Tar Pit and highly recommend it as a read. It addresses all of the above in greater detail.

I will admit this may be beyond the scope of your class but I think both pushing design simplicity and state conciousness is a great lesson for all interested in programming.
Best Practices of Code Organization Quote
06-10-2017 , 11:33 AM
Quote:
Originally Posted by adios
Best way I think to address your post it have this code "evolve" so I would add some brief comments at key points. I will make an attempt.
Heh... Part of the assignment I had associated with this chunk of code was to try to figure out what was happening and add comments that describe various chunks of the code.

The idea is basically to give them a starting point and let them tinker. That's one of my underlying themes for the course. Half of it is just learning to try stuff out and see what happens. (Again, very hackish.)

Quote:
One thing that you want to consider is creating a function that runs the race with 2 to N competitors with N having an upper bound.
That would be an interesting extension of the code.
Best Practices of Code Organization Quote
06-10-2017 , 11:37 AM
Quote:
Originally Posted by just_grindin
When possible, one should avoid storing stateful information.
Can you give me an example of something that follows this and something that doesn't? I'm not 100% sure I understand.
Best Practices of Code Organization Quote
06-10-2017 , 12:11 PM
Quote:
Originally Posted by vento
Regarding the merging.

You could divide the class in groups or establish some kind of hierarchy
Each student will do their own code but also share with each other and talk what works and what doesn't and perhaps come with a draft then each will code and try different things and then they merge. Now they have turtle_race vs 1 and everyone would continue to develop that.
This might work. Resetting things periodically so that everyone is on the same page will certainly simplify things as we get deeper.

Quote:
If you want to merge perhaps make sure that code is kept simple and one function does one thing and does it well and functions more or less independently where possible of other functions on their code. That way it is easier to merge.
This is kind of where my mind is at, but I'm having a tough time thinking about how to actually do this. I think I would need to be very careful and intentional about setting up the variables to deal with local/global issues. For example, in the code below, I've moved the track drawing to a separate function.

Code:
def draw_track():
    track = turtle.Turtle()
    track.hideturtle()
    track.pensize(3)
    track.speed(0)
    track.penup()

    track.goto(-250,-100)
    track.pendown()
    track.goto(250,-100)
    track.goto(250,-50)
    track.goto(-250,-50)
    track.goto(-250,0)
    track.goto(250,0)
    track.goto(250,50)
    track.goto(-250,50)
    track.goto(-250,100)
    track.goto(250,100)
    track.goto(250,-100)
    track.goto(-250,-100)
    track.goto(-250,100)
    track.penup()

    track.goto(0,150)
    track.write('Turtle Race!', font=("Arial", 14, "normal"), align='center')
    

import random
import turtle
import time

screen = turtle.Screen()

draw_track()

P1 = turtle.Turtle()
P1.penup()
P1.shape('turtle')
P1.color('red')
P1.speed(0)
P1.goto(-268,75)

P2 = turtle.Turtle()
P2.penup()
P2.shape('turtle')
P2.color('blue')
P2.speed(0)
P2.goto(-268,25)

P3 = turtle.Turtle()
P3.penup()
P3.shape('turtle')
P3.color('orange')
P3.speed(0)
P3.goto(-268,-25)

P4 = turtle.Turtle()
P4.penup()
P4.shape('turtle')
P4.color('purple')
P4.speed(0)
P4.goto(-268,-75)

done = 0
P1x = -268
P2x = -268
P3x = -268
P4x = -268

track.goto(0,125)
track.write('Ready...         ', font=("Arial", 14, "normal"), align='center')
time.sleep(random.randint(2,5))
track.write('                GO!', font=("Arial", 14, "normal"), align='center')
    

while done == 0:
    P1x = P1x + random.randint(3,10)
    P2x = P2x + random.randint(3,10)
    P3x = P3x + random.randint(3,10)
    P4x = P4x + random.randint(3,10)

    P1.setx(P1x)
    P2.setx(P2x)
    P3.setx(P3x)
    P4.setx(P4x)

    if P1x >= 232 or P2x >= 232 or P3x >= 232 or P4x >= 232:
        done = 1
This fails because the track-drawing turtle ended up being a local turtle because it was created inside of the function. In this case, the solution is obvious (create the turtle before the function and just tell everyone that all track-drawing should be done by that turtle).

But as students introduce different things (variables to track the wagering, maybe some information that randomizes turtle racing characteristics so that it's not always a fair race), I'm having problem anticipating how this would be brought together.

Quote:
I wouldn't try to merge from 50 code samples, let them collaborate and find what works and you would be more of a maintainer.
I'm expecting only about 10 in the class, so this part will be fairly easy to manage... I think.

Quote:
Collaborating with others would be good lesson from them as well rather than people just working on their code and there would be constant merging rather than one just at the end and what people/groups think are the best ideas /best 'code' resulting to the best end product (or end product the group thinks is best). Obviously it depends what is the final task and complexity and if you want to grade each individuals work.
I definitely agree with getting them to collaborate (which is part of why I thought this would be a fun project). The end goal of the class is that they have a real coding experience (moving from an initial question/goal and working their way to an answer/completed code).

I'm setting up the class so that in the first few weeks there will be "Find your own tutorials on the internet" for doing some basic things after I've set them up ("Find your own turtle tutorial" is one of them). I'm wanting them to then share their tutorials with each other and see all of the differences in code/coding styles and then figure out how to make them work together.

For example, I've primed them for this sort of thing by giving them two codes. One starts with

Code:
import turtle

screen = turtle.Screen()
and the other starts with

Code:
from turtle import *

screen = Screen()
And I ask them to translate one short code snippet into the other. It's an incredibly basic task, but it's exactly the kind of thing that would cause frustration if they didn't even know that this was something that happened.

Quote:
You could have a clear goal for them. For example they are developing a game and idea is to make it work without bugs and be entertaining with a lot of options so they have an idea what they should aim for and meet the expectations without giving too strict guidelines (no need to go for longs list of user requirements
Since this is a first semester course and my first time teaching it, I'm keeping the baseline goals modest, and hoping that at least a couple students find some intrinsic interest and are willing to take things further. What I don't want to do is set high goals and frustrate everyone in the class because it's asking too much of them too quickly. (I work at a non-selective college, so I can't assume as much background as I might be able to do elsewhere.)
Best Practices of Code Organization Quote
06-10-2017 , 04:55 PM
Quote:
Originally Posted by Aaron W.
Can you give me an example of something that follows this and something that doesn't? I'm not 100% sure I understand.
Sure. Just as a caveat I am teaching myself programming so while I have working theoretical knowledge I haven't yet applied that knowledge to larger coding projects or solutions, so my examples might be contrived or off base in some fashion.

I tend to think of essential state as information that is paramount to completing the goal of your program that is either initial input data or too costly (in terms of computation time or memory use) to derive later from initial input. In your turtle example essential state information would be:

- Starting position of the turtle.
- Position of the finish line.
- Current position of the turtle.
- Turtle velocity
- Graphics initilization.

Each of these is non-existent before execution and cannot be derived from other data (except current position and turtle velocity). Current position and turtle velocity are included because it is probably faster/less stateful to store the current position and velocity of the turtle than it is to compute using other values when it is needed for other parts of code.

One example of state that you would likely not need to store that jumps out from your example:

- Turtle acceleration.

A turtle's acceleration can be derived rather quickly at any time using other information with mathematical operations which should take constant execution time so it's probably easier to apply the execution than it is to store the acceleration of the turtle in memory.

Like I said these examples may be slightly contrived to try and illustrate my points within your turtle example or would be offbase due to my inexperience but I am sharing in good faith without the intent to confuse.

One thing I would also mention is that I don't believe there is anything that precludes carrying these ideas into an object oriented design pattern though some posters have commented this mostly appears in functional programming contexts.

The overall goal is design simplicity and predictable behavior from code execution. Avoiding state when possible is just an easier way of achieving these goals. While objects may necessitate state to some extent (i.e. you will have an object with some state in resident memory), that doesn't mean one cannot avoid using state when it is not needed to make human understanding easier, to circumvent resource limitations or to speed up execution time.
Best Practices of Code Organization Quote
06-10-2017 , 05:53 PM
Disregarding the other topics (oh my, no one knows what state is)...

Turtle is a great place to have math students work on an absolute classic of math: the drunken walk. It would let them see how math turns into simulation.

You wouldn't need much more than a single loop and I'm guessing it would take about 10 LOC. What you have in the OP is just waaaayyyyy too much to be handing someone new to programming. Ouch.

Last edited by daveT; 06-10-2017 at 06:00 PM.
Best Practices of Code Organization Quote
06-10-2017 , 07:51 PM
Also ignoring state, not important. Proper procedural programming with each step in the procedure is neatly commented would get full marks in my class. Neatly commented code will encourage not using extraneous variables and lines of code. I'd focus on one or two procedural programs a week, including the pseudo-code for the first few programs, and have four or five different topics to cover, such as:

1. Variable types
2. Input/output
3. Functions
4. Conditionals
5. Loops

And maybe something like recursion with the Fibonacci sequence at the end, which you can do without if there's no time left.

With a little more time, I'd like to go back to variables and add pointers and references and the nitty-gritty about how compilers handle variables. And then hit an entire course on OOP including polymorphism. Realistically though, loops is in my estimation about as far as most students will go and retain the info.
Best Practices of Code Organization Quote
06-10-2017 , 07:54 PM
Quote:
Originally Posted by Jeff W
I would focus on teaching them procedural programming. I don't think you get a lot of bang for you buck teaching OOP to math students who might never take another CS course.
Kind'a agree with this. Also students need to know fundamentals before they can start to be creative. Game programming is not intro level.
Best Practices of Code Organization Quote
06-10-2017 , 08:14 PM
Quote:
Originally Posted by just_grindin
Sure. Just as a caveat I am teaching myself programming so while I have working theoretical knowledge I haven't yet applied that knowledge to larger coding projects or solutions, so my examples might be contrived or off base in some fashion.
I'm probably in a similar boat as you. I appreciate the explanation, and it makes sense.
Best Practices of Code Organization Quote
06-10-2017 , 08:14 PM
Also, you could construct a basic maze game with this, and address state if you have time to return to variables. Advanced students would be able to save the maze in file after re-visiting Input/output, recursion, and state. But, you might not even have time depending on how much time you have and how able the students are at learning programming. Some students are just flat-out not that able, which is why extra credit for a game makes sense.
Best Practices of Code Organization Quote
06-10-2017 , 08:17 PM
Quote:
Originally Posted by daveT
Turtle is a great place to have math students work on an absolute classic of math: the drunken walk. It would let them see how math turns into simulation.
Yes! I've already intended to do both 1D and 2D random walks (on a regular lattice). I'm not sure if I'm going to general 2D random walks.

Quote:
What you have in the OP is just waaaayyyyy too much to be handing someone new to programming. Ouch.
Most of the code is just drawing the track. The actual racing part is super short. This could be me being overly ambitious. I'll keep letting it roll around in my head.
Best Practices of Code Organization Quote
06-10-2017 , 08:20 PM
Quote:
Originally Posted by leavesofliberty
Kind'a agree with this. Also students need to know fundamentals before they can start to be creative. Game programming is not intro level.
I'm not just going to cut them loose and tell them to figure it out on their own. There's definitely going to be a guided process. But I want to use their ideas and go through the hard work of having them talk through the problem-solving process.

I want them to visualize how it will look and then the plan is to take what they imagine and break it down into pieces with them. These are math students, so I want to believe that they already have some mental categories/logical processes already lined up for me to tap into.
Best Practices of Code Organization Quote
06-10-2017 , 08:24 PM
Quote:
Originally Posted by Aaron W.
I'm not just going to cut them loose and tell them to figure it out on their own. There's definitely going to be a guided process. But I want to use their ideas and go through the hard work of having them talk through the problem-solving process.

I want them to visualize how it will look and then the plan is to take what they imagine and break it down into pieces with them. These are math students, so I want to believe that they already have some mental categories/logical processes already lined up for me to tap into.
Well it could work as long as the class is structured with chapters on the fundamentals as it relates to the turtle game. It'd also help if the turtle game was broken into a design document of some kind with some diagrams of the processes so students can look at it meta before digging in.

I'm biased towards C++ myself, but I know schools are doing more Java and Python these days.
Best Practices of Code Organization Quote
06-10-2017 , 08:33 PM
The thing about OOP in an intro course is that you'll run into problems like, "What's a method?" when you really can't explain it without first addressing, "What's a process?" Not saying it's impossible to kill two birds with one stone, but it presents challenges.
Best Practices of Code Organization Quote
06-10-2017 , 08:40 PM
I really appreciate the ideas that are coming forward. It's giving me plenty to think about.
Best Practices of Code Organization Quote
06-10-2017 , 08:47 PM
Quote:
Originally Posted by leavesofliberty
The thing about OOP in an intro course is that you'll run into problems like, "What's a method?" when you really can't explain it without first addressing, "What's a process?" Not saying it's impossible to kill two birds with one stone, but it presents challenges.
unless I am misunderstanding what a process is, this is not true for java or c#.
Best Practices of Code Organization Quote

      
m