Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
coffeetable
Feb 5, 2006

TELL ME AGAIN HOW GREAT BRITAIN WOULD BE IF IT WAS RULED BY THE MERCILESS JACKBOOT OF PRINCE CHARLES

YES I DO TALK TO PLANTS ACTUALLY

hug the mods posted:

i have monthly contributions to rakudo core for over a year while programming stuff in it for over 3 years now
why would you do these things

Adbot
ADBOT LOVES YOU

Soricidus
Oct 21, 2010
freedom-hating statist shill
self harm is often a cry for help

qntm
Jun 17, 2009
Perl 6 intentionally confuses items and single-element lists:

code:
> (1, (2), 3)
(1 2 3)
> ((((1))))
1
> (1, 2, 3).elems.elems.elems.elems
1
A string, like any scalar, is a single-element list too:

code:
> "A".elems
1
> "string".elems
1
> "".elems
1
> "string"[0][0][0][0]0[0]
string
To get string length in Unicode code points, you do "abc".chars. Well, in the version I have installed that was the case anyway, but apparently that behaviour changed in the past month, so now you use codes to get length in code points and chars to get length in displayed graphemes. Substring operations also operate on graphemes. So:

code:
> "नि".codes
2
> "नि".chars
1
> "\r\n".chars
1
> "नि\r\n".substr(1,1).perl
"\r\n"
So string operations yield platform-dependent results.

If you call anybody in the Perl 6 community out on any of this, the standard defence is "Perl 6 is quirky! Why do you hate fun? Larry decided it one day and moved on, he has a degree in linguistics"

E: okay, that character was meant to be a special single character but apparently the forums dislike advanced Unicode characters in code blocks?

qntm
Jun 17, 2009
Perl 6 always does "what you'd expect" and also always does "the right thing". In the Perl 6 universe, these are (1) the same thing and (2) universal

fuck the mods
Mar 30, 2015

qntm posted:

Perl 6 intentionally confuses items and single-element lists:

code:
> (1, (2), 3)
(1 2 3)
> ((((1))))
1
> (1, 2, 3).elems.elems.elems.elems
1
A string, like any scalar, is a single-element list too:

code:
> "A".elems
1
> "string".elems
1
> "".elems
1
> "string"[0][0][0][0]0[0]
string
To get string length in Unicode code points, you do "abc".chars. Well, in the version I have installed that was the case anyway, but apparently that behaviour changed in the past month, so now you use codes to get length in code points and chars to get length in displayed graphemes. Substring operations also operate on graphemes. So:

code:
> "नि".codes
2
> "नि".chars
1
> "\r\n".chars
1
> "नि\r\n".substr(1,1).perl
"\r\n"
So string operations yield platform-dependent results.

If you call anybody in the Perl 6 community out on any of this, the standard defence is "Perl 6 is quirky! Why do you hate fun? Larry decided it one day and moved on, he has a degree in linguistics"

E: okay, that character was meant to be a special single character but apparently the forums dislike advanced Unicode characters in code blocks?

some of the tests were "fixed" by changing

code:
ok foo("some string\n"), "some result"
to
code:
ok foo("some string"), "some result generated without using \n or r\n or whatever the gently caress"

qntm
Jun 17, 2009

tef posted:

call it cool because i'm larry wall

quote:

"why is it called 'Cool'? that word is an adjective, but it's not a role. generally I would expect concrete data type names to be nouns. I'm willing to be persuaded otherwise but I found this quite surprising as a newcomer"

"well, actually it stands for 'Convenient Object-Oriented Loop'."

"huh? it's a data type, not a language construct. why is it called 'loop'"

"well, actually it stands for 'Convenient Object-Oriented Loopback'."

"the... the network address?"

"now you're just bikeshedding"

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

fritz posted:

quote:

Otoh, not all code needs to be maintainable.

fritz posted:

quote:

Otoh, not all code needs to be maintainable.

fritz posted:

quote:

Otoh, not all code needs to be maintainable.

fritz posted:

quote:

Otoh, not all code needs to be maintainable.

Cybernetic Vermin
Apr 18, 2005

tons of stuff is best written with the attitude that if it needs to change it can be rewritten. basically :justpost:

fuck the mods
Mar 30, 2015

Cybernetic Vermin posted:

