How principled coders outperform the competition

Coderized
15 Mar 202311:11

Summary

TLDRThis video script addresses seven common mistakes that degrade code quality, offering guidance to improve programming practices. It emphasizes adhering to programming standards for consistency and readability, mastering design principles like SOLID for better code structure, and utilizing design patterns for effective problem-solving. The script also stresses the importance of clear naming conventions for maintainability and the necessity of testing to ensure code reliability. Additionally, it advises on proper time management and avoiding rushing to prevent technical debt, ultimately aiming to enhance a programmer's skills.

Takeaways

  • ๐Ÿ“œ **Use Programming Standards**: Adhering to programming standards like whitespace, file structure, etc., ensures code consistency and readability.
  • ๐Ÿ”‘ **Follow Design Principles**: Principles like SOLID provide guidelines to write better, more maintainable code.
  • ๐Ÿ”’ **Single Responsibility Principle**: Aim for classes with one responsibility to simplify code and enhance reusability.
  • ๐ŸŒŸ **Open/Closed Principle**: Design modules to be open for extension but closed for modification to avoid breaking changes.
  • ๐Ÿ”„ **Liskov Substitution Principle**: Ensure that derived classes are substitutable for their base classes without affecting the program's correctness.
  • ๐Ÿ“š **Interface Segregation Principle**: Design interfaces to be small and specific to the needs of the modules that use them.
  • ๐Ÿ”„ **Dependency Inversion Principle**: Depend on abstractions, not on concrete implementations to reduce coupling.
  • ๐Ÿงฉ **Utilize Design Patterns**: Patterns provide proven solutions to common software design problems.
  • ๐Ÿ” **Improve Code Readability**: Use clear naming conventions, avoid unnecessary encodings, and replace magic numbers with named constants.
  • ๐Ÿ“ˆ **Write Tests**: Testing at different levels (end-to-end, unit, integration) ensures code correctness and behavior.
  • โฑ๏ธ **Manage Time Wisely**: Overestimate time for tasks to account for unexpected challenges.
  • ๐Ÿƒโ€โ™‚๏ธ **Avoid Rushing**: Take time to think through decisions to establish a solid foundation and avoid technical debt.

Q & A

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

    -The script does not explicitly list seven sins but focuses on common mistakes that degrade code quality. These include not using programming standards, not following programming design principles, and other issues related to code maintainability and readability.

  • Why is adhering to programming standards important?

    -Adhering to programming standards ensures code consistency, making it easily readable. It's particularly crucial when working in teams as it allows everyone to rely on shared expectations, similar to how not switching fonts all the time makes reading smoother.

  • What is the SOLID acronym in software design principles and what does each letter stand for?

    -SOLID is an acronym for five object-oriented design principles intended to make software designs more understandable, flexible, and maintainable. S stands for Single Responsibility, O for Open/Closed, L for Liskov Substitution, I for Interface Segregation, and D for Dependency Inversion.

  • Can you explain the Single Responsibility Principle from SOLID?

    -The Single Responsibility Principle states that a class should have only one reason to change, meaning it should only have one job or responsibility. This helps in identifying the purpose of the class, testing it cleanly, and reusing it without unrelated methods.

  • What does the Open/Closed Principle suggest about module design?

    -The Open/Closed Principle suggests that modules should be open for extension but closed for modification. This means new functionality should be added by extending modules rather than modifying them directly, reducing the risk of breaking existing code.

  • How does the Liskov Substitution Principle guide the extension of modules?

    -The Liskov Substitution Principle states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. It guides the extension of modules by ensuring that subclasses remain compatible with what their superclass represents.

  • What does Interface Segregation Principle imply for module functionality?

    -The Interface Segregation Principle implies that no client should be forced to depend on methods it does not use. It suggests splitting modules into smaller interfaces that can be composed to provide only the required functionality, which is beneficial for testing and reducing dependencies.

  • Can you describe the Dependency Inversion Principle?

    -The Dependency Inversion Principle states that high-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions. This promotes loose coupling and high cohesion.

  • Why are programming design patterns important in software development?

    -Programming design patterns are important because they provide tried and tested solutions to common software design problems. They help in architecting software systems by matching the right solutions to the needs of the software, making the code more maintainable and scalable.

  • What is the significance of using clear and descriptive names in code?

    -Using clear and descriptive names in code enhances readability and maintainability. It helps future developers, including oneself, to quickly understand what the code does without extensive analysis. It also aids in avoiding miscommunication and keeps the code in sync if certain values are used elsewhere.

  • Why is it recommended to write tests for code?

    -Writing tests for code is recommended because it verifies that the code operates as expected. Tests can be end-to-end, unit, or integration tests, and they help catch issues early, reduce bugs, and ensure that future changes do not break existing functionality.

  • What is the advice on time estimation and project management in the script?

    -The script advises to overestimate initial time estimates for tasks, considering the unpredictability of problems that may arise. It also encourages not rushing through projects, especially long-term ones, to avoid technical debt and ensure projects become easier to manage over time.

