Marking Criteria

Software Engineering Large Practical

In today's final lecture, I will talk about how your project will be graded

Slight Disappointment

Proposals

  • Not one student suggested some kind of ranking of something software engineering or Informatics related. Eg.
    • Ranking git repositories by average size of commit
    • Ranking git repositories by amount of profanity
    • Average response rates for issues

Rankings

Proposals

  • A few students have struggled with how to “combine rankings”
  • As if there must be a single ranking
  • I did not specify this
  • I only said that there had to be a ranking
  • Which should be read as “at least one ranking”

Honours Project

Proposals

I forgot to mention that some of you have quite ambitious projects. You can make a start to them here and then possibly self-propose completing the project for your honours project next year. The proposal will be in January so you'll know by then if you want to continue with what you have.

Grading

Software Engineering

  • The bigger picture answer to the question of what you will be graded upon, is your ability to demonstrate your software engineering skills
  • Perhaps, ideally, I'd like to simply grade you on your software engineering skills
  • There are two reasons this is not the case:
    • It's infeasible for me to accurately judge your software engineering ability unless you demonstrate it in some way
    • There will likely be times in the future when demonstrating an ability is more important than attaining it

Grading

Engineering vs Producing

  • Even directly grading your ability to engineer software is a little unsatisfying
  • What commonly matters is your ability to produce software
  • Often, the best way to achieve success in any software project is to avoid developing code

Grading

Engineering vs Producing

Grading

Unfortunately

  • The lesson is: in general try to avoid writing software
  • Unfortunately, for this project you have to demonstrate an an ability to engineer software
  • Of course if you manage to do something like the above, that is still impressive and credit worthy
    • Just make sure you get the credit it is due, by writing about it in your report

Proposals

Cooking

  • Cooking is way more popular than I expected
    • Approximately 8-10 proposals were for some form of recipe collection site
  • To re-iterate, there is a slight risk here that you demonstrate more of an ability to curate a database than to engineer software
  • You may find the above WYSIWYG editor helpful for your needs, but be careful as you will likely end up storing the whole thing as unstructured data

Recipes

Front-end To a Database


@app.route('/')
def show_entries():
    cur = g.db.execute('select id, title, text from entries order by id desc')
    entries = [dict(id=row[0], title=row[1], text=row[2]) for row in cur.fetchall()]
    return render_template('show_entries.html', entries=entries)

Recipes

Front-end To a Database


@app.route('/add', methods=['POST'])
def add_entry():
    if not session.get('logged_in'):
        abort(401)
    g.db.execute('insert into entries (title, text) values (?, ?)',
                 [request.form['title'], request.form['text']])
    g.db.commit()
    flash('New entry was successfully posted')
    return redirect(url_for('show_entries'))

Recipes

Front-end To a Database


<form action="{{ url_for('add_entry') }}" method=post class=add-entry>
      <dl>
        <dt>Title:
        <dd><input type=text size=30 name=title>
        <dt>Text:
        <dd><textarea name=text rows=5 cols=40></textarea>
        <dd><input type=submit value=Share>
      </dl>
    </form>

Recipes

Front-end To a Database


<ul class=entries>
  {% for entry in entries %}
    <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
  {% else %}
    <li><em>Unbelievable.  No entries here so far</em>
  {% endfor %}
  </ul>

Recipes

Add Rankings


@app.route('/add', methods=['POST'])
def add_entry():
    ...
    g.db.execute('insert into entries (upvotes, title, text) values (?, ?, ?)',
                 [0, request.form['title'], request.form['text']])
    ...

When we add an entry give it zero votes

Recipes

Add Rankings


    <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
    <form action="{{ url_for('upvote_entry') }}" method=post class=up-vote>
      <dl>
        
        <dd><input type=submit value=upvote>
      </dl>
    </form>

When we display an entry, we give it an upvote button

Recipes

Add Rankings


@app.route('/upvote', methods=['POST'])
def upvote_entry():
    # Perform a query to get the current number of upvotes:
    upvotes = cur.fetchall....
    g.db.execute('update entries set upvotes=? where id=? values (?, ?, ?)',
                 [upvotes+1, request.form['recipe-id']])
    ...

To upvote we simply execute a database update statement

Recipes

Add Rankings


def show_entries():
    cur = g.db.execute('select id, title, text from entries order by upvotes desc')

When we display entries, order by upvotes

Grading

Demonstrate Software Engineering

  • Recall that the main goal is to demonstrate your ability to engineer good software
  • Software is good if it is both:
    1. working now
    2. maintainable for the future
  • Generally a higher priority on the latter

From the Coursework Handout

  • Use of source code control
  • Documentation, including source comments
  • Testing
  • Maintainable code
  • Your report
  • Early submission

Source Code Control

  • There was a whole lecture devoted to this topic
  • To be clear: the only real requirements are:
    • That you have at least set up a git repository
    • You are making sensible, commits, of one unit worth of work
    • You make reasonable commit messages
    • Your repository is sane:
      • You have not stored generated files in the repository
      • It is generally clean with no uncommited changes
      • You have a ‘.gitignore’ file

