Live data from Hacker News

Refactor vs. Rewrite

remesh.blog

111–120 of 123 posts

Re: Refactor vs. Rewrite

#111

IME whether you rewrite or refactor, the lesson is the same: You have to grind your way into the good architecture. It doesn't become good because the code is fresh, but because you have battle scars to show. And a success story in that case comes from having a complete learning loop. In a lot of orgs the learning itself is argued against for one reason or another - development proceeds with as little feedback on qua…

"Grind" your way into good architecture? Good architecture is designing, not trial-and-errored. The only grinding I do is mental before I type a single letter of code.

So all the code you’ve ever written was perfect in every way from day one?

You’ve never made a suboptimal choice?

And never made a mistake?

Re: Refactor vs. Rewrite

#112
post #12

Earlier quoted context omitted.

I feel like you have denied the existence of people who are capable of writing down a good architecture on the first try, without all the grinding.

No good plan survives first contact with the enemy... Less pithily, the good architecture will almost certainly end up with arbitrary patches and madness after 2 years of active use, if anyone cares about it at all... And then somebody will join and say 'This is a mess, we should refactor and/or burn it to the ground.'

It's funny to say, but I can't agree. I've designed and implemented many custom systems for which there was never a predecessor, and not only did it work splendidly at first release, but have been extended and enhanced many times over the years with no refactoring. Many of these systems have been extended enough to start taking over other systems that were never intended.

Design a system to be modular from the very beginning with only the most fundamental of API signatures and you win. Many of these signatures may even no-op for years, but because they're fundamental to the problem, you know there could be a case where they're needed.

I've never had a failed or late project and most of my projects are ones that were assigned to me because no other team would touch them due to all of the attention and required SLAs.

Re: Refactor vs. Rewrite

#113
post #94

Earlier quoted context omitted.

Any halfway decent static type system would capture that nullability and prevent accidentally using a null value without checking, so you seem to have slightly undermined your own argument here.

Static type systems don't necessarily prevent accidental null value usage. Not sure where you get that impression? However, for initialized variables, nulls (or None) was an example I used as that is the common one in python and conveys the point rather than language details. All of the "decent static type" systems I'm aware of have the same issue with undefined values that break behavior. E.g. zero's as integers, em…

Static type systems don't necessarily prevent accidental null value usage.

The better ones do.

Some languages with static type systems, notably C and its descendants, have reference or pointer types that are nullable by default. With the wisdom of hindsight, that design decision is regrettable; Tony Hoare himself famously called inventing null references his “billion-dollar mistake”.

There are safer alternatives. For example, you can have a type that makes optionality explicit, so it contains either nothing or a single value of some known type. Before you can work on the contained value, if there is one, you must deliberately extract it; the type system will prevent you from accidentally using the optional value in place of the contained value. In Haskell, this type is called Maybe a. Rust has Option. In OCaml, it’s 'a option.

All of the "decent static type" systems I'm aware of have the same issue with undefined values that break behavior. E.g. zero's as integers, empty strings.

Again, with a sufficiently expressive type system, you can encode properties such as a list being non-empty in your types. This lets you prevent illogical actions like trying to take the head of a list with nothing in it. You sometimes see these techniques if you’re working on high reliability systems with formal verification.

You can also handle edge cases safely by replacing a partial function that is undefined for certain inputs, such as dividing by zero or taking the head of an empty list, with a total function that gives you back an optional value as described above.

Re: Refactor vs. Rewrite

#114
post #101

Earlier quoted context omitted.

If the business model is boring, you’ll need complex technology to compensate. If your business model is complex like in a lot of enterprise software, you should strive to keep the technology as simple as possible. Simple doesn’t mean to not use complex or cutting edge things IMO but to be conservative in using things that push the cognitive load of your collective team. A 10 person company probably doesn’t need a K8…

"If the business model is boring, you’ll need complex technology to compensate." Could you elaborate on this? What is the complexity compensating for? Boredom of the developers?

Compensating for competitive factors both for customers and for investors to care that you're worth putting money into. If you don't have something that makes you special from your competitors, what's the point of you existing? That's just a small business like a mom & pop grocery store or a boutique web design agency (both of which are endangered species). If you don't have any competitors, then you'd better have something of value, correct? Or is one's company Theranos et al? In enterprise, the competitive factors can be things like relationships to certain vendors and this can supersede technology secret sauce and is as equally valuable as a trade secret. You get overly-complicated business models that become a house of cards like Enron or WeWork which make unsophisticated investors think they know what they're doing, and as engineers we are attracted to our own biases toward shiny new things that might solve all our headaches.