Outlines

00:00

๐Ÿ“ The Seven Deadly Sins of Programming

This paragraph introduces the concept of seven deadly sins in programming that can severely degrade code quality. It acknowledges that all programmers write flawed code as they learn and emphasizes that there's no shame in receiving criticism for bad code. The speaker aims to guide viewers on how to improve their coding skills by identifying common mistakes and offering solutions. The first sin discussed is the neglect of programming standards, which are essential for maintaining consistent and readable code, especially in team settings. The paragraph also touches on programming design principles, highlighting the SOLID principles as a guide to better programming practices. The SOLID acronym stands for Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion, each principle aimed at creating more maintainable, scalable, reusable, and testable code.

05:02

๐Ÿ” Design Principles and Patterns in Programming

The second paragraph delves into programming design principles and patterns, emphasizing their importance in creating well-structured software systems. It explains the three categories of design patterns: creational, structural, and behavioral. Creational patterns assist in the management and instantiation of objects, structural patterns deal with the organization and manipulation of objects, and behavioral patterns focus on the functionality and communication within the code. The paragraph also discusses the value of a universal programming vocabulary, suggesting that clear and descriptive naming conventions are crucial for code readability and maintainability. It advises against using abbreviations and magic values, recommending the use of named constants instead. The summary stresses the importance of writing tests, suggesting that well-architected code following SOLID principles makes testing more manageable. Lastly, it touches on the importance of time management and estimation in programming projects, advising to overestimate time requirements to account for unexpected challenges.

10:03

โณ The Importance of Patience and Time Management in Coding

The final paragraph stresses the importance of patience and careful planning in programming projects. It warns against rushing through projects, especially long-term ones, as this can lead to poor architecture and code debt. The speaker suggests that taking the time to make thoughtful decisions from the outset can prevent future issues and result in projects that become easier to manage over time. The paragraph concludes with a quote from Martin Fowler, emphasizing that good code should be understandable by humans, not just computers, and thanks the viewers for their time and attention.

Mindmap

Keywords

๐Ÿ’กProgramming Standards

Programming standards refer to the set of rules and guidelines for arranging code in a consistent and readable manner. They include aspects like whitespacing, file structure, and other philosophies. In the video, the speaker emphasizes the importance of adhering to these standards to ensure code is easily readable and maintainable. For instance, not following standards is compared to switching fonts all the time, which can be read but is less efficient due to the subtle differences.

๐Ÿ’กDesign Principles

Design principles in programming are fundamental philosophies that guide developers to write better code. They serve as a framework for thinking about how to structure and organize code. The video mentions SOLID principles as an example, which are a set of five design principles intended to make software designs more understandable, flexible, and maintainable.

๐Ÿ’กSOLID

SOLID is an acronym for five object-oriented design principles intended to make software designs more understandable, flexible, and maintainable. It stands for Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion principles. The video explains each principle in the context of creating modular, decoupled, and maintainable code.

๐Ÿ’กSingle Responsibility Principle

The Single Responsibility Principle states that a class should have only one reason to change, meaning it should only have one job or responsibility. The video uses the example of splitting a large class performing unrelated jobs into separate classes to adhere to this principle, making the code easier to understand, test, and reuse.

๐Ÿ’กOpen/Closed Principle