Source Code Control

Repository Sanity

  • A specific example:
    • Some of you have created a Python virtual environment
      • That is great
    • Some of you have committed the generated virtual environment files (including all Python standard libraries) to the repository
      • That is not great
    • Do not store generated files in the repository
    • Instead store the (preferably executable) instructions for generating those files
      • You do not store class files, but a build script

Source Code Control

Not Directly Graded

  • Feature branches: these are not required, but exist for a reason:
    • They make your life easier, and hence you may well produce better code as a result
  • Sub-modules: Allow you to track changes in a third-party library, and generally keep that separate from your code:
    • Third-party libraries for your back-end should generally be installed on the server and not commited to your repository
    • Front-end, usually Javascript, often need to be stored in the repository to be made available for the client
      • Not always the case, eg. public mirrors of common Javascript libraries, such as JQuery exist

Source Code Control

Proposals: Commit messages

  • Do not feel limited to single line commit messages
  • If you perform a git commit, without the -m, it will open up an editor and you can type in as much as you like
  • Normally I suggest that if you write more than one paragraph and you are quite possibly recording something that you maybe wish to record elsewhere
  • But many of you seem to be sticking religiously to single sentence commits messages as if there were some kind of limit

Documentation

Developer Documentation

  • Many large projects require extensive documentation
  • Web sites on the other hand, hopefully, do not require user documentation separate from the web site itself
  • The documentation you write, is for other developers
  • This means, anything someone would need to take over development from you
  • The only means that you can individually reduce your “bus factor”

Documentation

Developer Documentation

  • This includes:
    • Compilation instructions
    • Running Instructions
    • Testing Instructions
    • Debugging instructions
    • Deployment instruction if appropriate
    • A starting point to help the developer orientate themselves
      • Eg. “The main logic of the web application is in 'blah.code' routes the requests to specific functions”
      • Eg. “If you wish to change only the look of the website the CSS files are found in ...”

Documentation

Automation

  • Anything that can be automated, should be automated
  • Rather than have long lists of commands developers need to input provide a script to do them all
  • If that script may need to be parameterised, so be it:
    • Either with script command-line arguments (in bash these are accessible with $1, $2 ...)
    • Or editing the script in which case the variables to edit should be clearly marked at the top

Documentation

Automation

Edit the script

$INSTALL_DIR=""
$PATH_TO_DEPX=""
if [ "${INSTALL_DIR}" == '' ]; then
        echo "You need to set the installation directory."
        exit 1;
fi
...

Documentation

Source Code Comments

  • Repeating the advice from earlier:
    • Generally you are not writing what the code does but why it does it
  • Generally held view that “code should be self-documenting”:
    • That's fine, I agree, but often it is non-obvious how to make it self-documenting
    • It may even be impossible, for example if works around a feature of an external library

Documentation

Do I need a comment?


// Choose a delay from the exponential distribution given the rate
dice = generator.nextDouble();
delay = 1.0 - (1.0/rate * Math.log(dice));
System.out.println (delay);

