How principled coders outperform the competition

15 Mar 202311:11


TLDRThis video script outlines seven common pitfalls in programming that can degrade code quality. It emphasizes the importance of adhering to programming standards for consistency and readability, and introduces the SOLID principles to guide better coding practices. The script also discusses the value of design patterns, the significance of clear and descriptive naming conventions, and the necessity of testing code. Additionally, it touches on the challenges of time management and the risks of rushing, advocating for thoughtful planning and execution to avoid future code debt and ensure maintainable, scalable, and testable code.


  • πŸ“œ Adhering to programming standards like whitespace, file structure, and shared expectations is crucial for code readability and collaboration.
  • 🎯 Implementing SOLID principles (Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) leads to more maintainable, scalable, reusable, and testable code.
  • πŸ” Following programming design patterns provides structured solutions to common coding problems and helps in creating a universal programming vocabulary.
  • πŸ“Œ Using descriptive and meaningful variable names, avoiding unnecessary encodings, and replacing magic values with named constants improves code clarity.
  • πŸ§ͺ Writing tests, including end-to-end, unit, and integration tests, is essential for validating code functionality and maintaining a modular and decoupled architecture.
  • ⏳ Accurate time management and estimation are important; it's better to overestimate and deliver early than to miss deadlines due to unforeseen challenges.
  • πŸš€ Don't rush the coding process, especially for long-term projects, to avoid accumulating technical debt and to ensure a solid foundation for future development.
  • πŸ“ˆ Continuous improvement is key; embrace the learning process and strive to write code that is understandable and maintainable by other developers.
  • 🌟 Good programmers write code that is not just for computers, but for humans to understand, emphasizing the importance of code quality and readability.

Q & A

  • What are the seven deadly sins of programming mentioned in the script?

    -The script does not explicitly list all seven sins, but it discusses several bad programming practices such as not using programming standards, not following design principles like SOLID, underusing design patterns, poor naming conventions, lack of testing, poor time management, and rushing through development.

  • Why is adhering to programming standards important?

    -Programming standards are important because they provide a set of rules for code formatting, whitespacing, and file structure, which make the code consistent and easily readable. This is especially crucial when working in a team, as it ensures that everyone relies on shared expectations, making the code more maintainable and understandable.

  • What does the acronym SOLID represent in programming?

    -SOLID is an acronym that stands for five design principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. These principles guide programmers to create more maintainable, scalable, reusable, and testable code.

  • What does the Single Responsibility Principle suggest?

    -The Single Responsibility Principle suggests that a class or module should have only one reason to change, meaning it should have only one responsibility. This helps in breaking down large classes into smaller, more manageable ones, making the code easier to understand, test, and reuse.

  • How does the Open/Closed Principle relate to software design?

    -The Open/Closed Principle states that software entities (modules, classes, functions, etc.) should be open for extension but closed for modification. This means that you should be able to add new functionality without changing the existing code, which reduces the risk of introducing bugs and makes the system more stable.

  • What is the purpose of Interface Segregation Principle?

    -The Interface Segregation Principle states that no client should be forced to depend on methods it does not use. It encourages creating smaller, more specific interfaces that a module can implement, which leads to more modular and flexible code, especially beneficial for testing and maintaining the system.

  • What does Dependency Inversion Principle mean?

    -The Dependency Inversion Principle suggests that high-level modules should not depend on low-level modules. Instead, both should depend on abstractions (typically interfaces). This decouples the modules, allowing for more flexibility in changing implementations without affecting the rest of the system.

  • How do programming design patterns help in software development?

    -Design patterns provide reusable solutions to common problems in software design. They are not fixed implementations but rather templates that can be adapted to specific needs. Patterns help in structuring the software in a way that is maintainable, scalable, and understandable, leading to better architectural decisions.

  • Why is it important to avoid unnecessary encodings and magic values in code?

    -Avoiding unnecessary encodings and magic values makes the code more readable and maintainable. It reduces the cognitive load on developers, as they don't have to decipher what certain values or strings represent. Using named constants and descriptive variable names helps in understanding the code's intent and prevents errors that may arise from misinterpretation.

  • What are the different types of testing mentioned in the script, and what are their purposes?

    -The script mentions end-to-end testing, unit testing, and integration testing. End-to-end testing simulates user interactions to validate the system's behavior as a whole. Unit tests verify the functionality of individual modules in isolation. Integration tests examine how modules interact with each other. Each type of testing serves to ensure different aspects of the code's correctness and reliability.

  • How can following the SOLID principles make writing tests easier?

    -Following the SOLID principles leads to more modular and decoupled code. This structure makes it easier to isolate individual components for testing, as each module has a single responsibility and clear interfaces. This simplifies the process of writing unit tests and helps in creating a more robust testing suite.