The Open/Closed Principle suggests that software entities should be open for extension but closed for modification. This principle is illustrated in the video by advising to extend a module rather than modifying it directly to add new functionality, thus preventing the risk of breaking existing code.

๐Ÿ’กLiskov Substitution Principle

The Liskov Substitution Principle states that objects of a superclass shall be replaceable with objects of a subclass without affecting the correctness of the program. The video humorously explains this by stating that a hexagon can be extended to a six-pointed star but not to a five or seven-pointed star, as it would no longer fit into the code expecting hexagons.

๐Ÿ’กInterface Segregation Principle

The Interface Segregation Principle argues for the preference of many client-specific interfaces over a single general-purpose one. The video explains that modules should not need to know about functionality they don't use, advocating for splitting modules into smaller interfaces that can be composed to provide the exact set of functionality required.

๐Ÿ’กDependency Inversion Principle

The Dependency Inversion Principle suggests that high-level modules should not depend on low-level modules but should depend on abstractions. The video simplifies this by stating that instead of modules communicating directly with each other, they should communicate via interfaces, which allows for greater flexibility and easier module swapping.

๐Ÿ’กDesign Patterns

Design patterns are reusable solutions to common software design problems. The video categorizes them into creational, structural, and behavioral patterns. It mentions examples like the factory method pattern, the adapter pattern, and the observer pattern, which are used to architect software systems by matching the right shapes to the needs of the software.

๐Ÿ’กCode Readability

Code readability refers to the ease with which a reader can understand the structure, logic, and intent of the source code. The video stresses the importance of clear naming conventions, avoiding unnecessary encodings and abbreviations, and replacing magic values with named constants to improve code readability. It argues that even if the code is functional, if it's not easy to read, it's not considered good code.

๐Ÿ’กTesting

In the context of the video, testing refers to the process of checking code to ensure it meets the required functionality and to prevent software failures. It mentions different levels of testing such as end-to-end, unit, and integration testing. The video suggests that applying SOLID principles can make writing tests easier by creating modular and decoupled code.

๐Ÿ’กTime Management

Time management in programming refers to the ability to accurately estimate and allocate time for tasks. The video advises doubling or tripling initial time estimates to account for unforeseen problems, which aligns with the idea that it's better to overestimate and deliver early than to underestimate and miss a deadline.

๐Ÿ’กCode Debt

Code debt refers to the accrual of technical debt in the form of poorly written code that needs to be refactored. The video cautions against rushing through a project and emphasizes the importance of taking time to think through decisions from the start to avoid accumulating code debt that makes projects harder over time.

Highlights

There are seven deadly sins in programming that can degrade code quality.

Writing bad code is a natural part of learning and can be improved.

Programming standards like whitespace and file structure are crucial for readability and teamwork.

Adhering to standards prevents confusion and slows down the development process.

Programming design principles are essential for improving as a programmer.

SOLID principles are a set of five important design principles.

Single Responsibility Principle suggests one responsibility per module.

Open-Closed Principle advocates adding functionality without modifying existing modules.

Liskov Substitution Principle emphasizes extending modules only when they are of the same type.

Interface Segregation Principle states modules should not depend on unused functionality.

Dependency Inversion Principle promotes abstract communication between modules.

Combining SOLID principles results in decoupled, maintainable, scalable, reusable, and testable code.

Design patterns provide solutions to common coding problems and should be used more often.

Naming conventions are crucial for code readability and understanding.

Avoiding unnecessary encodings and abbreviations improves code clarity.

Using descriptive names and replacing magic values with named constants enhances code maintainability.

Good code is easy to read and understand, even if it's not perfect.

Testing code is essential, with different levels like end-to-end, unit, and integration tests.

Applying SOLID principles can make writing tests easier.

Time management is crucial; overestimating time for tasks can prevent missed deadlines.

Avoid rushing through projects to prevent long-term issues and code debt.

Good programmers write code that is understandable to humans.

Transcripts

play00:00

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

play00:07

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

play00:12

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

play00:16

have there's really nothing to be embarrassed about.

play00:20

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

play00:24

to make improvements if you're willing.

play00:27

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

play00:32

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

play00:39

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

