←back to thread

1455 points nromiun | 3 comments | | HN request time: 0s | source
Show context
Buttons840 ◴[] No.45074873[source]
I'm probably one of the "smart developers" with quirks. I try to build abstractions.

I'm both bothered and intrigued by the industry returning to, what I call, "pile-of-if-statements architecture". It's really easy to think it's simple, and it's really easy to think you understand, and it's really easy to close your assigned Jira tickets; so I understand why people like it.

People get assigned a task, they look around and find a few places they think are related, then add some if-statements to the pile. Then they test; if the tests fail they add a few more if-statements. Eventually they send it to QA; if QA finds a problem, another quick if-statement will solve the problem. It's released to production, and it works for a high enough percentage of cases that the failure cases don't come to your attention. There's approximately 0% chance the code is actually correct. You just add if-statements until you asymptotically approach correctness. If you accidentally leak the personal data of millions of people, you wont be held responsible, and the cognitive load is always low.

But the thing is... I'm not sure there's a better alternative.

You can create a fancy abstraction and use a fancy architecture, but I'm not sure this actually increases the odds of the code being correct.

Especially in corporate environments--you cannot build a beautiful abstraction in most corporate environments because the owners of the business logic do not treat the business logic with enough care.

"A single order ships to a single address, keep it simple, build it, oh actually, a salesman promised a big customer, so now we need to make it so a single order can ship to multiple addresses"--you've heard something like this before, haven't you?

You can't build careful bug-free abstractions in corporate environments.

So, is pile-of-if-statements the best we can do for business software?

replies(23): >>45074916 #>>45074936 #>>45074945 #>>45075059 #>>45075089 #>>45075095 #>>45075106 #>>45075135 #>>45075188 #>>45075195 #>>45075392 #>>45075443 #>>45075463 #>>45075515 #>>45075547 #>>45075846 #>>45076426 #>>45077189 #>>45077500 #>>45077548 #>>45078893 #>>45079553 #>>45080494 #
marginalia_nu ◴[] No.45075059[source]
I honestly think that's pretty close to optimal for a lot of places. With business software it's often not desirable to have large sweeping changes. You may need some small change to a rule or condition, but usually you want things to stay exactly the way they are.

The model of having a circle of ancient greybeards in charge of carefully updating the sacred code to align with the business requirements, while it seems bizarre bordering on something out of WH40K, actually works pretty well and has worked pretty well everywhere I've encountered it.

Attempts to refactor or replace these systems with something more modern has universally been an expensive disaster.

replies(1): >>45075158 #
Buttons840 ◴[] No.45075158[source]
It does work for awhile, until one day:

Project Manager: "Can we ship an order to multiple addresses?"

Grey Beard: "No. We'd have to change thousands of random if-statements spread throughout the code."

Project Manager: "How long do you think that would take?"

Grey Beard: "2 years or more."

Project Manager: "Okay, we will break you down--err, I mean, we'll need to break the task down. I'll schedule long meetings until you relent and commit to a shorter time estimate."

Grey Beard eventually relents and gives a shorter time estimate for the project, and then leaves the company for another job that pays more half-way through the project.

replies(4): >>45075181 #>>45076553 #>>45076761 #>>45076892 #
1. weiliddat ◴[] No.45076553[source]
If Grey Beard doesn't relent

Project Manager: "Can we ship an order to multiple addresses? We need it in 2 weeks and Grey Beard didn't want to do it"

Eager Beaver: "Sure"

  if (order && items.length > 1 && ...) {  
    try {  
      const shipmentInformation = callNewModule(order, items, ...)  
      return shipmentInformation  
    } catch (err) {  
      // don't fail don't know if error is handled elsewhere  
      logger.error(err)  
    }  
  } else {  
    // old code by Grey Beard  
  }
replies(1): >>45076814 #
2. quectophoton ◴[] No.45076814[source]
... and then that `callNewModule` has weird bugs like mysteriously replacing `+` with spaces, sometimes labels are empty but only if they are shipped to a specific company, sometimes the invoices are generated multiple times for the same shipment, after 1 year after Sales has already sold this multi-item shipment feature to massive companies it suddenly stops working because the new module wasn't properly hooked for auto-renewing credentials with a specific service and the backlog of unshipped items but marked as shipped grows by the second...

Of course Eager Beaver didn't learn from this experience because they left the company a few months ago thinking their code was AWESOME and bragging about this one nicely scalable service they made for shipping to multiple addesses.

Meanwhile Grey Beard is the one putting out the fires, knowing that any attempt to tell Project Manager "finding and preventing situations like this was the reason why I told my estimate back then" would only be received with skepticism.

replies(1): >>45077014 #
3. weiliddat ◴[] No.45077014[source]
Of course, why reuse existing logic when we can (vibe) code new modules and functions from scratch every time we need it!

/s