To begin our little project, we need to create our initial project structure. Once that’s in place, we can create the first class from our application model -
It’s frequently the case that a project directory accumulates addition stuff above and beyond the actual source code itself. For this reason, it’s my custom to carefully curate the folder structure of any project, so that things start off tidy and stay that way as the project evolves.
For this project, I’m starting with two subfolders underneath the main project folder:
src folder is for all the projects that make up deliverable components of our application. In this case, we’re starting with just a single project
tests folder is for all our test projects, keeping the tests nicely segregated. You can see here the
WordTutor.Core.Tests project, which will contain all the unit tests for the
.vs folder is a working folder for Visual Studio Code, and the
.git folder contains our git repository. Both can be ignored.
One thing I’m really appreciating with .NET Core is the new project structure - all of the repetition and boilerplate from the old
.csproj files has gone. Check it out - here’s the entire file for
Here, we’re targetting .NET Standard 2.0 for maximum compatibility. Good practice is to target .NET Standard where possible - and the lower the standard you use, the wider the potential for reuse. Though, this is because lower versions are more restrictive, so it’s a balancing act.
The project file for
WordTutor.Core.Tests.csproj is a litte more complex, due to project and package references, but it is still far easier to read than the older style:
This time, the project targets an actual runtime, necessary for execution of the unit tests.
Neither project explicitly references any
.cs source files - inclusion is now automatic, with a couple of benefits: there is a reduced chance for conflicts when adding additional source files, and this also encourages a tidy codebase where extraneous source files (debris left over from earlier efforts) is cleaned up as it’s made.
Modelling a single word
To encapsulate each individual spelling word, we have the immutable class
VocabularlyWord. Here’s an abridged view of the important details:
We begin with the essential properties for the word - how to spell it correctly, how to say it correctly (because sometimes a speech engine doesn’t say things the way we expect), and a sample phrase to give the word in context.
For simplicity, we initialize a word with just a spelling and then we have some transformation methods that each return a new instance with the required change. This is a little bit wasteful, creating heap debris, but we’re looking at an interactive application here, not a server, so the simplicty of design likely worth the performance cost.
The key that makes these transformation methods work is a private constructor that allows creating of a near-clone of an existing word:
Each parameter has a null default, and if not provided, the matching property from
original is used instead. This is possibly because null isn’t a permitted value for any of the properties.
There’s nothing particularly novel about the implementations of
GetHashCode(), but they’re included for completeness:
The testing of
VocabularyWord is pretty straightforward, so I’ll leave it to you to check out the code for yourself.
In the next post, we’ll look at collecting many words together into a
VocabularySet and explore how to transform an immutable collection.