play00:44

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

play00:50

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

play00:54

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

play00:58

to rely on shared expectations.

play01:02

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

play01:06

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

play01:12

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

play01:16

to choose from in the wild.

play01:20

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

play01:25

improve.

play01:27

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

play01:31

They're the raw philosophies of code.

play01:34

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

play01:38

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

play01:44

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

play01:49

our code down into modules of one responsibility each.

play01:54

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

play01:59

that up into separate classes to avoid violating the principle.

play02:03

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

play02:08

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

play02:12

irrelevant methods at the same time.

play02:15

This actually becomes more important as we progress.

play02:19

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

play02:24

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

play02:28

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

play02:33

but we should never modify it directly.

play02:36

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

play02:41

breaking your code.

play02:43

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

play02:48

code.

play02:49

Okay, that's enough of that.

play02:52

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

play02:56

that it's still the same type at heart.

play02:58

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

play03:02

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

play03:07

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

play03:12

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

play03:16

so it will have failed the principle.

play03:19

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

play03:23

instead.

play03:25

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

play03:30

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

play03:35

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

play03:40

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

play03:45

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

play03:51

that each module needs.

play03:54

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

play03:59

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

play04:03

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

play04:09

define.

play04:10

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

play04:15

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

play04:20

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

play04:24

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

play04:30

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

play04:34

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

play04:39

our code more maintainable, scalable, reusable and testable.

play04:46

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

play04:51

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

play04:54

your mind.

play04:57

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

play05:02

so they're still kind of open to interpretation.

play05:05

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

play05:09

our software has.

play05:11

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

play05:17

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

play05:22

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

play05:26

type.

play05:29

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

play05:33

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

play05:39

one that another module needs.

play05:41

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

play05:47

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

play05:52

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

play06:00

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

play06:03

you might have used before.

play06:05

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

play06:10

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

play06:13

The benefit of creating a universal vocabulary of programming.

play06:18

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

play06:23

understanding it?

play06:25

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

play06:30

Take a look at this snippet.

play06:32

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

play06:37

Let's fix this in steps.

play06:40

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

play06:45

to read code in a natural way.

play06:48

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

play06:53

they are.

play06:54

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

play06:59

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

play07:03

They're quite vague and ambiguous.

play07:05

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

play07:11

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

play07:16

with named constants.

play07:18

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

play07:22

used elsewhere.

play07:23

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

play07:28

too hard about it.

play07:29

However, we can still improve it further.

play07:32

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

play07:37

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

play07:40

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

play07:45

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

play07:51

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

play07:54

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

play07:59

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

play08:04

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

play08:09

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

play08:13

the end user.

play08:14

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

play08:20

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

play08:24

to us.

play08:25

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

play08:29

application running, but they are surprisingly valuable.

play08:33

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

play08:39

and integration tests to examine the interaction between those modules.

play08:44

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

play08:48

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

play08:53

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

play08:59

you learned earlier.

play09:01

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

play09:07

Number six isโ€ฆ

play09:11

Time.

play09:12

And how you manage it.

play09:15

Time estimation is a process I still fail in sometimes.

play09:19

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

play09:25

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

play09:29

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

play09:33

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

play09:38

I really should take my own advice sometimes.

play09:42

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

play09:46

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

play09:51

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

play09:57

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

play10:03

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

play10:06

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

play10:10

a place for that in prototypes.

play10:12

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

play10:16

things through from day one.

play10:17

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

play10:21

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

play10:26

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

play10:31

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

play10:35

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

play10:40

And that's it.

play10:41

Wow, you leveled up.

play10:43

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

play10:48

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

play10:51

Any fool can write code that a computer can understand.

play10:54

Good programmers write code that humans can understand.

play10:59

Thank you so much for watching.

play11:01

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

play11:05

now.

play11:06

See you next time.

Rate This
โ˜…
โ˜…
โ˜…
โ˜…
โ˜…

5.0 / 5 (0 votes)

Related Tags
Clean CodeProgramming StandardsDesign PrinciplesSOLID PrinciplesCode QualityCode TestingTime ManagementCode ReadabilitySoftware ArchitectureDevelopment Best Practices