πŸ“ The Seven Deadly Sins of Programming

This paragraph discusses the importance of adhering to programming standards to maintain code quality and readability. It emphasizes the learning process in coding and the ease of improvement. The video aims to guide viewers to better coding practices by identifying common mistakes. The first sin highlighted is the neglect of programming standards, which are crucial for consistency and collaboration. The paragraph also introduces the SOLID design principles, explaining each principle's role in creating maintainable and scalable code. The SOLID acronym stands for Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. The paragraph concludes by advocating for the use of programming design patterns to solve code problems effectively.


πŸ” Design Patterns and Code Readability

The second paragraph delves into the use of design patterns to architect software systems, categorizing them into creational, structural, and behavioral patterns. It provides examples of each, such as the factory method and adapter patterns. The paragraph also addresses the importance of naming conventions in code for clarity and understanding. It suggests avoiding unnecessary encodings, expanding abbreviations, and using descriptive names to improve code readability. The discussion on testing includes end-to-end, unit, and integration tests, emphasizing the benefits of modular and decoupled code for easier testing. Time management and estimation are also touched upon, with advice on not rushing and allowing for unforeseen challenges.


⏳ Time Management and Patience in Development

The final paragraph emphasizes the importance of taking time in project development, especially for long-term projects. It advises against rushing and the associated risks of poor architecture leading to code debt. The paragraph suggests that thoughtful planning from the beginning can lead to projects that become easier over time. It concludes with an inspirational quote from Martin Fowler, highlighting the goal of writing code that is understandable by humans, not just computers, and encourages viewers to become the programmers they aspire to be.



πŸ’‘Programming Standards

Programming standards are a set of rules and guidelines that dictate how code should be written to ensure consistency and readability. In the video, the importance of adhering to these standards is emphasized for maintaining a clean and understandable codebase, especially when collaborating with others. An example given is the use of whitespacing and file structure to achieve this consistency.

πŸ’‘SOLID Principles

SOLID is an acronym for five principles of object-oriented design and programming that help create a maintainable and scalable codebase. The principles are Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. The video explains how these principles contribute to better code design, making it easier to understand, test, and modify.

πŸ’‘Design Patterns

Design patterns are reusable solutions to common problems in software design. They are not fixed implementations but rather templates for how to solve a problem. The video categorizes design patterns into creational, structural, and behavioral, each serving a different purpose in software architecture.

πŸ’‘Code Readability

Code readability refers to how easily and quickly a programmer can understand the purpose and functionality of a piece of code. The video emphasizes the importance of readable code and provides tips on how to improve it, such as avoiding unnecessary encodings and using descriptive names for variables and functions.


Testing in software development is the process of evaluating the correctness, completeness, and quality of the code. The video discusses different types of testing, including end-to-end, unit, and integration testing, and how they contribute to validating the functionality and behavior of the code.

πŸ’‘Time Management

Time management in programming involves estimating and allocating time effectively for tasks, including coding, testing, and refactoring. The video advises doubling or tripling initial time estimates to account for unforeseen challenges and encourages not rushing the development process.

πŸ’‘Code Quality

Code quality refers to the standard of the code in terms of its structure, performance, and maintainability. The video discusses various practices and principles that contribute to high code quality, such as adhering to programming standards, following SOLID principles, and writing tests.

πŸ’‘Code Debt

Code debt is the concept of accumulating technical debt by making quick, 'dirty' code changes that solve immediate problems without considering the long-term implications. The video warns against rushing the development process, which can lead to code debt and make future changes more difficult.


Maintainability refers to how easy it is to modify, improve, or fix a piece of software. The video emphasizes the importance of writing maintainable code by following best practices and principles that make the codebase more understandable and easier to work with over time.


Reusability is the ability of a piece of code to be used in different contexts or projects without significant modification. The video encourages the creation of reusable code by breaking down large classes into smaller, single-responsibility modules, as per the Single Responsibility Principle.


Seven deadly sins in programming that degrade code quality

Importance of adhering to programming standards for code consistency and readability

The SOLID principles for better programming practices

Single Responsibility Principle: one responsibility per module

Open-Closed Principle: design for extensibility without modification

Liskov Substitution Principle: extending modules without breaking compatibility

