The Second Edition of “Refactoring”
martinfowler.com
martinfowler.com
http://www.drdobbs.com/joltawards/2006-jolt-awards/187900423...
The book was an easy read and was an efficient use of my time. I expect that rewrite in Javascript will further improve the information density.
I distinctly remember one of the things in the book, which in retrospect isn't even really a refactoring, called something like "null object". The idea was that if you were going to return null from a function (e.g. get student by ID but that ID doesn't exist) then you could instead return a concrete singleton object that represented null. That way, if you forgot to check for it then at least your program wouldn't crash. Now, the merits of this idea are debatable and I don't think I've ever used it in the years since. But I strongly remember thinking at the time that it was the only idea in the book that wasn't totally obvious.
There was a good chapter early on about testing, which I think was my first exposure to that idea. It was a bit brief but that's not a surprise given it was a bit of a digression from the main topic. A whole book on that might've been quite a bit more interesting.
If I forgot to check for null (or missing data) then I would rather have my program to raise an exception (to prevent data corruption). Then my error handling code will email that exception to me. I will analyze exception message (NPE) and stack trace. Then I will fix my program and deploy it to production.
This is basically a workaround for a defect of certain typed programming languages that allow null everywhere.
Worst mistake of computer science.
https://www.lucidchart.com/techblog/2015/08/31/the-worst-mis...
The problem with "everything can be null" is the type system is prevented from finding very common "you can't do this thing" errors.
Without it, everyone uses null objects (or Maybe, a generic for of this) and there are no segmentation faults/dereferencing errors. (Yes there can be other sorts of errors, but the problem has been made far better.)
before:
public Student GetStudentById(int id)
{
var record = db.findStudentById(id)
if (record == null) return null;
return new Student(record.id, record.name, ...);
}
Then in say a student record controller class: public View Get(int id)
{
var student = getStudentById(id);
if (student == null) return View("NotFound");
return View("Display", student);
}
After: [ContractAnnotation("=> notnull")]
public StudentSearchResult GetStudentById(int id)
{
var record = db.findStudentById(id);
if (record == null) return StudentSearchRsult.NotFound;
return new StudentSearchResult(record.id, record.name, ...);
}
Then: public View Get(int id)
{
var student = getStudentById(id);
return new View(student.ViewName, student); // look no null check becase student.ViewName is always valid here
}
Note: of course this is entirely simplified for the purposes of example. Perhaps your real world example doesn't return null from the db, but a RecordSet with either 0 or 1 elements. Perhaps your db uses exceptions that you translate into results like this.The cool thing there is that you get tool support (from e.g. ReSharper) telling your that this is entirely safe to do without a null check and tool support when it's not.
There are many ways that this can be implemented that avoid an if result != null / == no value, often a map suffices.
Can anybody comment?
Second problem was that refactoring became much harder, because the tests were deeply tied to the implementation (are methods X, Y and Z called with such and such arguments?).
* using the definition of "integration" as "integrating components of the project", not "integrating with external services" (which is the definition I personally prefer).
I've seen a similar, entire book dedicated to database refactoring that had roughly the same pattern. Chapters named akin to "The Change Table Name Refactor" felt kind of bizarre, when what I was hoping would be contained was advice about refactoring large databases in practice (moving data to new service boundaries, etc). Practical advice on building systems to move data and such seems to be just missing
Trivial after the book exists, sure
The catalog misses out most of the interesting discussion
Refactoring helped me start to understand the 'why' and 'when'. Why is design A better than design B? When is it time to tidy up this code? Which choice will be easier to change later? That kind of thing.
e.g. linked list, hashes, lookup table, classes, counters, iterators, etc
(Not referring to books such as TAOCP which cover a few topics in-depth)
[1]https://en.wikipedia.org/wiki/List_of_data_structures
[2]https://martinfowler.com/eaaCatalog/
This is very interesting choice of language. I wonder whether typescript could have been a candidate as well. Although not as popular as JS, I believe most of JS community has migrated to typescript (due to obvious benefits) and it is more closer to a C-based language.
I suspect it was much like "Agile Web Development with Rails", which up until the most recent edition, listed DHH as an author
We're going through http://refactoring.guru at work right now, it's a nice modern version of Fowler's classic imo.
You think the majority of JS developers have switched over to TypeScript?
[0] https://2018.stateofjs.com/front-end-frameworks/conclusion/
Edit: Upon rereading I see you are talking about the book, not actual projects, so my reply is not all that applicable. Though I'd actually say that Typescript is much more understandable than JS to someone unfamiliar with both.
From that point of view, I see what you're saying.
When I first read Refactoring, IntelliJ wasn't released yet and refactorings still needed to be done by hand. Automated refactorings are so incredibly useful when it comes to improving code quality over time that I don't know what it was we did without them.
Types or not, the refactored code itself is still refactored.
Done by a tool or not, the refactoring in principle remains the same. The tool merely automates the transformations which defines the refactoring.
And in that sense types isn’t really essential to refactoring at all.
The more I think about it, the less it makes sense to bother about refactoring when you did not bother about type level guarantees in the first place.
Can refactoring tools miss something? Sure, but this holds true for various static languages too. Don't sell the nonsense of 100%. Find me a Java IDE that won't miss reflection calls. (Personally I can point to a tool for Java that moves the bar above 0, but it also isn't 100%.)
Just because you're used to shitty dynamic languages isn't a statement about dynamic languages in general or the possible tooling, anymore than being used to shitty static languages is a statement about static languages in general or the possible tooling. I also see someone conflating "dynamic" with "untyped"/"non-typed" -- there are very few untyped languages, let alone in wide use, "dynamic" doesn't mean the same thing.
I'm looking forward to the JS version of the book just for recommendation purposes because I hope it will put a rest to so many of these threads about refactoring in the absence of a static type system being somehow way harder or impossible.
Ultimately I think the discomfort is from fear, certain programmers practice fear-driven development. "What if the tool (or me, if I'm taking 5 mins instead of 5 seconds to do it) misses something?" It's the same fear with people who can't imagine refactoring without unit tests, but who need to refactor legacy code to get it under test. You can do these things, they're not particularly difficult, but if you're suffering from fear, I'm not going to convince you. Maybe a book + examples would though.
[0] http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91....
[1] http://wiki.c2.com/?RefactoringBrowser
Ralph Johnson: "We originally thought that the lack of static type-checking would make it hard to build a refactoring browser for Smalltalk. Lack of type information is a disadvantage, but the advantages of Smalltalk made it a lot easier to make a refactoring browser for Smalltalk than it would have have been for C++ or Java."
For example consider the thing you constantly see in Java where you construct an object then assign each property through a method. The type system will catch it if the property is not passed correctly.
In a dynamic language like JavaScript the same is better done with an inline object. The reason being that the type system won't catch it if there is a mistake, and so you want to go for the easiest way to write it. On the theory that less code is less maintenance.
However now it is hard to rename a property and be sure that your refactor is correct. Because where does a property come from? It could come from anywhere - over the network, from an API call, the name of a database field - it is easy to miss it.
Which means that not only should the refactor go in a different direction, but how safe you feel in doing refactors will also go in a different direction!
I’m just stating that there is nothing fundamental about code-refactoring which ties it exclusively to the domain of typed programming-languages, something I consider fairly self-evident.
I mean obviously one can refactor terrible code in any language to help improve its structure right?
That this remark would cause such sub-thread defending types in general (I never said they didn’t have value) has me honestly quite surprised.
https://www.amazon.com/Refactoring-Ruby-Addison-Wesley-Profe...
Also thanks to other posters who describe their view of the updates of content.