
This course is aimed universally at all software developers that are working in the Object Oriented paradigm; the examples and the exercises are in C#, so it is most suited to developers that are working in C# or have much familiarity with C# (although the principles are equally applicable in Java, Python or other OO languages). The concepts covered are core to development, so they will be useful for those just starting out, but still useful for the most experienced professional - we encourage you, if you are this person, to engage more deeply with the exercises to try and stretch your understanding of the concepts.
The course is designed to go from underlying concepts through to the most concrete of rules - it starts out conceptually, and then we build upon the concepts to get to more concrete ideas. We highly recommend going through sections 2 and 3 sequentially (Axioms and Lenses, and then Values), and after that you can either go sequentially (recommended) or you can jump between chapters. However, some demos assume you have seen the previous few sections, and we do assume you know the previous concepts or ideas covered.
For each section, there are a set of videos that cover the theory, and in some cases a demo that shows how that theory is applied. Then, very importantly, there are exercises that we highly encourage you to do. These will help you to embed the theory. The learning cycle applied in this course goes like this: theory (videos) -> experimentation (exercises) -> practice (you do this in your daily work) -> reflection (in your cohort, hopefully, or on your own). This means the course can be done over a period of months, with time set aside each week for videos and exercises. Then, try to apply your learning in your daily programming tasks, or in a project you are working on. Finally, meet back together with your cohort and discuss how that concrete experience has gone - this will help you to reflect what you have learned. Alternately you can do this course as an intensive three to five day program, but in that case it's even more important that you do the exercises to practice what you're learning.
Please download the attached notes; these are the notes for the entire course and serve as a supplement to the video material. Each section will indicate what pages to read from the notes, and some will indicate what exercises to do from the notes (while others will have exercises not included in the notes).
Discover core coding principles that apply to professional software developers, using practical lenses to evaluate code, trade-offs, and contexts. Practice through exercises and teamwork to reinforce learning.
Define axioms as true starting points for reasoning and show how lenses analyze code across abstraction levels, illustrating how baseline truths shape software principles and outcomes.
Code is a high read, low write system; prioritize reading over writing, use code reviews to prevent defects, and consider future readers in software design.
Emphasize code quality as a logical consequence of axioms that reduces accidental complexity and increases readability, helping us manage both essential and accidental complexity as we write and read code.
Explore how lenses relate within a framework of axioms, environment, concepts, values, and practices, and how purpose and needs drive rapid feedback via test driven development and code reviews.
Notes
Read the Introduction section of the course notes (pages 5 to 7).
Further Reading
Read "No Silver Bullet: Essence and Accidents of Software Engineering" - this is provided in this section in PDF form.
Exercises
Watch the J.B. Rainsberger video linked below - the talk is only 7m30 seconds. Please be warned, the speaker does use some PG-13 language. Consider your own response to what J.B. Rainsberger is saying in this talk - do you agree? Do you not?
Do the exercises on page 7 of the course notes. If you have a group to discuss these questions with, please discuss them with your group - try to argue for both sides of each question to see if you can grapple more deeply with the concept of lenses.
Discover how code communicates intent, prioritizing readability and meaningful naming with ubiquitous language and domain primitives to ease maintenance and collaboration.
Embrace simplicity by valuing simpler solutions over complex ones to reduce accidental complexity and reveal essential complexity, improving readability and long-term maintainability.
Explore how communication, flexibility, and simplicity guide values in software development, optimize for user needs, and shape team discussions through exercises and concepts.
Notes
Read the Values section in the notes (p 9 to 11).
Further Reading
Please refer to the Further Reading suggestions on p14 of the notes if you would like to read further - however, the suggestions require the purchase of books not included in this material, so while we recommend these books, it's not required reading.
Exercises
Do exercise 1 on page 14 of the notes (Fibonacci comparison). If you have a group, spend some time (15 minutes) on your own considering the question and write notes around your answers, and then come together to discuss your answers in comparison to others. Note that that preferences for the different implementations probably indicate different values, or different emphases on values among your group.
Define coupling as the probability that changes in one module affect another, compare high, low, and loose coupling, and emphasize managing relationships to avoid a big ball of mud.
Explore external coupling, the weakest yet essential form of content coupling, by using a common external protocol like HTTP, and learn to shield core logic with an anti corruption layer.
Examine simple object data coupling, then decouple an email agent from the email service using dependency injection by passing an interface through the constructor, enabling runtime replacement.
Explore cohesion as the internal bond within modules, its types from coincidental to functional, and how boosting functional cohesion with profiling reduces coupling and eases maintenance.
Notes
Read the Coupling and Cohesion section in the notes, pages 20 to 22.
Further Reading
The notes include a number of links and further references for further exploration of this topic. Please at least read the publicly available articles referenced, which can be found in resources.
Coupling and Cohesion at Ward Cunningham's wiki
PragPub Magazine, January 2011: Code Coupling (p24) by Tim Ottinger and Jeff Langr. Find this attached.
PragPub Magazine, Decemober 2010: Cohesive Software Design by Tim Ottinger and Jeff Langr. Find this attached.
Exercises
For this section there are no exercises, as this concept will be used in later sections - however, please do read the further reading articles referenced above.
Refactoring teaches switching between adding functionality and refactoring hats. Use test-driven development cadence to improve internal structure and reduce coupling without changing behavior, through rename, move, delete, extract, and inline.
Master basic refactoring techniques, including rename, move, delete, extract, and inline, using Visual Studio and automated tools with unit tests to ensure safe changes.
Explore move refactoring to relocate a class or method across folders and namespaces, update usages automatically, and safely manage static methods and cross-file dependencies.
Notes
There are no notes for this section
Further Reading
We highly recommend reading Refactoring (2nd Ed) by Martin Fowler. The info page for the book is worth exploring (there is a free opening chapter), and the companion site: https://refactoring.com/ which contains a full catalog of the refactorings identifed by Martin Fowler, which are far more than the core five we cover in the videos in this section.
Exercises
Watch the worked example at the end of the section, which demonstrates the use of refactoring by way of the Tennis Refactoring Kata. Then do the kata yourself: get the code from Github, pick one of the versions to refactor and go for it, remembering to run your tests after every small change you make. This is a pure refactoring exercise - you don't need to add any functionality. Although the demo is only 36 minutes, give yourself a few hours to do it, and, if possible, do it in pairs and discuss each step in your pair, holding one another accountable to keep refactorings small and to run the tests between each change.
Download the attached zip file (RefactoringExercise.zip). Within it is a C# solution that contains a Program.cs. The instructions for the exercise are found at the top of Program.cs.
Learn how to safely refactor code with a tennis scoring kata in C#, using open source starting points, deliberate practice, tests, and xUnit in Visual Studio to build muscle memory.
This lecture demonstrates live refactoring of a premium calculator, moving parameters to the constructor, introducing base rate options and smoker status enums, and enhancing tests with builders and randomization.
Refactor tests to focus on the result, introduce a SUT builder to encapsulate the premium calculator setup, and move test logic into a reusable calculator builder.
There are no further notes for this section.
Further Reading
A blog post by developers at Google on reducing nesting can be found below.
Also attached is a paper from HP in 1979 talks about applying the Cyclomatic number defined by McCabe within HP, and how it helps to reduce bugs through reviewing complex code. The relevant article is on page 64.
Exercises
Try to run the cyclomatic complexity metrics on some existing code in your tool (such as Visual Studio). This would best work on existing production code, but can also be done using a kata or other exercise you have done before in this course. (If you can't find something to run it on, use the start of the Tennis Refactoring Kata). Then try to reduce the cyclomatic complexity of the method with the highest cyclomatic number by breaking it up using the refactoring techniques learned so far.
Minimize repetition by keeping things small: small classes, methods, procedures, and modules to encourage reuse and avoid copy-pasting, as discussed in the dry principle.
Explore symmetry as a design principle that balances code concepts, from open and close methods to constructors and destructors, and apply it to reduce repetition and improve clarity.
Notes
Read the Principles section in the notes on page 12 to 14.
Further Reading
The principles listed here are taken and adapted from Kent Beck's Implementation Patterns (Addison-Wesley, 2008). In particular, Chapter 3: A Theory of Programming (pp 9 to 18).
Exercises
Medicine Import exercise: download the attached Exercise-MedicineImport.zip file. This contains a Visual Studio solution, open up this solution and go to Program.cs, which contains the exercise instructions.
Principles to Values exercise: download the attached Exercise-PrinciplesToValues.zip file. This contains a readme.md file that contains the instructions for the exercise.
Extra: Do exercise 3 on page 16 of the notes.
Notes
Read the DRY section in the notes, page 23 and 24
Further Reading
Read "The Evils of Duplication" - a free excerpt from The Pragmatic Programmer: your journey to mastery 20th Anniversary Edition (Addison-Wesley, 2020) by Dave Thomas and Andy Hunt. The excerpt is attached to this page.
Read interview linked below with Dave Thomas and Andy Hunt by Bill Venners, from 2003 (last accessed 2 December 2022)
Explore Kent Beck's four rules of simple design—appropriate for the intended audience, communicative, well factored, and minimal—to guide clear, flexible code.
J. B. Rainsberger's formulation distills simple design into two essential rules: minimize duplication and maximize clarity, refined through refactoring to reduce duplication and improve clarity.
Notes
Read the Four Rules of Simple Design section in the notes on pages 17 to 19.
Further Reading
The original four rules are extracted from Extreme Programming Explained 2nd Edition, Kent Beck with Cynthia Andres (Addison-Wesley, 2005), and can be found in that book on pages 109 to 110.
Martin Fowler's formulation and discussion on the four rules can be found on his web site (last accessed 2 December 2022) - see link below.
J.B. Rainsberger's formulation and discussion on the four rules (he calls them elements) can be found on his blog (last accessed 2 December 2022) - the link is below.
Exercise
Roman Numerals Refactoring: download the attached RomanNumerals.zip file - the instructions for the exercise are contained within the readme.MD file within this zip file.
Download the attached file (SRP-TotalPerProductCalculator.zip), and open the solution. The instructions for the exercise are contained within Program.cs
Apply the open/closed principle by designing for extension rather than modification. Use polymorphism with property-specific classes to calculate annual rates, enabling new property types without altering existing code.
We are going to use the GildedRose Refactoring Kata to practice the use of the Open/Closed Principle
This Kata asks you to refactor a fairly large method and to also add some functionality.
Please clone the repository from Github - the link is provided in the Resources section below.
Your Task: Do the refactoring to improve the UpdateQuantity method as the kata asks you to do, following the DRY-DAMP cycle until you have got a version that is open for extension. Then add the functionality asked for by the kata by ONLY adding code.
First it is essential before refactoring to get the ThirtyDays test working. You do this by creating an approved file (ApprovalTest.ThirtyDays.approved.txt) by piping the console output to that file. Place this approved file in the csharp folder. Now run the test, and it will compare the result of this run to the approved file. This creates an overall characterisation test that will highlight if something has gone wrong. After that, it will be immensely helpful to write some unit tests before refactoring an area.
Extra: Try to get your resulting code to follow the Object Calisthenics Rules. These rules are to try to push you in ways you wouldn't normally code, to try things that seem a bit out of the ordinary and overly restrictive. By doing this in a kata, you stretch your skills and ways of thinking about code, which will help you in production to write more communicative, simpler, and more flexible code.
Object Calisthenics Rules:
Only one level of indentation per method
Don't use the ELSE keyword
Wrap all primitives and strings (wrap primitive types in classes)
First-class collections (wrap collections in classes)
One dot per line
Don't abbreviate
Keep all entities small
No classes with more than two instance variables
No getters/setters/properties
Extra thoughts:
This kata is publicly available, so you can use it in your teams: We highly recommend this for practicing. Code reviews are a good way of aligning your teams, but there are so many conflicting concerns when doing them (e.g. getting things out quickly, historical decisions or even no-go areas), that you often don’t get to just try ideas out: practice is for trying things out. This Kata lets you try to do something – if it doesn’t work out, reflect on why, learn from the experience, throw it away and try again. If it does work, reflect on why, learn from the experience, throw it away and try again another way. The output is not the goal, the process is.
Do this kata over and over in a team, with different pairs. Try to carve out the time – even an hour a week – just to spend on this practice.
Explore the Liskov substitution principle, where subtypes must be substitutable for base types, preserving contracts, invariants, preconditions and postconditions, and avoiding new exceptions in inheritance.
Explore how strengthening preconditions in a premium member fine calculator can violate the substitution principle, and how explicit preconditions and postconditions guide safe extendability of a library system.
Exercise: Liskov Substitution Principle
Consider whether you think each of these subtypes are substitutable for their base types according to the Liskov Substitution Principle – think conceptually, or create a class diagram to illustrate and explain your answer. Remember to consider both requirements: Contract Rules and Variance Rules.
Car for Vehicle
NoticeAccount for BankAccount
Square for Rectangle
LineSegment for Line
If you can, do this in pairs or small groups, and discuss the final answers you come to with the other pairs in your larger group. Alternately, try to write your reasoning out to verbalise it clearly.
Notes
Read the SOLID section in the notes: pages 25 to 36.
Further Reading
The first time these principles were written about together as a group was in Agile Principles, Patterns and Practices by Robert C. Martin. They're also covered similarly in Agile Principles, Patterns and Practices in C# by Robert C. Martin and Micah Martin, (Prentice Hall, 2007) - Chapters 8 to 12, pages 115 to 175.
A great compilation of thoughts and blog posts about SOLID is available for free from a link provided in the external resources section entitled Pablo's SOLID Software Development eBook (last accessed 2 December 2022)
A long-form Article: S.O.L.I.D. Software Development, One Step at a Time by Derick Bailey (published in CODE Magazine, 2010) - a link is provided in the External Resources section below (last accessed 2 December 2022)
Also linked in the External Resources here is an extra video - it is a lecture by Venkat Subramaniam's called Core Design Principles for Software Developers. The SOLID content starts at 56m, but the rest is also well worth watching as it recaps many of the concepts we have covered in this course.
Thinking exercise to finish the section
Draw a diagram linking the three core values of Communication, Simplicity and Flexibility to the SOLID principles - which of the SOLID principles serve which of the three values, and how do they do this?
The course is for developers who are looking to improve their ability to write good, clean, maintainable code. In it, we cover key coding principles that help to develop a language for discussion within the team. These include coupling and cohesion, the SOLID principles, DRY.
Note: the course examples and exercises are in C#, but the theory covered is applicable in all OO languages.
Goals -
• To get developers thinking about code quality
• To provide developers with the tools they need to discuss and evaluate code quality
• To get developers to build alignment about what “good” code is
• To provide developers with some guidelines about how to go about writing better code
Course Structure -
The following topics are covered:
• Preparation – what is the team’s existing understanding of good code?
• Lenses for Thinking about Code Quality - Thinking about programming like Kent Beck:
Core Values of Software Development
Key Principles
The Four Rules of Simple Design
• Cohesion and Coupling
• DRY
• SOLID Principles:
Single Responsibility Principle
Open-Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
• The Practice of Writing Clean Code:
Coding Standards
Meaningful naming
Functions
Comments
Learning Outcomes
At the end of this course developers will be able to:
Understand why code quality is important and how it enables effective software development
Describe key coding principles such as cohesion & coupling, DRY, and the SOLID principles
Reason about code quality using a variety of lenses
Discuss code quality ideas among a team and be able to, as a team, work towards alignment and agreement on the team’s coding standards
Write cleaner, more readable, more communicative, more flexible code than before