tons of stuff is best written with the attitude that if it needs to change it can be rewritten. basically :justpost:

such as most of rakudo

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
in 1999 i wrote some perl5 to generate the bill of material from an EDA schematic and i hardcoded the object fields as ordinals and a few months later i had to face the guy who had taken over the code :(

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
holy poo poo i did some terrible stuff in that job, like i had to implement a circular buffer on an FPGA and in the control register i chose write modes basically at random for each bit and when I tried to revise it to be more uniform the software team screamed at me for breaking compatibility

because of the way i chose the semantics, the status register could indicate that the buffer was empty and full at the same time :gonk:

karms
Jan 22, 2006

by Nyc_Tattoo
Yam Slacker

Job Security™

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
job security sociopathy is for olds, this was my first job out of college and i just dind't know any loving better and anyway my tenure coincided with the company's downward spiral so not much security to speak of

tef
May 30, 2004

-> some l-system crap ->

Cybernetic Vermin posted:

tons of stuff is best written with the attitude that if it needs to change it can be rewritten. basically :justpost:

this is good when you're rewriting to replace one design with another, but unfortunately this usually means "replace code that no-one understands to add a new edge case and because three of them are packed into a line, you missed one in the new code"

tef
May 30, 2004

-> some l-system crap ->
that said i am a-ok with making code easy to delete over easy to maintain

tef
May 30, 2004

-> some l-system crap ->

gently caress the mods posted:

all of these people are smart as hell but there really is no strong lead or direction beyond the parts Larry rules on.

you can't specify software without writing it the first time. our brains are too small to consider all the ambiguities we encounter. i mean, larry had some advantage in perl 5 which is why it only took him 15 years to specify a subset of the next version of the language, but it wasn't until hugs came along that anything happened to perl 6, and it stalled when audrey left.

larry basically said "i wrote perl 5" and "the community will write perl 6" thus the whole test and spec package first and a lot of software to show all of these advanced features work in the small and no real libraries, integrations, or toolchain as broad as it's peers.

it's a long long way from say swift sharing a large proportion of it's toolchain with another language (ish), or rust's flagship project servo, or even python's "mostly the same except you'll have to change all of your source code and libraries at the same time"

quote:

I'm mad about new perl and wrote all of this

in return: i'm going to write an alternate universe fanfic where python 3 wasn't botched to gently caress

qntm
Jun 17, 2009
in my day you could write a bad programming language in two working weeks and accidentally conquer the universe with it

Vanadium
Jan 8, 2005

tef posted:

that said i am a-ok with making code easy to delete over easy to maintain

How do I do this in practice, beyond my usual modus operandi of writing code no one actually needs

Brain Candy
May 18, 2006

Vanadium posted:

How do I do this in practice, beyond my usual modus operandi of writing code no one actually needs

make the API rly good and loosely coupled

good luck!

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Vanadium posted:

How do I do this in practice, beyond my usual modus operandi of writing code no one actually needs
http://web.mit.edu/Saltzer/www/publications/endtoend/endtoend.pdf

tldr: leave application logic to the application

corollary: choose a platform and code as directly and concisely to it as possible, until such time as you have a specific requirement to support other platforms

in the job after the one i was talking about, i was programming on ST20 processors which have their own built-in multithreading kernel but well, someone before me thought it would be just swell to code a threading kernel on top of that which added no value

Gazpacho fucked around with this message at 01:38 on Dec 27, 2015

karms
Jan 22, 2006

by Nyc_Tattoo
Yam Slacker

Vanadium posted:

How do I do this in practice, beyond my usual modus operandi of writing code no one actually needs

Judicious use of copy+paste. (don't listen to me)

fuck the mods
Mar 30, 2015

sure. it's why I still do contribute to the project regularly and push for its use (selfishly) outside of my ranting here. but even with my regular involvement I was caught off guard with what I can only describe as the word games of "Xmas release" to "oh we really mean just the spec" at the last minute.

the GLR (great list refactor) involved less changes to the various code bases I maintain than the continued surprise changes in the last 2 months. some of these changes, like Supply syntax, match your sentiment. but others like precompilation were done literally without understanding what needed to be done by the person who ran with it (which has been admitted today in #perl6). and I don't mean everyone was learning what needed to be done, I mean one person took it upon himself to ignore the lessons and details that had already been uncovered by people who *did* know what needed to be done and started almost entirely from scratch.

the module system won't work if it's located somewhere read only anymore, clearly something dist packagers can't work with yet. the excuse originally was development use would always have write access so shut up about your edge case. its admitted later they have no idea how dist packaging works. can't say I'm surprised, because currently the difference between an actual problem and a corner case is your perl5 reputation. I was pretty happy to see mst looking at tool chain code today

tef
May 30, 2004

-> some l-system crap ->

Vanadium posted:

How do I do this in practice, beyond my usual modus operandi of writing code no one actually needs

this is hard to do and hard to explain

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

tef posted:

in return: i'm going to write an alternate universe fanfic where python 3 wasn't botched to gently caress

we were actually really close to making that happen, releasing a python 2.8

i still want to do it.

tef
May 30, 2004

-> some l-system crap ->

gently caress the mods posted:

I was pretty happy to see mst looking at tool chain code today

the problem is that perl 6 will not get the long term attention it needs unless numerous people are paid to work on the implementation full time.

in order to get that, you kinda need to have people who already rely on perl 6 to make money.

for people to rely on perl 6 to make money you kinda need to have people paying long term attention to it, well, a resilient group, one where the project won't disappear overnight but also one where the amount of time you spend handling bugs is worth it for the time you save using it.

it isn't so much that perl 6 was a mistake but it wasn't even a fork to the language, it's a whole new language that's hoping some of the perl 5 programmers left and other people will jump in from python and ruby

the thing is that people use ruby because of rails (& other bits of the web service ecosystem) and python because of numpy, django, and node for a variety of reasons, not because the language had interesting features. people tend to pick languages because of social factors or work pressures: people learn what their friends learn and their friends learned what was popular.

i guess i want to see an apology for perl 6, not because other languages grew popular, but because i don't think perl 6 was worth the cost to perl 5. perl 6 from the outset was a death sentence, well, not so much a death sentence, but perl 5 has become frozen, like c, into part of the ecosystem like bash. too much relies on it to change it any more. cpan isn't what it's used to be either.

we kinda needed perl 5 without the perl 1-4 bits, and then maybe we could be using perl 6 now instead of writing one liners with hyperexpressions automapped over lazy junction rules.

tef
May 30, 2004

-> some l-system crap ->
btw perl's "every list is flattened automatically" (well more that the comma is associative in perl) looks real weird, but i have encountered a poo poo ton of flatMaps in code and maybe larry was on to something when he explained why he did it : "it's useful sometimes"

fuck the mods
Mar 30, 2015
I make my living with perl 6. this is my own fault of course but I think it's funny I'm able to convince clients into letting me use it but not able to convince some core developers of the problems I found to be very real

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
This question will probably provoke laffs but does perl6 process perl 5 code as the original spec required (and which perl 5 lmao)


tef posted:

btw perl's "every list is flattened automatically" (well more that the comma is associative in perl) looks real weird, but i have encountered a poo poo ton of flatMaps in code and maybe larry was on to something when he explained why he did it : "it's useful sometimes"
I'm 100% sure that was never a deliberate choice on wall's part (prior to perl6 anyway)

fuck the mods
Mar 30, 2015

Gazpacho posted:

This question will probably provoke laffs but does perl6 process perl 5 code as the original spec required (and which perl 5 lmao)

No, that part of the spec was dropped a very long time ago. But there is a module that does it pretty well with the small caveat that you need a perl 5 built with `-Duseshrplib`

Inline::Perl5 posted:

code:
    use Inline::Perl5;
    use DBI:from<Perl5>;

    my $dbh = DBI.connect('dbi:Pg:database=test');
    my $products = $dbh.selectall_arrayref(
        'select * from products', {Slice => {}}
    );
code:
    use Data::Dumper:from<Perl5>;
    class MyDumper is Data::Dumper {
        has $.bar;
        method foo { say "foo!"; }
    }
    my $dumper = MyDumper.new([1], bar => 1);
    say $dumper.Dump();
    say $dumper.foo;
    say $dumper.bar;

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy
so it's just embedded the way perl5 has Inline::C? let me guess, it's one of those things that has effects at compile time and run time, because compile time is also allowed to be runtime in certain situations in perl

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy

chmods please posted:

because compile time is also allowed to be runtime in certain situations in perl

reminds me of a marginally-related perl bug where code in the following form:

Perl code:
my $x = 42 if $butts eq "lol";
would result in random garbage being assigned to $x because my has effects at compile time (allocate $x) but also effects at run time (initialize $x to the rhs). however $x never actually gets initialized because of the conditional (the default initializer is to set it to undef, but that doesn't get run here), so it gets random stack garbage instead. yes, this has bitten us at work, why do you ask?

Quebec Bagnet fucked around with this message at 06:26 on Dec 27, 2015

tef
May 30, 2004

-> some l-system crap ->
let's try to make code easy to delete

step 0: don't write code

the number of lines of code doesn't tell us much on its own, but it's magnitude does 50, 500, 5,000, 10,000, 25,000 etc

a million line monolith is going to be more annoying than a ten thousand line one and significantly more time, money, and effort to replace.

this is facile, but generally the more code you have the harder it is to get rid of. saving one line of code saves absolutely nothing on its own.


step 1: copy paste more code

lines of code is a good approximation for the maintenance burden of code, but some lines of code cost more than others. it's sometimes to copy paste a couple of times before making code reusable.

when you avoid copy paste and go for code reuse, you introduce dependencies upon the library you have created. building reusable code is something thats easier to do in hindsight with a couple of examples of use in the code base, than foresight of ones you might want later.

it's much harder to delete code that's used in multiple places. it's much harder to delete code that's been reused, and the more it has been reused the more accidental and implicit behaviours will be relied on.


step 2: don't copy paste code

when you copy and paste something enough times maybe it's time to pull it up to a function. you know the code won't be going away any time soon: this is the "save me from my standard library" stuff, the "open a config file and give me a hash table", "delete this directory". a lot of this code is stateless, or at least the state they are relying on is things like environment variables. the stuff that ends up in a file called "util".

each of these things should generally stand on it's own give or take a couple of helper functions, so my advice is this sort of code should live in it's own file, rather than in one shared util file with a bunch of methods. make a util directory and stick them in there. a single file util will always grow until it is too big and yet too hard to move out, putting them in individual files makes it easier for them to grow as time goes along. some of the time this code is a wrapper around a third party library, or error handling code.

like the one shots, they are more about dealing with the computer than your application or business logics like file handles, or processes. stuff that is just going to be platform detail. other good examples of code you're not going to delete are lists, hash tables, and other collections. not because they often have very few methods, but because they don't grow in scope over time.


step 5: write more boilerplate

despite writing libraries to avoid copy pasting, with very simple interfaces we often end up writing a lot more code but we call it boilerplate as you usually change some of code in a different place each time, rather than the same bit over and over. it's like a more frustrating copy paste that's less obvious on how to lift out.

it is not that you are making code easy to delete, but you are consolidating something that is hard to delete and keeping it away from the rest of the code lest it be contaminated with business logic. stuff like network protocols, wire formats, parsing libraries, stuff where it's hard to interweave policy (what a program should do), and protocol (what a program can do) together without limiting the options.

like with copy paste, we are duplicating parts of code to avoid introducing dependencies, gain flexibility, and pay for it in verbosity. with these libraries, when you change your mind about what you want them to do, you can change one part and continue on. although the total lines of code never really goes down, it never really grows that quickly.

again, this is not an exercise in code reuse but trying keep the parts that change frequently from the parts that are relatively static. it's not so much deleting code but being able to replace parts of it without interruption.


step 5: don't write boilerplate

boilerplate works best when it's invoked for one off situations or to cater to all tastes, but sometimes you end up doing the same things over and over. despite urlib2 being flexible, it's still awful to use. you can layer on a library atop that handles the details for you. this isn't as uncommon as you'd think: requests is an successful example of providing a simpler interface for common tasks built over a complex library which can be assembled into shape (urllib3).

what we are doing is structuring our code into layers atop each other: starting at the bottom with the things that change the least (platform, runtime), and slowly adding a layer as we deal with a new concern, like protocol, or policy. i'm not advocating you go out and create a /protocol/ and a /policy/ directory but you do want to try and keep your util directory free of business logic, and build simpler interfaces out of wrappers around more flexible but verbose ones, and layer your software to manage change: things that don't need to change shouldn't rely on things that do.

it isn't a clean separation between "absolutely inflexible" "every project" and "this project" every time but it's a corner that's relatively expensive to cut in large code bases and one that's hard to fix later. layering is about not making your code easy to delete but making the most of what you have with the code you have got: the code you're going to change is the code you should focus on making it easy to delete, but a healthy system always has some redundancy.

it really isn't about code reuse.


step 6: write a big ball of mud

eventually you have to deal with your business logic somewhere, and once you've isolated the other parts of your code that are unlikely to change in scope you're actually going to have to make the program do something. remember that one big poop emoji vs 19 small tangled poop emoji? sometimes it's easier to delete one big mistake than try to delete 18 smaller mistakes one at a time.

this works well when your software is disposable but all of the moving parts look the same each time even if it does look a bit different. one off client sites, event web pages, homebrew content management systems. when you work in a factory line you don't really care about the lifecycle that far after release. i've seen mobile games companies operate around this principle: make a bunch of fire and forget demo games out of a shared toolkit and maintain the ones that people like. this often involves punching things into a template or framework, well the sort of framework that's a big ball of mud but it has handy gaps left for your things.

when you know what code is going to be deleted soon or easily replaced you can cut a lot more corners, especially when you've isolated the other parts. it isn't so much about code reuse but making it easy to prototype without too much investment.


step 7: don't write a big ball of mud

on the other hand, some of us are not so lucky and we must live with our mistakes for a lot longer. the problem with big balls of mud is that the short term gains are fantastic but eventually they become a very very big poop emoji. although the layers i've talked about above work with a very thin veneer of business logic atop a bunch of domain and platform specific things, this breaks down when you have an awful lot of business logic.

before we talked about layering state, logic, protocol, and policy above more simpler lumps of code, we change that and begin first with a shared layer. out software starts to resemble multiple processes sharing the shame file system. they don't care what filesystem it is as long as it as the files it expects to be there. another example is dependency injection, whereby a hidden namespace is populated with objects and hopefully most of the code to glue it together is handled for you.

other examples involve a twitter engineer wrote something about how they've introduced namespaces into their rpc toolkit, to let them control how the system in a similar means to how other people have used dns. the trick with having 18 small balls of mud is keeping the ways in which they depend on each other to simple contracts, although it's a rough ride even for well established things like filesystems.

uniformity of interface, like file systems or wsgi, is one thing that makes code easy to delete: there is code re-use in things like rack/wsgi/*, but what they enables you do is to pick and choose your http server and middleware and make it easy to change your mind and delete the code that made those choices.

it isn't so much that you can split your software into smaller parts, but a uniform interface makes it easier to delete the code you depend on and replace it. a uniform interface is not just how the system works, but how it breaks too. it can be better to have an honest interface (i might be slow) vs one that assumes (i will always return quickly) because computer networking is terrifying.


step 8: loose coupling

it isn't so much the size of your code base, or how cleanly you've split your software into layers, or how uniformly your components communicate and share with each other, these are just as much approximations of what it means to write code that is easy to delete. it is not having few dependencies, making them explicit or implicit, but how you isolate and compose these dependancies together, and how you can change them over time.

when your code is loosely coupled together, it's easy to delete it. a healthy code base has some verbosity, some redundancy, and just enough distance between the moving parts so you won't trap your hands in it.


tl;dr if you want to write code that is easy to delete, repeat yourself to avoid creating dependencies, but don't repeat yourself to manage them. layer your code apart to make it easy to change your mind and isolate the bits of your code that are fast moving and/or hard to write from each other. don't try to do all of these things at the same time. or just don't write so much code

tef
May 30, 2004

-> some l-system crap ->
that took longer to write than i thought it would and tbh i think i answered your question with a complete tangent :confused:

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.
pro post tef, cheers for that.

triple sulk
Sep 17, 2014



tef posted:

it isn't so much that perl 6 was a mistake but it wasn't even a fork to the language, it's a whole new language that's hoping some of the perl 5 programmers left and other people will jump in from python and ruby

i'm venturing to guess that like 75% of ruby/rails devs already jumped ship, mostly to js with a few scattered amongst other languages that may not thrive in the long run. the other 25% cannot be coaxed away from ruby no matter what you offer them at this point.

b0lt
Apr 29, 2005
did the perl6 people mix up christmas and april fools day?

quote:

Superscripts can now be used for integer powers
Non-digit unicode characters with a numeric value (½ and such) can now be used for that numeric value
There is a new “approximately equal” operator

gonadic io
Feb 16, 2011

>>=

b0lt posted:

did the perl6 people mix up christmas and april fools day?

∼∼unicode compatibility∼∼

gonadic io
Feb 16, 2011

>>=

gonadic io posted:

∼∼unicode compatibility∼∼

e: wtf radium? the one time i want the forums to mangle the character codes...

gonadic io fucked around with this message at 11:57 on Dec 27, 2015

b0lt
Apr 29, 2005

gonadic io posted:

∼∼unicode compatibility∼∼

they should add a mojibake equality operator for things like this

Adbot
ADBOT LOVES YOU

coffeetable
Feb 5, 2006

TELL ME AGAIN HOW GREAT BRITAIN WOULD BE IF IT WAS RULED BY THE MERCILESS JACKBOOT OF PRINCE CHARLES

YES I DO TALK TO PLANTS ACTUALLY

tef posted:

let's try to make code easy to delete

step 0: don't write code

the number of lines of code doesn't tell us much on its own, but it's magnitude does 50, 500, 5,000, 10,000, 25,000 etc

a million line monolith is going to be more annoying than a ten thousand line one and significantly more time, money, and effort to replace.

this is facile, but generally the more code you have the harder it is to get rid of. saving one line of code saves absolutely nothing on its own.


step 1: copy paste more code

lines of code is a good approximation for the maintenance burden of code, but some lines of code cost more than others. it's sometimes to copy paste a couple of times before making code reusable.

when you avoid copy paste and go for code reuse, you introduce dependencies upon the library you have created. building reusable code is something thats easier to do in hindsight with a couple of examples of use in the code base, than foresight of ones you might want later.

it's much harder to delete code that's used in multiple places. it's much harder to delete code that's been reused, and the more it has been reused the more accidental and implicit behaviours will be relied on.


step 2: don't copy paste code

when you copy and paste something enough times maybe it's time to pull it up to a function. you know the code won't be going away any time soon: this is the "save me from my standard library" stuff, the "open a config file and give me a hash table", "delete this directory". a lot of this code is stateless, or at least the state they are relying on is things like environment variables. the stuff that ends up in a file called "util".

each of these things should generally stand on it's own give or take a couple of helper functions, so my advice is this sort of code should live in it's own file, rather than in one shared util file with a bunch of methods. make a util directory and stick them in there. a single file util will always grow until it is too big and yet too hard to move out, putting them in individual files makes it easier for them to grow as time goes along. some of the time this code is a wrapper around a third party library, or error handling code.

like the one shots, they are more about dealing with the computer than your application or business logics like file handles, or processes. stuff that is just going to be platform detail. other good examples of code you're not going to delete are lists, hash tables, and other collections. not because they often have very few methods, but because they don't grow in scope over time.


step 5: write more boilerplate

despite writing libraries to avoid copy pasting, with very simple interfaces we often end up writing a lot more code but we call it boilerplate as you usually change some of code in a different place each time, rather than the same bit over and over. it's like a more frustrating copy paste that's less obvious on how to lift out.

it is not that you are making code easy to delete, but you are consolidating something that is hard to delete and keeping it away from the rest of the code lest it be contaminated with business logic. stuff like network protocols, wire formats, parsing libraries, stuff where it's hard to interweave policy (what a program should do), and protocol (what a program can do) together without limiting the options.

like with copy paste, we are duplicating parts of code to avoid introducing dependencies, gain flexibility, and pay for it in verbosity. with these libraries, when you change your mind about what you want them to do, you can change one part and continue on. although the total lines of code never really goes down, it never really grows that quickly.

again, this is not an exercise in code reuse but trying keep the parts that change frequently from the parts that are relatively static. it's not so much deleting code but being able to replace parts of it without interruption.


step 5: don't write boilerplate

boilerplate works best when it's invoked for one off situations or to cater to all tastes, but sometimes you end up doing the same things over and over. despite urlib2 being flexible, it's still awful to use. you can layer on a library atop that handles the details for you. this isn't as uncommon as you'd think: requests is an successful example of providing a simpler interface for common tasks built over a complex library which can be assembled into shape (urllib3).

what we are doing is structuring our code into layers atop each other: starting at the bottom with the things that change the least (platform, runtime), and slowly adding a layer as we deal with a new concern, like protocol, or policy. i'm not advocating you go out and create a /protocol/ and a /policy/ directory but you do want to try and keep your util directory free of business logic, and build simpler interfaces out of wrappers around more flexible but verbose ones, and layer your software to manage change: things that don't need to change shouldn't rely on things that do.

it isn't a clean separation between "absolutely inflexible" "every project" and "this project" every time but it's a corner that's relatively expensive to cut in large code bases and one that's hard to fix later. layering is about not making your code easy to delete but making the most of what you have with the code you have got: the code you're going to change is the code you should focus on making it easy to delete, but a healthy system always has some redundancy.

it really isn't about code reuse.


step 6: write a big ball of mud

eventually you have to deal with your business logic somewhere, and once you've isolated the other parts of your code that are unlikely to change in scope you're actually going to have to make the program do something. remember that one big poop emoji vs 19 small tangled poop emoji? sometimes it's easier to delete one big mistake than try to delete 18 smaller mistakes one at a time.

this works well when your software is disposable but all of the moving parts look the same each time even if it does look a bit different. one off client sites, event web pages, homebrew content management systems. when you work in a factory line you don't really care about the lifecycle that far after release. i've seen mobile games companies operate around this principle: make a bunch of fire and forget demo games out of a shared toolkit and maintain the ones that people like. this often involves punching things into a template or framework, well the sort of framework that's a big ball of mud but it has handy gaps left for your things.

when you know what code is going to be deleted soon or easily replaced you can cut a lot more corners, especially when you've isolated the other parts. it isn't so much about code reuse but making it easy to prototype without too much investment.


step 7: don't write a big ball of mud

on the other hand, some of us are not so lucky and we must live with our mistakes for a lot longer. the problem with big balls of mud is that the short term gains are fantastic but eventually they become a very very big poop emoji. although the layers i've talked about above work with a very thin veneer of business logic atop a bunch of domain and platform specific things, this breaks down when you have an awful lot of business logic.

before we talked about layering state, logic, protocol, and policy above more simpler lumps of code, we change that and begin first with a shared layer. out software starts to resemble multiple processes sharing the shame file system. they don't care what filesystem it is as long as it as the files it expects to be there. another example is dependency injection, whereby a hidden namespace is populated with objects and hopefully most of the code to glue it together is handled for you.

other examples involve a twitter engineer wrote something about how they've introduced namespaces into their rpc toolkit, to let them control how the system in a similar means to how other people have used dns. the trick with having 18 small balls of mud is keeping the ways in which they depend on each other to simple contracts, although it's a rough ride even for well established things like filesystems.

uniformity of interface, like file systems or wsgi, is one thing that makes code easy to delete: there is code re-use in things like rack/wsgi/*, but what they enables you do is to pick and choose your http server and middleware and make it easy to change your mind and delete the code that made those choices.

it isn't so much that you can split your software into smaller parts, but a uniform interface makes it easier to delete the code you depend on and replace it. a uniform interface is not just how the system works, but how it breaks too. it can be better to have an honest interface (i might be slow) vs one that assumes (i will always return quickly) because computer networking is terrifying.


step 8: loose coupling

it isn't so much the size of your code base, or how cleanly you've split your software into layers, or how uniformly your components communicate and share with each other, these are just as much approximations of what it means to write code that is easy to delete. it is not having few dependencies, making them explicit or implicit, but how you isolate and compose these dependancies together, and how you can change them over time.

when your code is loosely coupled together, it's easy to delete it. a healthy code base has some verbosity, some redundancy, and just enough distance between the moving parts so you won't trap your hands in it.


tl;dr if you want to write code that is easy to delete, repeat yourself to avoid creating dependencies, but don't repeat yourself to manage them. layer your code apart to make it easy to change your mind and isolate the bits of your code that are fast moving and/or hard to write from each other. don't try to do all of these things at the same time. or just don't write so much code

nothing to add, just quotin so that there's likely to be more similar posts in future

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply