Win a copy of Head First Android this week in the Android forum!

Christian Clausen

+ Follow
since Jun 04, 2020
Cows and Likes
Total received
In last 30 days
Total given
Total received
Received in last 30 days
Total given
Given in last 30 days
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Christian Clausen

Thanks for all the great questions and discussions, everyone! I'll be signing off for now. If you want to reach me for whatever reason I am on twitter, twitch, medium, or github, all with the username "theDrLambda". Thank you, Code Ranch, for having me.

Same here! We really do agree on quite a few things.

I think we agree on most things about software development, Junilu, you seem very knowledgeable and we share a lot of the same references. We share the same values, we just have different ways of teaching them. Your way is right for some people, and I hope mine is for some as well.
Congratulations to the winners, I hope you'll enjoy the book.
Such an interesting discussion!

There are so many points I would like to comment on, so I will probably miss some.

How do you approach code refactoring in the real world?

Firstly, in the real world, I always treat the team as the only method of delivery, which means that the biggest refactoring effort comes from talking with the team, and deciding on a common level of quality, and then holding each other to it.

That being said, if by "real world" you mean I start with a large chunk of unrefactored legacy system, then I have two answers depending on the context. If you are about to make a change in the legacy code, my answer would be to do refactoring before implementing changes. It comes from the Kent Beck quote:

First make the change easy, then make the easy change

I have a section about that in the book:

If on the other hand, you are just annoyed that the legacy system slows you down, then I discuss this in chapter 9 (which I am working on now). First I isolate the legacy code, then I add monitoring, so I can see which parts are being used a lot, and which not at all. Then, because I like easy decisions, I start with the most and least used parts, and either eliminate, refactor, or rewrite them. Note: this is simplified, but you can look up the detailed version in the book in a month or so.

And everything is iterations in software, the shorter the better.

there is NEVER a perfect code

Actually, I like to say that code can be perfect for a specific change, that is some change is as easy as possible. This means if you know the direction the software is taking, then the code can be perfect for that. Of course, in practice, the direction is not entirely known, and also changes. But based on this principle I tend to spend more time refactoring parts that change often.

"refactoring" sprint

Please don't do these, they will be a nightmare, both from all the merge conflicts, but also for the customer who does not see any value. Another problem with this, following what I write in the book, is that we can only deliver (push to master) once our code is refactored, so putting this in a separate sprint means we cannot put any code on master before this sprint.

there's a chance that inexperienced folks get too carried away and get too "theoretical"

I totally see where this is coming from, however, people grow so much doing this. Going crazy and making some small piece of code (like the guilded rose kata) totally gold plated, refactored over the top is an excellent exercise. Once or twice. Of course, we should not spend all our time doing extreme gold plating, some things will never change once written, and therefore require no refactoring at all. But there is a lot of learning and growth in doing it a few times in the beginning.

Rename, Extract, and Compose Method

These are definitely powerful, but I am missing something that introduces classes in this: Replace type code with classes, introduce strategy pattern, encapsulate data.

his recommendation to wait a while before refactoring

I just want to clarify that I only mean wait until you are ready to push your code to master, which I think you should do every day. This is because while we are writing the code it is often quite fluent which means we can change data structures or approaches easily. I don't want to refactor the code to support some algorithm, if I then change my mind and have to undo the refactoring. Only once I have the desired functionality mostly locked down I start refactoring.

Copy/Paste programming is grounds for immediate termination of employment

I know this is a joke, I just want to go on the record and say: there is a place for c&p while working, just not when you deliver (push to master). It is a super quick way to get something up and running, and refactoring should remove the duplication anyway. Copying something you don't understand should be grounds for termination.

I think you meant "peer reviews" but "pair reviews" works

I love synchronous peer review (ie. pair or mob programming). However, I am not a fan of blocking peer review (ie. pull requests), because they prevent continuous integration, which causes bad merges, and longer lead time. But this is running off a tangent far from refactoring.

the average "experienced guy" in large corporate settings [...] has practically little to no experience in refactoring or unit testing

This is what motivated me to contact Manning.

Challenge accepted

Let me know how that goes, I am very curious!

capture all potential improvements

Not all improvements are cost beneficial. One of my common pet peeves is when people show me some highly optimized code, which has become completely unreadable in the process. I have to be pragmatic in my job, so I usually say that improvements should be guided by usage statistics. Notice, having a well-refactored code base is not an improvement, it is a necessary condition to keep high velocity, and therefore should be part of developers daily work.

delay refactoring until you're ready to deliver is just not in line with the approach recommended by other experts

If you consider that by deliver I mean the change (ie. push to master), not the product, then I don't agree, the approach I recommend nicely aligns with other experts' approaches, in particular red-green-refactor. I just added a few more steps, like push to master, spike, and work, which were all present although implicit in other approaches.

there may be valid business situations where the business can tell developers to forego refactoring

Like if the software is scheduled to be decommissioned.

then sure, skip refactoring

* delay, not skip.

accumulating debt becomes a liability

Here I take Robert C Martin's opinion: a mess is not technical debt. Reference

Hi Junilu,

Unifying code to exploit structure is actually the entire point of chapter 5 of the book. I'll give a short teaser here: Extract method applies mostly when the duplication is inside methods which is usually when we think DRY. However another case could be where we can make two consecutive else-if bodies be equal, in which case we can join the conditions and get rid of one of the bodies, this expresses a connection between the conditions, which can then enable other refactorings. You can also have duplication in structure, such as two classes which are almost equal, which can be joined. Another case is when the control flow is duplicated, but with different method calls somewhere, in which case we can join them by utilizing a strategy pattern.

In general, I think DRY is dangerous because the mnemonic is too powerful. I've seen people get obsessed with trying to eliminate everything that looks like duplication, even when the code is supposed to be independent. There are multiple cases in which DRY is counterproductive, which I go into more detail with in a recent blog post ( There are probably more situations when DRY is the right strategy, but we must not forget: there is no universal truth.
Hi Lucian,

Thanks for your question, and sorry for the slow response time.

This book is intended to be very pragmatic as the primary target is people who have no prior exposure to refactoring, so I focus on giving them as much useful knowledge as I can without overwhelming them. Therefore I do not discuss different approaches to refactoring in-depth, although I might mention them in passing, so curious readers can go and research them on their own.

Regarding testing, I discuss it very little in my book for the same reason as above. Refactoring, by any definition, cannot change external behavior. So how can a test fail? I see a few ways refactoring can cause an existing test to fail. The first way, as Junilu said, is if something went wrong in the process of refactoring. This would be my first instinct and the first thing I investigated. Often it is just some human error or oversight, so if the refactoring was quick I would probably just reset my branch and do it again.

The second way is if the test is not in fact external. That is we can make refactorings that are breaking interfaces, as long as we have control over all the call sights. In this case, because the test is not external it should be treated as any other code while refactoring, and therefore it should be fixed in the same way other calls are.

The third way is if our tests are dependent upon internal structure, like a performance test. These are not explicitly connected to the code, so they are easy to overlook when refactoring. If you discover such a test after doing some refactoring you should investigate whether the test is still relevant and if it is then roll back the refactoring.

Hope that was useful
Thank you, Dinesh, for the kind words 🙏
Hi guys, I want to answer all the questions, but I have to hit a deadline. So I'll check back on Monday, and see if I can reply to all the questions!
The example was mostly meant to illustrate the difference between brief variable names and descriptive ones. Whether they were good names or not was not important for my reasoning. Naming is notoriously one of the hardest things in computer science. Names are also highly dependent on context, which I did not want to dwell on

However, if the question of brevity is not minded on naming but on duplication -- as Jorge suggests -- it is another question entirely. Usually, code duplication is a hint at some unexploited structure in the code, in which case it goes away through refactoring. Rarely does this make the code smaller.

Thank you. In my workshops and through my consulting I take a much more holistic approach, and coach both testing, mobbing, Git, monitoring, architecture, you name it. But I am a firm believer in learning in isolation
I only mention version control briefly in the book. I think it is an amazing tool, and am actively trying to use it as much as possible in my own work. However, in the interest of not overloading or distracting the reader, I don't go into any technical Git. I was nervous even writing about "diff" because I don't want to teach Git in this book. I strive to keep my message as clean as possible

I do write about Git on my blog though, including recommending doing an interactive rebase before delivering, so the history reflects the story you want it to.
The last paragraph of chapter 1 attempts to achieve exactly this:

Also note that because we focus only on learning refactoring, and we have a safe
environment, we can get away without automated tests — but this probably is not true for
real systems. We do so because it is much easier to learn automated testing and refactoring

My fear is that people will (naively) take what you wrote in your book out of context and think that refactoring without tests is fine in real-world development situations, not just while learning how to do refactoring

Yes, I think this is correct. As much as I would like to I cannot prevent people from making poor decisions. Even with all the arguments for testing in Fowler's book, people still ignore it. Even when a large part of the industry preaches that it makes development both faster and safer, some people still ignore it.

The same btw. is true for pair and ensemble (mob) programming, which I also think many people would benefit greatly from, however I would never claim you can't learn refactoring without it. ;)

It's not about "feeling" safe, it's about being safe

It is about feeling safe. As Djikstra said, "tests can prove the presence of bugs, not the absence". You gain evidence through tests, however, to be safe you need formal machine-checkable proofs (or at least that is state of the art at present).
TDD (and automated testing) is one approach to get the level of quality you desire. There are others, like proving correctness. I don't think anyone of them is universally the appropriate one. It depends on the context. As a consultant, I coach teams on TDD if they find that is right for them. The purist in me wishes we could prove everything correct, and never have bugs again, but sometimes that is too expensive. Then I wish we could test everything, but sometimes that is too expensive too. Then I wish we would make completely fault-tolerant systems, but ... you get the rest.

No matter what level of quality you desire, and no matter the strategy to get it, the refactoring patterns and rules stay the same. This suggests to me that they can be learned separately.
Hi Junilu,

Can you make mistakes while refactoring? Sure. Can you make mistakes while coding? Yes. Testing is a business decision, not a technical requirement. If you work in an area where errors mean little to no damage you may not do any testing at all, if you work on a billion-dollar Mars rover then testing is not nearly sufficient to get the safety you need so you do proofs instead. As I mentioned elsewhere, I am not against automated tests by any means, I just think you can learn refactoring without having to learn (or know) automated testing.