Interface Segregation Principle: modules should only know about used functionality

Dependency Inversion Principle: abstract communication via interfaces

Benefits of SOLID principles: decoupled, maintainable, scalable, reusable, and testable code

Programming design patterns for solving code problems

Creational, structural, and behavioral patterns in software architecture

Avoiding unnecessary encodings and improving code clarity

Using descriptive names and named constants for better code understanding

The importance of testing code for quality assurance

End-to-end, unit, and integration tests for different levels of validation

Time management and estimation in project development

Avoiding rushing and ensuring a solid foundation for long-term projects

Martin Fowler's quote on writing code for human understanding



Hi there, there are what I would consider to be seven deadly sins when it comes to programming.


Things that will grind your code quality into dust if you don't heed their lessons.


Now I hope you've never had to hear someone tell you that you write bad code, but if you


have there's really nothing to be embarrassed about.


We all write flawed code as we learn, and the good news is it's fairly straightforward


to make improvements if you're willing.


In essence, that's why I've created this video to guide you to becoming a better coder.


So let's look at the mistakes you might be making and see if we can fix them.


The first thing I see people doing is not using programming standards.


They give us rules to follow, like whitespacing, file structure and other philosophies that


we apply to make our code consistent and therefore easily readable.


It's also especially important when working with other people, because it allows everyone


to rely on shared expectations.


If you don't keep standards, it's kind of like switching fonts all the time.


We can read it, sure, but the subtle differences throw us off and slow us down a bit.


As for choosing a standard, if you aren't given one by your team, then there's plenty


to choose from in the wild.


The second thing, programming design principles, are probably some of my favourite ways to




You can think of principles like a general guide into becoming a better programmer.


They're the raw philosophies of code.


Now there's a lot of principles out there, too many to cover in this video, but I will


quickly show five very important ones which go under the acronym of SOLID.


The S in SOLID stands for Single Responsibility, and it teaches us that we should aim to break


our code down into modules of one responsibility each.


So if we have a big class that is performing unrelated jobs, for example, we should split


that up into separate classes to avoid violating the principle.


It's more code, yeah, but we can now easily identify what the class is trying to do, test


it more cleanly and we can reuse parts of it elsewhere without having to worry about


irrelevant methods at the same time.


This actually becomes more important as we progress.


The oh-so-open-closed principle suggests that we design our modules to be able to add


new functionality in the future without having to actually make changes to them.


Instead, we should extend a module to add to it, be that wrapping it or something else,


but we should never modify it directly.


Once a module is in use, it's locked, and this now reduces the chances of any new additions


breaking your code.


Luckily, the Luminous Lyskov leaves us a lesson that loosely limits how we leverage our legacy




Okay, that's enough of that.


Lyskov wants to tell us that we should only extend modules when we're absolutely sure


that it's still the same type at heart.


For example, we can probably extend a hexagon into a six-pointed star, because that still


makes sense as a six-sided shape, but we can't really do the same if we wanted a five or


seven-pointed star, because that would no longer be compatible with what a hexagon represents.


It just wouldn't fit cleanly anymore into parts of your code that expect hexagons, and


so it will have failed the principle.


If that's the case, it should extend something that fits its design or become its own type




Almost at the end now, and we have I for Interface Segregation.


It says that our modules shouldn't need to know about functionality that they don't use.


We need to split our modules into smaller abstractions, like interfaces, which we can


then compose to form an exact set of functionality that the module requires.


This becomes especially useful when testing, as it allows us to mock out only the functionality


that each module needs.


Which brings me to Big D, which stands for Dependency Inversion.


This one is pretty simple to explain, because it says that instead of talking to other parts


of your code directly, we should always communicate abstractly, typically via the interfaces we




Dependency Inversion breaks down any direct relationships between our code, and isolates


our modules completely from one another, meaning we can swap out parts as we need to.


Because they communicate with interfaces now, they don't need to know what implementation


they are getting, only that they take certain inputs and return a valid output.


The cool thing about SOLID is that when we combine all these principles together, it


ends up decoupling our code, giving us modules that are independent of each other and making


our code more maintainable, scalable, reusable and testable.


Programming design patterns, not to be confused with principles from the last chapter, are


also something I see underused a lot, when they really should have more of a place in


your mind.


Patterns give us some real solutions to our code problems, but they aren't fixed implementations,


so they're still kind of open to interpretation.


We use them to architect our software systems, matching the right shapes to fit the needs


our software has.


First up, we have creational patterns, which are there to help us make and control new


