3 ms·
Cleaning up code requires way too much human judgment for that to be possible any time soon.
by crdoconnor 10y ago
Cleaning up code requires way too much human judgment for that to be possible any time soon.
- js8 10y agoWell, I have this idea that, pretty much, smaller programs (in the sense of Kolmogorov complexity) are well-written and thus maintainable. More precise argument is as follows: You take a very simple functional language, like say, Haskell Core. Let's consider a large and representative enough (finite) set of programs in this language. We find the smallest possible (or very small) representation of this set. This will involve definition of some commonly used functions. Let's call all the functions that are in this representation "the basic library". Then, for a new program, we can try to find shortest possible (among those you're able to consider) representation, such that, using the functions from the basic library comes for free (so you don't count the size of functions in the basic library towards the total size of the new program). So if we can write a program that would be able to find smaller representation using definitions (functions) that we already generated in that representative set, I think it would essentially automatically refactor code to be more readable and maintainable.
- crdoconnor 10y agoThis might get you the shortest code but it wouldn't necessarily get you the cleanest code. There's often a trade off between coupling and terseness which requires (human) judgement in order to balance the competing concerns correctly. There's also the matter of using appropriate metaphors. I have a feeling that a "cleaner" optimized like this would get you a program full of the equivalent of perl one liners, assuming it's even possible.
- js8 10y agoI don't know how the generated code would look like, but I am sure humans wouldn't like it. But that's not a big deal, because for every piece of code out there, there is somebody who doesn't like it. Proper metaphors (better call them abstractions) would be generated at that "basic library" creation step. Basically those are functions that are commonly useful. Some of them would correspond to abstractions known by many programmers, some of them would be different, but altogether would let you write more compact code (because that's what they have been selected for). Ultimately, knowing abstractions amortize and ease understanding of the code that uses those. We humans do the same thing - the code that is easy to understand is the code that uses commonly known abstractions, such as control structures, standard library functions, etc. What makes this possible is that we hold these shared abstractions in our heads, and create them as a part of programming culture by working with different code bases. There is no trade off. You cannot write a terse function with high coupling, because then you cannot use the shared abstractions very efficiently inside it, nor you can build other functions easily by reusing this function. So terseness IMHO behaves very differently when you account for the fact that you can create new definitions, and you put those definitions to use. (And especially if those definitions come from some "basic library" for free - they are not included in the cost that you have to pay to understand the program - because they have already been understood.)
- crdoconnor 10y agoAbstractions are different to metaphors. You can have an abstraction with a name 'x' that you can use to send messages over an SMTP server. The metaphor could be "mailer", "mailbox", "email sender", "postman" or many other different things with subtly different implications. Moreover, the "basic library" creation step that you allude to the point where you decide where the borders between different modules of code lie. Creating those borders at the appropriate point - deciding the coupling - is arguably the most important part of refactoring and the part (I) have found hardest to clean up in legacy code. I am currently rewriting a library which in retrospect I now realize should have been two libraries. "You cannot write a terse function with high coupling" Oh, you absolutely can. In fact, after a certain point terseness tends to correlate with higher coupling. There is often a trade off to be made between coupling one block of code to another (e.g. introducing a dependency) and sacrificing terseness.
- js8 10y ago> Abstractions are different to metaphors. You can have an abstraction with a name 'x' that you can use to send messages over an SMTP server. How is that different from a function (or set of functions) that abstract the technicalities of sending messages over SMTP? I am not sure why specific metaphor is so helpful here. I don't think it helps in understanding the function, on the contrary. > Moreover, the "basic library" creation step that you allude to the point where you decide where the borders between different modules of code lie. Not quite. The important thing to understand is that I am not optimizing for size of a single program, but large set of different programs. The same thing that humans do. > There is often a trade off to be made between coupling one block of code to another (e.g. introducing a dependency) and sacrificing terseness. Well, I understand "high coupling" differently than you, then. For me, it means things like doing different unrelated things in a single function (so the result is that it's harder to reuse it). It doesn't mean that you cannot call other functions. I don't consider a function that avoids a library call, instead inlining the functionality, to be well-written. (If that's what you mean by the trade-off - maybe some example would help.)
- 10y ago