double calculate_exponential_delay(double rate, Random generator){
    dice = generator.nextDouble();
    delay = 1.0 - (1.0/rate * Math.log(dice));
    return delay;
}
...
System.out.println(calculate_exponential_delay(rate, generator)

Documentation

Do I need a comment?


// Choose a delay from the exponential distribution given the rate
dice = generator.nextDouble();
delay = 1.0 - (1.0/rate * Math.log(dice));
System.out.println (delay);

System.out.println(calculate_exponential_delay(rate, generator)

Documentation

Do I need a comment?


// The X library indexes from 1, when we created our database we start the
// unique identifiers off at 0. Arguably we should change that and we
// would not need the "+ 1" here, but we need to think about where else we
// use the unique identifiers as indices first
Third_party.some_method(entries, index + 1);

Testing

Unnecessary Qualification

  • English has a habit of unnecessary qualification, eg.
    1. People in glass houses should not throw stones
      • How about everyone refrain from stone throwing?

Testing

Unnecessary Qualification

  • English has a habit of unnecessary qualification, eg.
    1. People using a dynamically typed language should comprehensively test their source code
      • How about everyone comprehensively test their source code?
  • However, reading your proposals:

Testing

Proposals

Testing

Proposals

Testing

Proposals

  • Dynamically typed languages have become much more popular in the last 10-20 years
  • At least in part this is because an increased emphasis on testing has reduced the benefits of static typing
  • So I can turn my sentence around:
    • “People who do not comprehensively test should use a statically typed language”
    • This is not an unnecessary qualification because I'm not suggesting that everyone should use a statically typed language

Testing

Proposals Disappointment

  • Very few proposals mentioned anything about testing
  • Even fewer asked anything about testing
  • I'm aware that testing seems like an extra chore
  • Think of it as reducing the amount of manual work you do

Testing

Choreness

  • I believe testing is seen as so laborious because your first exposure is to testing is of unit testing micro-methods
  • When your method returns the maximum integer in a list, I can see why you do not appreciate any great need to test

Testing

Large Programs

  • Parts of a large program often interact with each other in much more complex ways
  • Tests under these circumstances are much more fruitful, you are making sure that changes to one part of the program do not adversely affect some other part

Testing

Simple Example

  • You have some database for storing the persistant state of your web application
  • You have some schema, some tables with columns
  • Suppose you wish to add some new functionality:
    • This requires that you make a change to the database schema
    • Perhaps you have to add a column
    • How can you be sure that your change of the schema has not broken some functionality?

Testing

Simple Example

  • You have three possible strategies:
    1. Make the change and re-run your comprehensive test suite
      • Fix anything that was broken and repeat
    2. Make the change and manually test out all functionality, preferably in different circumstances
      • boring, repetitive, error-prone and time-consuming
    3. Make the change in a way that is very unlikely to break existing functionality, such as adding a new table
      • Do this often enough and it is an excellent way to make an unmaintainable mess

Recipes Example

Original schema:

drop table if exists entries;
create table entries (
  id integer primary key autoincrement,
  title text not null,
  text text not null
);

Testing

Recipes Example

Which we update with ‘upvotes’

drop table if exists entries;
create table entries (
  id integer primary key autoincrement,
  title text not null,
  text text not null,
  upvotes integer
);

Testing

Recipes Example

Our original code to add to the database is now wrong

@app.route('/add', methods=['POST'])
def add_entry():
    if not session.get('logged_in'):
        abort(401)
    g.db.execute('insert into entries (title, text) values (?, ?)',
                 [request.form['title'], request.form['text']])
    g.db.commit()
    flash('New entry was successfully posted')
    return redirect(url_for('show_entries'))

When you have several operations on the same tables you have to re-check all of the operations that were previously working

Testing

Automate Test Database Creation

  • Create some test databases
  • But make sure you write some code to automatically create them
  • A common error is to use your application to create some test databases
  • But this means if you update the database schema you will have to re-use your application to create them again with the new schema
  • Much better if you only have to update a line or two in code to automatically create them

Maintainable Code

  • Software is generally deployed in an ever changing environment:
    • The requirements change because the world has changed
      • New laws
      • New competing/complimentary products
      • New hardware
      • New uses
  • For this reason software must be frequently updated/fixed/modified/enhanced
  • This is difficult if your software is not maintainable

Maintainable Code

Code Structure

  • Generally have you got a nice separation of concerns
  • You have some processing of the data, could you use that outwith your application?
  • Often the solution involving the least amount of code is the best
    • This does not mean using fewer characters, but fewer constructs
    • A common error is over-using classes

Maintainable Code

Idiomatic Code

  • You have chosen your language(s) of choice
  • You should use it appropriately, this is, admittedly, a little vaguely defined

Maintainable Code

Idiomatic Code

  • For example, suppose you are using Python (popular in the proposals):
    • Not using getters and setters (Python has ‘properties’ for this purpose)
    • Using iterators, see below:
    • Using with syntax
  • More generally, do not use Strings and Integers for all kinds of values that could have more specific and appropriate types

for x in xs:
    ...

better than:

for i in range(length(xs)):
    x = xs[i]

Maintainable Code

Automate Everything

  • The best way to make sure that someone else can maintain your code is to automate as much as possible
  • If you have a single command to compile and run your web application they can at least run it simply
  • If you have a single command to run your entire test suite, they can easily modify code and examine the effects

Your Report

  • As discussed last week
  • This is your opportunity to enhance the demonstration of your software engineering abilities
  • This includes how readable it is
    • If cannot understand it, you will not receive much credit for it, nor whatever you are trying to convey
    • This is a common situation, if you cannot describe what you have done and why, you likely will not receive much credit for it, whatever form credit may take

Early Submission

  • Early submission deadline: Thursday 11th December at 4pm
  • If you submit after the early submission deadline the highest grade you can achieve is 90

Interactions

  • Use of source code control
  • Documentation, including source comments
  • Testing
  • Maintainable code
  • Your report
  • Early submission

Interactions

  • For example testing is a special case of automate everything under maintainable code
  • Documentation is a special case of readable code under maintainable code

Summary

  • How easily could someone else continue develop of your application?
  • If the answer is, “not easily” then you are failing
  • Use your report to demonstrate that you are not failing
    • Or that you have at least learnt how not to fail
  • Note: I've not said much about actually producing some cool/good product
    • If you produce something good but in a way that is entirely unsustainable you likely won't recieve a very high mark
    • Similarly some proposals are of quite questionable value, but done in a very principled manner could well achieve a very high mark

Summary

  • I do not wish to scare you
  • Relax, if you spend enough time on it you will almost certainly get at the very least a reasonable mark
    • Remember what I said about failure

Any Questions