Tuesday, 18 January 2022

A Philosophy of Software Design - Chapter 1

 A Philosophy of Software Design is it's author's attempt to teach an often neglected core skill in software development: How to design and create high quality software. This is not done in the way it is often attempted, where a method of programming like OOP is explained and codified and good practices are listed. Rather the book attempts to explore and explain the principles that underlie these good practices so that the reader can then apply them to other problems they will encounter day to day.

The author is John Ousterhout, who currently teaches the first class on Software Design at Stanford University. In the preface he talks about how Software Design is both a fairly static subject in academia and not taught enough and that the book contains both lessons learned during his own extensive code writing career and the classes he has taught at Stanford University.

Chapter One: Introduction

The first chapter describes complexity as the biggest limitation in writing programs. The larger and more interconnected the program is the larger the cognitive load of adding to it becomes. There are two ways of managing complexity: First by simplifying the code, and second by hiding it inside an encapsulation (called a module) like a function or class. 

Unlike traditional design work code is highly malleable, this allows the designing of the program to be an ongoing iterative part of programming. The contrast between Waterfall and Agile is noted and should be familiar to any programmer out there, but the book set reducing complexity as one of if not the most important goal of software design.

The book focusses mostly on describing complexity and its solutions at a very high level. Unlike most programming books there is little actual code printed and very few images. Instead the focus is on more narrative examples rather than the nitty-gritty written code.

Book Reviews

PS: 2nd Edition

I'm reading the first edition of the book released in 2018, the second edition has reworked chapter 6, added some sections comparing and contrasting with Clean Code and added a new chapter. Luckily these sections have been released for free here as a sort of errata to the first edition.

Monday, 3 January 2022

Planning the first sprint part 1: What are we making?

Sprints in the Solo Project are split up by feature, where the sprint is finished when the feature is implemented. So what is the feature to be implemented in the first?

The core purpose of Omnihedron is selecting random items from a user-defined list, where the randomness is generated via virtual dice rolls. As such the first requirement is the ability to roll dice to generate random (or rather pseudo-random) results, seeing as the other features rely on this functionality.

Feature: The user can roll dice. ⬅ A good feature, but somewhat vague and unclear.

 There already exists structured notation for describing dice-rolls that is widely used by roleplaying games and roleplaying communities: Wikipedia: Dice Notation, as well as programming libraries able to evaluate and execute dice rolls. From both a user and developer point of view it makes sense to implement such existing familiarity and tools into Omnihedron.

Feature: The user can make dice rolls described via dice notation. ⬅ The use of dice notation can be argued to be a implementation detail, but seeing as it is user facing I'll allow it.

What kind of dice rolls should we support? If we want to make the program as widely useful as possible we should support as much of the commonly used dice notation as is possible, preferentially even a superset thereof. Most important are:

  • NdM: Where N is the number of dice and M the number of faces on those dice.
  • Mathematical Operators: Specifically +, -, /, and *.
  • Comparisons: Checking the rolled value against a given value.
  • Reroll: Reroll a die if a comparison succeeds. The ability to rerolls 1's is common in games.
  • Keep/Drop: Discard dice until N dice are left.

In all honesty, these options are taken from the library I'll be using, and as such could be considered programming to an implementation.

With that we have a feature and a series of examples of that feature, finishing the discovery phase of the BDD process.

Behaviour Driven Development

BDD is a re-implementation or expansion of Test Driven Development that is intended to be less focussed on the tests and more on the purpose of tests in the entire software development cycle. Tests in traditional TDD is heavily focussed on the programmer. The programmer decides what is tested and what the tests expect from the program.

In contrast BDD involves the rest of the software development team with deciding what is expected from the program, and how the program should behave under specific circumstances, which in turn is used to define the tests.

This is accomplished by bringing together the product owner, programmers and testers to together define requirements in a structured manner. The first part of this post is an example of the first phase: Discovery, where a feature to be worked on is selected and discussed so that the meaning, purpose and expectations from that feature are agreed upon.

When doing this on your own it is important to remember that you cannot be just the programmer and product owner, you also have to be the tester. This is something that developers find difficult, as it is our jobs to make things work, while when you are a tester your job is to break a poor programmer's hard work. And indeed, I forgot to put on a tester's hat during the above discovery.

Employing BDD should keep this from happening

So from there we have another feature:

  • Malformed dice notation should return an error message to the user.

Formulation

