Premature Optimization

CodeAesthetic
10 Feb 202312:39

Summary

TLDRThe video script discusses the pitfalls of premature optimization in software development. It emphasizes the importance of balancing velocity (speed of adding new features), adaptability (system's ability to change), and performance. The speaker argues that focusing too early on performance can lead to technical debt and hinder progress. Instead, they advocate for a measured approach, using data structures wisely, profiling for hotspots, and making educated guesses about code efficiency. The key message is to optimize only when necessary and to prioritize real-world problem-solving over micro optimizations.

Takeaways

  • 🚫 Premature optimization is often unnecessary and can be harmful, as it diverts attention from more pressing issues.
  • ⏱️ Performance discussions are not always valuable; they matter when they address real-world problems.
  • 🔍 Performance should be viewed as part of a tradeoff triangle, balancing velocity, adaptability, and maintainability.
  • 🛠️ Focusing solely on velocity can lead to technical debt, which slows down development in the long run.
  • 🔧 Adaptability involves designing code for future changes, but overdoing it can hinder velocity and performance.
  • 🔮 A crystal ball (predicting future requirements) would be ideal, but in reality, over-engineering for unlikely scenarios is wasteful.
  • 🎲 The importance of performance varies with the project's stage; early development may prioritize features over performance.
  • 🌐 Facebook's initial use of PHP, despite its inefficiencies, allowed for rapid development and growth.
  • 📈 Measuring performance is crucial; assumptions about what makes code faster should be tested empirically.
  • 🔄 Premature micro-optimizations are often pointless when modern computers are fast enough to handle them.
  • 📊 Profiling can reveal the true performance bottlenecks, guiding where to focus optimization efforts.

Q & A

  • What is the root of all evil according to the speaker?

    -The speaker believes that premature optimization is the root of all evil.

  • Why are most conversations about performance considered a waste of time?

    -They are a waste of time because people often prioritize performance over other important aspects like velocity and adaptability, without considering the bigger picture.

  • What is the tradeoff triangle in software development?

    -The tradeoff triangle consists of velocity (how quickly new features are added), adaptability (how well the system can change to new requirements), and performance (the efficiency of the system).

  • What is the risk of focusing solely on velocity?

    -Focusing solely on velocity can lead to creating technical debt, which may slow down development and maintenance in the future.

  • How does adaptability affect velocity and performance?

    -Adaptability, which involves writing reusable and extensible code, can increase velocity by reducing the size of changes needed for new features. However, it can also hurt performance due to added abstraction and indirection.

  • What should be the approach to performance optimization based on the stage of a project?

    -The approach depends on the project stage. Early in development, focus on velocity and adaptability. As the project nears completion, shift focus to performance to ensure a smooth final product.

  • Why did Mark Zuckerberg choose PHP for Facebook initially?

    -Zuckerberg chose PHP because it allowed him to build Facebook quickly, despite its inefficiencies and scaling issues.

  • What are the two types of performance issues the speaker differentiates?

    -The speaker differentiates between macro performance (design-level performance considerations) and micro performance (fine-tuned performance at the module or function level).

  • Why is premature optimization typically a concern for micro performance?

    -Premature optimization for micro performance often involves unnecessary fine-tuning that may not yield significant benefits and can lead to wasted effort.

  • What is the importance of measuring in performance optimization?

    -Measuring is crucial because it helps validate assumptions about what will improve performance. It ensures that efforts are directed towards actual bottlenecks rather than perceived issues.

  • What should be the first step in addressing performance issues?

    -The first step should be to identify and address 80% moves, such as changing data structures or algorithms that can have a significant impact on performance.

Outlines

00:00

🔍 The Tradeoff Triangle: Performance, Velocity, and Adaptability

The paragraph discusses the importance of balancing performance with velocity (speed of adding new features) and adaptability (system's ability to change). It emphasizes that focusing on performance too early can lead to technical debt and hinder future development. The speaker suggests that the right design can increase velocity by reducing the changes needed for new features, but over-adaptability can slow down performance. The stage of the project should guide the focus on these elements, with mature projects prioritizing performance and early-stage ones focusing on feature development and system extensibility. The speaker also differentiates between macro and micro performance, with the latter often being the subject of premature optimization.

05:02

🤔 The Futility of Premature Optimization

This paragraph delves into the concept of premature optimization, where developers might focus on micro optimizations that have negligible impact on performance. The speaker uses the example of the pre-increment (++) and post-increment (i++) operators in C++ to illustrate how such optimizations can be unnecessary and time-consuming. They argue that unless a performance issue is proven to be caused by a specific function, readability should take precedence. The paragraph also touches on the importance of measuring performance and the role of data structures in achieving significant performance improvements.

10:03

📈 Optimizing for Real-World Impact

The speaker advocates for a practical approach to optimization, starting with changes that could have a significant impact (80% moves) and using data structures effectively. They suggest profiling to identify performance hotspots and making educated guesses about the underlying code operations. The paragraph highlights that memory allocation and proximity of critical elements in memory can affect performance, but these considerations should only come into play after more straightforward optimizations have been exhausted. The speaker concludes by emphasizing the need for a real performance problem before focusing on optimization and encourages a measured approach to finding and addressing performance issues.

Mindmap

Keywords

💡Premature Optimization

Premature optimization refers to the practice of optimizing code or systems before it is necessary, which can lead to unnecessary complexity and potential inefficiencies. In the video, it is presented as a root cause of problems, emphasizing that performance should not be the primary focus at the beginning of a project, as it can hinder velocity and adaptability.

💡Tradeoff Triangle

The tradeoff triangle is a concept introduced in the video that represents the balance between velocity, adaptability, and performance. It suggests that focusing on one aspect may come at the expense of another, and the right balance depends on the project's stage and requirements. For example, a feature-complete game might prioritize performance over velocity, while an early-stage game might focus on adding features quickly.

💡Velocity

Velocity in the context of the video refers to the speed at which new features are added to a project. It is one of the corners of the tradeoff triangle, and the video emphasizes that while velocity is important, it should not come at the cost of creating technical debt or sacrificing adaptability.

💡Adaptability

Adaptability is the ability of a system to change and accommodate new requirements. It is another corner of the tradeoff triangle and is crucial for maintaining a system's relevance over time. The video discusses how designing for adaptability can increase velocity by reducing the changes needed for new features, but it can also negatively impact performance if overdone.

💡Technical Debt

Technical debt is the concept of accumulating problems or complications in a system due to suboptimal choices made during development, often in pursuit of short-term gains. In the video, it is mentioned as a consequence of focusing on pure velocity, where quick solutions can lead to long-term maintenance issues.

💡Performance

Performance in the video refers to the efficiency and speed of a system or code. It is the third corner of the tradeoff triangle and is often a concern when optimizing. The video argues that while performance is important, it should not be the first problem addressed, and that premature optimization can be more harmful than beneficial.

💡Macro Performance

Macro performance, as mentioned in the video, refers to system-wide performance considerations. It contrasts with micro performance, which focuses on fine-tuned optimizations at a smaller scale. Macro performance is about making strategic decisions that affect the overall system, such as data structure choices.

💡Micro Performance

Micro performance is the fine-tuned optimization of individual modules or functions within a system. The video suggests that premature optimization often occurs at this level and can lead to unnecessary complexity. It emphasizes the importance of measuring and understanding the actual impact of micro optimizations before implementing them.

💡Data Structures

Data structures are a fundamental concept in computer science that determine how data is stored and organized. In the video, the importance of choosing the right data structure for performance is highlighted, as it can lead to significant improvements or detriments to the system's efficiency.

💡Profiling

Profiling is the process of measuring and analyzing the performance of a program, particularly to identify bottlenecks or hotspots where the most time is spent. The video uses the example of Grand Theft Auto V online to illustrate how profiling can reveal unexpected performance issues and lead to significant improvements.

💡Optimization

Optimization in the video refers to the process of improving the performance of a system or code. It is presented as a necessary step when facing a real performance problem, and the video advises a measured approach, starting with significant changes like data structures and then moving to smaller optimizations if needed.

Highlights

Premature optimization is considered the root of all evil.

Performance discussions are often a waste of time due to strong feelings about performance rather than its actual importance.

Performance is part of a tradeoff triangle involving velocity (speed of adding new features) and adaptability (system's ability to change).

Focusing solely on velocity can lead to technical debt and hinder future development.

Adaptability involves writing code for easy changes and maintaining reusable, extensible components.

High adaptability can sometimes reduce velocity and negatively impact performance due to increased abstraction and indirection.

The balance between velocity, adaptability, and performance depends on the project's stage.

Mark Zuckerberg's choice to write Facebook in PHP, despite its inefficiencies, allowed for rapid development and growth.

Performance should not be the first problem addressed; it's important to be deliberate about optimization strategies.

Performance issues can be categorized into macro (design-level) and micro (fine-tuned) performance.

Premature optimization often occurs at the micro level and may not be necessary given the speed of modern computers.

The difference between pre-increment (i++) and post-increment (++i) operators in C++ is negligible after optimization.

Function calls are often not the root of performance issues, and readability should be prioritized unless proven otherwise.

Data structure selection is crucial for performance optimization, as it can significantly affect the outcome.

Profiling tools can identify hotspots in code, guiding developers to areas that need optimization.

Memory usage and allocation patterns play a significant role in performance, with proximity in memory leading to faster execution.

Optimization should begin with addressing real performance problems, making significant changes, and then profiling and analyzing code.

Transcripts

00:00

I truly do believe that premature optimization is the root of all

00:03

evil.

00:18

Most conversations about performance

00:19

are a total waste of time, not because performance isn’t important,

00:24

but because people feel very, very strongly about performance.

00:28

I tend to think of performance as an element of this tradeoff triangle.

00:32

Velocity, here, is how quickly one adds new features and adaptability

00:36

is how well the system can change to new requirements.

00:40

You might think that velocity and adaptation go hand in hand, and they do.

00:44

But sometimes one can hurt the other.

00:46

Focusing on pure velocity means hacking together something as fast as possible.

00:50

Taking the shortest path to the feature.

00:53

Future maintainers be damned, and at the beginning

00:56

you'll gain a lot of immediate velocity as you hack things together.

01:00

But as you do this, you're creating a bunch of technical debt

01:03

which will weigh you down to a halt.

01:05

Adaptability is about writing

01:07

the code in a way to enable changes as new requirements come in.

01:11

Think creating reusable extensible components,

01:14

beautifully crafted interfaces and configurability.

01:17

With the right designs, you can increase velocity by reducing

01:20

the size of changes needed to add new features.

01:23

But if you make things too adaptable, you also hurt velocity.

01:27

If you had a crystal ball and could see the future,

01:29

you'd be able to know exactly which use cases you'd need to design for

01:32

and also which ones you don't need to design for.

01:35

But when you

01:35

build a highly adaptable system that can adapt to a whole bunch of cases

01:39

that never happen, then all of that just ends up being a big waste of time.

01:44

With highly extensible systems, you also hurt performance.

01:48

Adding lots of adaptability naturally adds more abstraction and indirection

01:52

in your code, which usually has a negative impact on performance.

01:55

But this trade off is usually worth it because of the adaptability it allows.

02:01

You might think you always want something in the middle,

02:03

but I actually believe this depends on the stage of your project.

02:08

A feature complete game

02:09

pushing final ship date would focus on performance.

02:12

You might be okay with reducing the velocity of new changes

02:15

and adaptability in order to squeeze out the last little bit of performance.

02:19

But when a game is at earlier in development,

02:21

you might focus on getting more features out quickly or

02:24

building up an extensible system that lets you tweak the game freely.

02:29

When Mark Zuckerberg wrote Facebook, he did it in. PHP.

02:32

PHP is an awkward language, to say the least,

02:36

and it gave Facebook a whole slew of scaling issues as Facebook grew.

02:40

They ended up making a PHP to C++ compiler.

02:44

And later, when that had a performance plateau,

02:46

they basically created a dialect of PHP called Hack.

02:49

But would Zuckerberg be better off if he wrote it in highly optimized

02:52

code to start? No, I don't think so.

02:56

I think writing in the inconsistent, inefficient

02:59

PHP was the right move because it meant that he could build Facebook quickly.

03:04

Once performance

03:05

became a real problem Engineers went to solve it.

03:08

If he focused on choosing performance over velocity, it's not clear

03:12

that Facebook would have taken off and Zuckerberg wouldn't have had the privilege

03:16

to visit Congress as much as he has.

03:19

So the key with the triangle is

03:21

that performance is a problem, but it's not usually the first problem.

03:26

And you should be deliberate about which way you're leaning.

03:30

It's useful to differentiate performance issues into two camps:

03:33

macro performance, which I think of as design

03:36

level performance - these are system wide performance considerations;

03:40

and micro performance, which is fine tuned performance.

03:44

This could be looking at the perf of a single module or function.

03:48

Premature optimization usually occurs for micro performance.

03:52

This is typically where someone comments in a code review that you should do X

03:56

instead of Y because x is faster than y, but computers are really fast.

04:01

I have some python code that helps me generate the code animations

04:04

for this series, and that python code do some horrific stuff.

04:07

Each character,

04:08

my code is basically in a big array and on every frame

04:10

I just linear search through it to find the relevant characters,

04:14

and it still renders

04:15

me out of video fast enough that it's not worth making it any faster.

04:19

At the end of the day, you're writing code to solve a real world problem

04:23

and typically getting to the solution of that real world problem faster

04:26

is better than solving the problem slower with faster code.

04:31

Let's look at a few examples of premature optimization.

04:35

In C++, there's two operators that both let you increment a variable by one.

04:40

Proponents of ++i.

04:42

will say it's faster because technically i++ needs

04:45

to make a copy of the value since when it's part of a larger expression,

04:49

the incrementation needs to happen after the expression is evaluated.

04:55

Oh man, this one gets me.

04:58

You might say, but CodeAesthetic if it's faster.

05:02

Well, then why don't you just do it?

05:04

Why don't you just always do ++i?

05:07

Because sir/madame.

05:10

Think of the precedence.

05:11

I don't know for a fact that it is indeed faster.

05:14

And so should I blindly trust Daryl because he thinks it's faster?

05:18

No, of course not.

05:19

So now I need to go through and do a thorough and lengthy investigation

05:23

into the distinction between i++ and ++i.

05:27

Now, I've got to go and disassemble it.

05:29

I write a for loop with the pre increment operator and look at what it does.

05:34

Okay.

05:34

Here it loads the value from i into a register, EAX, then

05:39

adds one to it and then puts the result back into the memory for i.

05:43

Okay. Seems straightforward.

05:44

So let's look at post increment and it's identical.

05:49

You get the same code for both. Okay.

05:51

But this is just an int.

05:53

What if it's an iterator?

05:54

We have a vector which is just C++ versions of a list

05:58

and you can access the elements of the vector through an object

06:01

that overrides the two ++ operators.

06:04

The post one would need to make a copy, right?

06:08

Well, let's look.

06:09

Aha. Gotcha.

06:11

Look at the difference between these two long functions.

06:13

You'll notice that this one calls the function for the post

06:16

and this one calls the function for the pre.

06:19

And the post version of this has four extra assembly lines

06:22

to make a copy of the iterator and it calls into the other operator.

06:27

So you got me.

06:28

It does cost a little bit more to do i++.

06:32

Except when you turn on optimization, those function calls completely disappear

06:36

and you end up with identical code for both cases.

06:40

So now the answer is a thorough

06:42

and totally satisfying: maybe.

06:45

We must measure.

06:48

After measuring the difference on my MacBook

06:50

the speed of the slowest increment is 3.4 nanoseconds.

06:54

If you notice a little counter below, this is how many worst

06:57

case increments have occurred since I started talking about this.

07:03

Is my increment really going to execute this

07:05

many times?

07:09

Is my code going to even ship?

07:13

Will my startup fail?

07:16

I spent 3 hours on this investigation.

07:20

Could have spent 3 hours building the best

07:22

dog walking app known to humanity.

07:27

Does anything really matter?

07:31

So my point with this is that you should ask

07:34

yourself, is this conversation even worth it?

07:37

If it brings you joy to figure out which is technically faster, go for it.

07:41

But I don't think this should end up on a code review because it doesn't matter.

07:45

Otherwise, I have to go through this whole thing again.

07:47

I like i++ because I think it looks prettier.

07:50

And until someone tells me that we can't ship because our app is too slow

07:54

and we've measured that the solution is to change all of our i++s

07:57

to ++is, I'm sticking with it.

08:00

This also applies to functions.

08:02

In many of my previous videos,

08:03

I've argued about using extraction to help readability.

08:08

Some have argued that functions are expensive,

08:10

but rarely has the cost of a function been so significant

08:13

that removing the function is the solution to a performance problem.

08:16

And in the rare instance that it was a solution, it doesn't mean

08:20

that it's proof that it's worth the readability loss by default.

08:25

A big issue with making performance rules to follow

08:28

is that often the rules have a lot of exceptions.

08:32

Here we have a class that keeps track of the currently logged in users.

08:36

Our first implementation just has an array which contains a list of users.

08:40

Then we have this loggedIn() method which returns

08:42

whether or not the user's logged in.

08:44

It has a simple for loop

08:45

which looks through the list searching for the current user.

08:48

During a code review Someone says, “Hey, this thing is slow.

08:51

You shouldn't just search the list of users like that.

08:54

It's slow, and you should use a set instead” - a data structure

08:57

that lets you look up unique elements much faster.

09:01

But when you measure the difference, you actually find that set is slower

09:04

when you only have a few users log in, which is normal for your system.

09:08

I’d speculate this is because our integers in the area

09:11

right beside each other in memory and the implementation of set likely

09:14

allocates objects in lots of different places in memory - reducing cache hits.

09:18

But like I said before, until you've shown that this function specifically

09:22

is the leading cause of your performance issues, go with what's more readable.

09:27

So I do think that

09:28

set creates cleaner, more readable and less bug prone code.

09:32

So I'd go with that.

09:34

There's so many factors to performance that there's only one way

09:37

to properly optimize: measure., try something, measure again.

09:42

Measuring is critical because like we just showed your assumptions

09:46

of what will make things faster, can make things slower.

09:49

You can help form a hypothesis of how to make things better by doing an analysis.

09:53

Data structure selection by far is the most important,

09:56

and that's because choosing the right data structure can give dramatically

09:59

better results over the wrong data structure. When

10:02

dealing with performance issues.

10:04

I tend to think in terms of 80% moves first.

10:06

What are changes that could have an 80% reduction?

10:09

And often the only thing that can get you that far are data structure changes.

10:14

Once you've implemented them and measured the difference

10:16

and still see it's not good enough, then you have to look at the smaller things.

10:20

You might not know where to start, and that's

10:22

where you'd want to look at the profiler.

10:25

A profiler can tell you what are the hotspots of your code.

10:28

It can point out functions that are the most expensive.

10:31

There was kind of a funny story about Grand Theft Auto V online.

10:34

It was so slow to launch that one player who goes by t0st wanted to figure out why.

10:39

Even though they didn't have the source code

10:40

t0st used a profiler figure out why it was so slow.

10:44

It turned out

10:45

pretty much all of the time was spent parsing and processing a JSON file.

10:49

A patch to fix just that one part improved the load time by 70%.

10:53

That's the funny thing with performance is that sometimes when things are slow,

10:56

it's just one silly thing slowing everything down.

10:59

For GTA V all someone had to do is look.

11:04

After data structures and profiling

11:05

then you just have to start making educated guesses,

11:08

thinking about how your code

11:09

could be working underneath the hood and find ways to simplify stuff.

11:14

A lot of performance comes from how your code uses memory.

11:17

Allocating memory, which is done whenever you make a new object or array,

11:20

can slow things down in critical sections because the system has to find

11:24

free chunks to put stuff.

11:26

You'll get a lot of speed for having critical elements close by in memory

11:30

because things are much, much faster when they're in the CPU's cache.

11:34

But again, I wouldn't worry about these things

11:35

until you know you have a performance problem and have tried other things first.

11:40

So when you optimize:

11:42

first, have a real performance problem, then measure it.

11:46

Try to make 80% moves by swapping data structures

11:49

or moving to a well-known faster algorithm.

11:52

Profile and find hotspots.

11:54

Then, worst case, start thinking about what your code is doing under the hood.

12:01

What are some interesting cases you've hit while

12:03

trying to make code faster?

12:07

When a video of mine is getting long, I sometimes cut sections and post them

12:10

as deleted scenes on my Patreon. For this video, we talked about micro optimization,

12:15

but there's a section on my Patreon about macro optimization strategies.

12:18

If you're curious.

Rate This

5.0 / 5 (0 votes)

Verwandte Tags
SoftwareDevelopmentPerformanceOptimizationPrematureOptimizationVelocityAdaptabilityTechnicalDebtCodeDesignDataStructuresCodeProfilingIncrementOperatorsFunctionUsage
Benötigen Sie eine Zusammenfassung auf Deutsch?