object instances, such as the factory method pattern, which turns a bunch of requirements


into different modules that follow the same interface, but aren't necessarily the same




Then there's structural patterns, which are concerned with how we organise and manipulate


our objects, such as the adapter pattern, to wrap a module and adapt its interface to


one that another module needs.


Finally, there's behavioural patterns, which focus on how code functions and how it handles


communication with other parts of the code, such as using the observer pattern to publish


and subscribe to a stream of messages in an event-based sort of architecture.


Now there's a bunch of different design patterns under each category, some of them


you might have used before.


A lot of these patterns are used by frameworks and by professionals in huge corporations,


and that kind of ties in with another pretty unique benefit.


The benefit of creating a universal vocabulary of programming.


Have you ever written some code that seemed great at the time, but later you had trouble


understanding it?


Well, it often comes down to the way you name things.


Take a look at this snippet.


It's quite short, but it's hard to interpret what's going on without some thoughtful analysis.


Let's fix this in steps.


First up, we should avoid unnecessary encodings, such as type information, which make it harder


to read code in a natural way.


Next we have many abbreviations and acronyms that don't really explain well enough what


they are.


We should expand them to their full names to avoid any miscommunication.


Something better, but it's not really clear what some of these variables hold.


They're quite vague and ambiguous.


We should aim to use names that more accurately represent the nuances of the code we're working with.


We also want to replace magic values, such as the organ index or trigger word string,


with named constants.


By doing so, we clarify their significance, and we help to keep things in sync if they


used elsewhere.


Okay, we can now read this code and understand what it's doing without having to think


too hard about it.


However, we can still improve it further.


If you have any compassion for your future self, or other unfortunate developers who


might have to read your code, be descriptive with your names.


Ideally, we want to find a balance between being clear enough to quickly understand what


the code does, without being so verbose that it becomes an information overload.


Remember that no matter how good you think your code is, if it's not easy to read,


I would argue that it's not actually good code at all.


Many people don't test their code, and that's understandable, I think.


Writing tests can be very difficult when code is not properly architected.


At the high level, we have end-to-end testing, which lets you test the system as if you were


the end user.


It's useful because literally any spaghetti code can be end-to-end tested, assuming you


can simulate the inputs, as it never actually touches the code itself, only what it delivers


to us.


They can be tricky to set up, though, due to the need to always have a fully functional


application running, but they are surprisingly valuable.


At the lower level, we have unit tests to verify the operation of our modules in isolation,


and integration tests to examine the interaction between those modules.


These provide validation that our code is doing what we expect it to, rather than focusing


more on behaviour, like end-to-end tests.


If the thought of writing tests seems overwhelming right now, try applying the solid principles


you learned earlier.


You might be surprised at how much easier it becomes when your code is modular and decoupled.


Number six is…




And how you manage it.


Time estimation is a process I still fail in sometimes.


A common rule of thumb is to double or even triple your initial time estimate for a task.


It feels excessive, but it's impossible to predict the unknown problems we will encounter


along the way, so we need to account for those.


For example, this video took three times as long to make as I had predicted.


I really should take my own advice sometimes.


Remember that creation goes hand-in-hand with problems, so in the end, it's better to


overestimate and deliver ahead of schedule than it is to miss a deadline.


Alright, this one is a bit cheeky, as it's still kind of related to time, but I needed


seven, not six points to make the Deadly Sins reference, so here we are.


All I wanted to say here is that you should try not to rush.


Things can feel great when we're blazing through a project, and there's definitely


a place for that in prototypes.


But remember that if this is going to be a long-term project, take your time and think


things through from day one.


We'll never get all our decisions right first time, but we can at least give ourselves


a better foundation to work from, and hopefully avoid some of that nasty code debt later.


Anyway, you're likely to finish in less time regardless if you're not constantly battling


decisions you can't easily fix because of poor architecture.


We want projects that get easier with time, not harder.


And that's it.


Wow, you leveled up.


Go forth and be the programmer you were always meant to be.


I'd like to end with a quote from Martin Fowler.


Any fool can write code that a computer can understand.


Good programmers write code that humans can understand.


Thank you so much for watching.


It's been many weeks making this video, but it's all worth it to see that smile of yours




See you next time.

Rate This

5.0 / 5 (0 votes)

Related Tags
Clean CodingSOLID PrinciplesDesign PatternsCode QualitySoftware ArchitectureProgramming StandardsCode ReadabilityTesting Best PracticesTime ManagementCode Debt