Here are some coding tips, and details about grading programming assignments.
Give me six hours to chop down a tree,
and I will spend the first four sharpening the ax.
- Abraham Lincoln
This is true in coding as in chopping.
Resist the urge to start coding right away.
Spend 90% of your time preparing, and 10% coding, and you will spend
less net time!
Attempt to spend 10% preparing, and 90% coding,
then you may end up never understanding, and frustrating yourself,
wasting your time
If I want to learn a new protocol, language, etc.,
then I spend 90% of the allotted time on learning (studying),
and 10% on producing the product (the assignment).
Time pressure can get to one’s head, encouraging the opposite,
trying to complete the product first, before learning.
Resist that urge!
The time to complete each of these typically takes 2-5 hours for a
top-30% grade student,
about 10-25 minutes for myself, and maybe 30 min-1 hour for my
TAs.
Spend time on preparation not production!
Spend time enjoying learning the material,
not anxiously getting through through the assignment!
After all, programming is mostly thinking:
https:/agileotter.blogspot.com/2014/09/programming-is-mostly-thinking.html
An apprentice carpenter may want only a hammer and saw,
but a master craftsman employs many precision tools.
Computer programming likewise requires sophisticated tools,
to cope with the complexity of real applications,
and only practice with these tools will build skill in their use.
~ Robert L. Kruse, Data Structures and Program Design
All of the functions in files we provide must be completed as
directed by the comments.
Changes to function names or parameters may mean we cannot properly
grade that function,
and you may not receive any points for it.
Do not edit any header files unless we say so explicitly!
If there is any doubt, do not edit the header files.
Carefully read the comments of each member function,
noting both return values and output statements (they are not the
same!).
Develop your classes and/or functions one at a time, starting from the
simplest modules.
Move to the next function only after the previous one has been
tested.
Trying to code a whole class, and then remove the bugs afterwards,
will likely prove to be too big a task.
It may help to build your own simple test cases.
Print plenty of status messages to track the progress of your
algorithm
(and remember to comment them out before submission).
Using Windows or online web-based compilers can come back to bite
you,
so test on the desired platform (class container).
Stick to local IDEs that are Linux compatible, for example within the
class VM.
Use the supported language and version (e.g., python3
not
python2
, gcc-c++
not MS-visual-studio C++)
Diff tools are helpful for comparing two folders of files,
or comparing two of your output files.
Compare your output to any given sample output to make sure they are the
same,
including all newlines and spaces, via bash:
./yourcode.whatever <sample_input.txt >your_output.txt
# or for two-column format (easier to see):
diff -y --color sample_output.txt your_output.txt
# or using vim:
vim -d sample_output.txt your_output.txt
# or using git-delta
delta sample_output.txt your_output.txt
# or in a GUI:
meld sample_output.txt your_output.txt
Points / scoring
Environment
It is expected that all of your work runs correctly,
in the specified Linux environment we are working with in class,
in the exact manner we specify in the assignment description.
If you were contracted to write code for a job, and it ran on your
computer,
but not your employer’s as they needed, your work would be considered a
failure.
In that light, you are also responsible for submitting all text and
source files,
such that they are compatible with our specified environment,
e.g., encoded UTF-8, Unix delimited, etc.
Test cases
The test cases we will run for grading may be more extensive than any
fixed sample input we give you,
for example by using a randomized unit test (which you can still
see).
It is possible, even likely, that if your program seemingly works
perfectly,
for example with an input file: sample_input.txt
,
that it may not work perfectly with our grading scripts or random unit
tests;
this is fair and reasonable challenge,
since we describe the bounds of performance required generally;
when coding in the real world for a job,
you will be expected to anticipate edge cases, weird behavior, larger
than expected data-sets, etc.
Practicing this can help you train one of the more important skills of
an industry programmer.
You should manually try some failing test cases yourself, that have
input and output,
perhaps different or which exemplify some edge case.
Style
Good programmers don’t always have good comments,
but they almost always have clean, consistent, readable code style and
formatting…
Take pride in your code!
If your assignment is in Python, Bash, C++/C, or Rust,
we grade your code using auto-formatters like:
black
, shfmt
, clang-format
, or
rustfmt
respectively.
Normalization
After grading any given assignment,
if that assignment appeared to be too difficult for the class,
I may choose to normalize to the top student’s performance
(the student with the highest point rank will get a 100% / A).
This can, by definition, only help your grade, but not hurt it.
I won’t ever do the opposite (lower grades).
Precision unit testing
In the real world, and in industry, most of code is tested by
code.
When a networked program, or an operating systems program, or a web
program,,
does not have perfectly spaced output, it does not work, at
all...
Computers are not flexible; they are rigid, and they need babying!
Code that is merely run-able (playable, produces output, etc.)
is NOT correct code!
Getting workable code is the first half of the assignment.
Getting your workable code to be correct in all the remaining needed
details,
is the second half of the assignment.
Files should be in UTF-8, Unix/Linux delimited
(which if you used the class Linux environment,
without copy-pasting from your host OS, you should be fine).
Make sure to download and use the sample input and output text files we
gave,
not the text copied into a new text file you made.
Your program compiles and runs in the specified Linux environment
Check that file names match requirements and/or have not been
changed
Are you testing your execution with unchanged header files if
specified
(by checking the file in an old commit),
in case you edited for debugging purposes?
You should almost never edit the header files!
Did you check the program with more input / output test cases than we
gave you,
by generating your own?
Did you check that your functions all have the right inputs and
outputs,
even if they also have outputs to the screen?
Did you push your latest commits, and check you can see them
online,
in the Gitlab git-classes interface?
What is “correct code”?
These are operationally enforced in grade.sh
:
ClassroomCode.html
Bash is standard.
Some other shells like fish are nice, and those like nushell are
innovative.
All bash code for my classes must be auto-formatted by
shfmt
with the following arguments.
Pre-check and fix warnings where needed:
$ shellcheck yourscript.sh
Pre-format
$ shfmt -i 4 yourscript.sh
Run code as:
$ bash yourscript.sh
without the need for a shebang, or
$ . yourscript.sh
or
$ ./yourscript.sh
where this is at the top of your file:
#!/bin/bash
actually specifies un-ambiguously the use of bash, and the binary
location. This is the one you should use.
#!/usr/bin/env bash
specifies ambiguously the use of bash, but not the binary location, thus
opening a security vulnerability; env
was not intended for
this purpose, and it’s use here comes with a number of concrete
disadvantages.
#!/bin/sh
is the system’s default shell, and is ambiguous. This is like saying (by
analogy), I scripted this, maybe in python2, maybe python3, or maybe
even perl…and you’re supposed to guess blindly. It sometimes means a
POSIX compatible shell, but not always.
Debug your code:
bash -x yourscript.sh args if any
or
bashdb yourscript.sh args if any
All code for my classes must by type-hinted (Python 3.6+); this is
enforced by mypy (below).
All code for my classes must be auto-formatted by black.
Pre-check your code, and fix all warnings:
$ mypy --strict --disallow-any-explicit myscript.py
Pre-format your code:
$ black myscript.py
Run:
$ python3 myscript.py
or
$ ipython3 myscript.py
Put this at the top of your scripts:
#!/usr/bin/python3
not this:
#!/usr/bin/python
#!/usr/bin/env python3
etc…
I have also built a customized call-graph and control-flow-graph
generator for python scripts. In the class VM, you can use it as
follows:
$ py2cfg mycode.py
The ipython3 interpreter and python3 interpreter do some things differently:
Debug your code by stepping through it:
$ pudb3 mycode.py
or
$ pudb3 mycode.py arg1 arg2 argn
We use C++ 11 and 14+ features.
If you are using an old computer (campus machines),
then you may need to specify a higher version: -std=c++14
or -std=c++11
If you are using the class VM or container, then you do not need to
include version options at compile time.
All code for my classes must be auto-formatted by clang-format using the
following arguments.
Pre-check with:
$ cppcheck yourcode.cpp
or more specifically:
$ cppcheck --enable=all --language=c++ ./*.cpp ./*.h ./*.hpp
Pre-format with:
$ clang-format.py -i --style=Microsoft ./*.cpp ./*.h ./*.hpp
Compile with debug flags:
$ g++ -g file1.cpp fileN.cpp -std=c++14
Compile with extra nagging (a good thing):
g++ -g -Wall -Wextra -Wpedantic -pedantic-errors *.cpp -o yourbinexe
To run:
./a.out
For example, run with:
$ ./a.out
or
$ ./a.out <"sample_input.txt"
or
$ ./a.out <"sample_input.txt" >"your_output.txt"
Check for memory leaks with:
$ valgrind ./a.out <"sample_input_if_exists.txt"
or, for example:
$ valgrind --leak-check=full ./a.out <"sample_input_if_exists.txt"
Debug your code:
using cgdb
$ cgdb ./a.out
(gdb) start
or
(gdb) start <stdinfile >stdoutfile
(gdb) start arg1 arg2 argn <stdinfile >stdoutfile
or use gdb
$ gdb ./a.out
(gdb) layout next to show code
(gdb) start
or
(gdb) start arg1 arg2 argn <stdinfile >stdoutfile
A breath of fresh air:
cargo run