Once the features and examples have been decided on, the next step is to formulate them into formalized documentation. By using a formal language to describe features they are easy to understand for both humans and automated tools. The most common language used for this is Gherkin, which is designed to be human readable.

Gherkin used a Given, When, Then structure to describe scenarios, these are analogous to the Arrange, Act, Assert structure used in unit tests. Given describes the prerequisite state for starting the scenario, When indicates actions taken and Then describes the expected results.

Like all tests and related scenarios should be short and separate from the code. Don't reference buttons, commands or specific classes, but rather specify desired functionality and abstract user actions. This makes certain it does not need to change as the program changes and keeps it relevant as documentation for the program's desired functionality.

With formulation done we have a clear picture of what functionality we want to implement in the first sprint, we know the end goal and have specified clear acceptance criteria and know when the sprint is finished. In the next post I'll continue with planning the first sprint, now focusing on planning the classes themselves.

Wednesday, 15 December 2021

A dice-rolling program and why I'm writing it

My current hobby / self-development project is a re-write of Omnihedron, a diceroller and and random list roller for Tabletop Roleplaying Games like D&D. 

A common tool of Game Masters are lists of options from which options are selected randomly by rolling dice (examples: Dndspeak.com). Omnihedron allows users to define such tables using XML and its own language.

While the main reason I'm recreating Omnihedron is because it is an interesting learning project that fits into my existing interest in RPGs, there are a few points I want to specifically improve upon:

  • The window that shows the generated results does not allow selecting and copying results.
  • All the loaded lists are shown in a large list that quickly becomes hard to use.
As well as some potential improvements:
  • Adding variables to lists and commands.
  • Adding logic to commands.
  • Saving commands as dice
These will make it easier to create complex tables and allow creating custom dice like the narrative dice used in FFG's Star Wars RPG.

Learning C#

My current development experience is primarily in back-end web development, and a major goal of this project is to learn how to create an actual desktop program.

The main technologies used in building the application are C# 10, .NET 6 and WPF.

Monday, 13 December 2021

Take your own projects seriously

At first solo development in your spare time seems like it won't need as much planning or documentation as the work of a professional team does, and it indeed it doesn't. But the reality of a project run by a single developer in their spare time is that they lapse as interest and spare time wanes. It is a common programmer joke that even code you write yourself becomes unrecognizable, and so another interesting idea joins the folder(s) of incomplete projects (speaking from personal experience).

By making certain your own projects are properly planned and documented you can safely drop them and pick them up again weeks or even months later as time and attention permits.

But this is more easily said than done, so how do I plan to do this?

Docs as Code

While spending time on various subreddits and blogs (see upcoming blog post: Procrastination or Professional self development?) I've come across the idea 'Docs as Code' that seems to fit well with the goals I've set for myself. The central point is that the documentation is just as important as the code and should be handled with the same tools and included into issues and requirements.

To start this requires including documentation into the git depository, specifically as .md as github can display those properly. Secondly I will require features to be planned through documentation before  starting coding.

The advantage of writing documentation ahead of time is that it forces you to think and design before writing, and just like coding to an interface it will make the documentation less determined by the code. The tool developed for defining and describing software is of course UML, and in the spirit of keeping code and documentation as close together as possible I'll be using PlantUML for this. While Github cannot render .puml files, with the right plug-in Rider can.

Solo Agile

When planning the project I need to be flexible and get quickly visible progress. As such I'll be using a variation on Agile. Instead of splitting sprints over time they will instead focus on a specific feature at a time. Hopefully regular results will keep my interest on the project. 

If I'm going to use Agile that means I also need a big board and multi-colored post-its. Sadly keeping a bunch of those around at home for various active and less active projects seems unsustainable, so a computerized solution will have to be used. Github project boards are basically kanban boards that can be filled with issues and will allow planning and populating sprints while staying close to the code.

Even when working alone sprints and retrospectives should still be useful to evaluate the way I'm working and improve and expand upon the methods laid out here.

My goal with this blog is to become a better programmer, not just at writing code, but also at all the designing and planning needed to finish a project and deliver a program that can fulfill the requirements. I hope that by writing posts here to document and evaluate my methods and skills.

So for the next post in the Solo Experiment I will introduce the project I'm going to be working on and laying out its requirements.

Links

A Philosophy of Software Design - Chapter 1

 A Philosophy of Software Design is it's author's attempt to teach an often neglected core skill in software development: How to des...