But you're also right in that some technology companies basically hire developers to give them resume / vanity projects that don't necessarily help the business be competitive directly. However, that is another ball game that's into global brand territory which follows rules more of religions and politics than of capitalism.

Re: Refactor vs. Rewrite

#115

Earlier quoted context omitted.

More expressive type systems might make refactoring safer , but they don’t necessarily make it easier . The former happens because it’s harder to change something encoded in the types accidentally. For the latter, it should be easier to change something encoded in the types deliberately, but often the opposite is true.

No, it's really easy: change a definition's type, and then fix each type error. The errors give you a guided tour of the codebase that's impossible to get without static type checking.

You still need to fix all of those type errors, though. As we encode more information within our types, the effort to maintain them naturally tends to increase as well.

Your profile indicates that you work with Haskell. In Haskell, we often encode possible effects explicitly in types, while many other languages do not restrict effects to the same degree. This provides a degree of safety in Haskell that those other languages lack. However, it also means that if refactoring moves the place where some effect can be caused, that may require a change to the types that propagates widely through the system.

For example, suppose we have a system where the high level code is wrapped in some logging monad. We decide to refactor so that some of the log writes move to a much lower level, perhaps so we can then add more detailed information to the logged messages. At this point, the entire call chain down to where the logging will be done is infected by the logging monad. This is perfectly correct in terms of type safety. It is also work that would be entirely unnecessary if we were performing an equivalent refactoring in a language that did not encode so much information in its types in the first place.

Re: Refactor vs. Rewrite

#116
post #60

I think everyone is missing the big point here: they current implementation was in an untyped language and so refactoring was just to hard. Use languages with good type systems and then refactoring is easy, and always the correct technical choice. Let me say that again, the killer app of type systems is that no mistake can "total" the code.

The lack of static typing does not make refactoring incredibly hard or difficult. In fact, I would argue it's even easier due to the way dynamically-typed languages pass around data. Really, as long as you follow some basic rules and don't propagate complexity into your system too-much, refactoring is a breeze. When I do it, the types are inconsequential almost. The things I do worry about when refactoring is develop…

I mainly work in languages with good type systems. But I've also contributed a bunch https://github.com/mesonbuild/meson/pulls?q=is%3Apr+author%3... I can assure you despite all the unit tests refactoring just takes way, way, longer.

Re: Refactor vs. Rewrite

#117

Earlier quoted context omitted.

No, it's really easy: change a definition's type, and then fix each type error. The errors give you a guided tour of the codebase that's impossible to get without static type checking.

You still need to fix all of those type errors, though. As we encode more information within our types, the effort to maintain them naturally tends to increase as well. Your profile indicates that you work with Haskell. In Haskell, we often encode possible effects explicitly in types, while many other languages do not restrict effects to the same degree. This provides a degree of safety in Haskell that those other la…

Yes, I work in Haskell. As you say we have lots of types---and type errors. But refactoring is still insanely easier. I'm kinda infamous for bundling a refactor with every feature, in fact, because the extra work is just so minimal I cannot help myself.

Re: Refactor vs. Rewrite

#118

Earlier quoted context omitted.

Having a type system enables zero risk automated refactorings, even complex ones and make them a no brainer. Not having that builds a reluctance to do even simple refactorings. A good example is the simplest possible refactoring: renaming things. I was doing this in pycharm on a simple python project the other day and it proposed modifying just about all dependencies on the classpath because it couldn't tell apart th…

It seems to me that what you’re talking about there has more to do with having clear rules in the language for scope and modularity than to do with the type system.

Those clear rules are called the type system. The fact that it's static means the same stuff that the compiler uses to tell what is what may also be used to build syntax trees to facilitate transforming your code base from one valid state to another. It's impossible to do that with dynamically typed languages and at best you get some partial guarantees combined with some string replacing.

Re: Refactor vs. Rewrite

#119
post #92
post #57

Earlier quoted context omitted.

Have you heard of our lord and savior, Domain Driven Design? Here are the blue and red books.

Are these books Evans(blue) and Vernon(red)?

Yes. I think Vernon's is the best as it has more emphasis on the process and organisation instead of the code.
Post reply on HN