It's The End Of The Month As We Know It
If you ask an engineer whether it's safe to cross a bridge, he'll happily walk you through how safe bridges are, how the mathematics work out, how far we've come in structural safety. You'll come away from the conversation feeling confident that no bridge will ever collapse anywhere on the face of the Earth. If you ask a software engineer about banks, however, you'll likely come away terrified, with a 50/50 chance you're now convinced to put all your money in bitcoin. Banks are notorious for bad software decisions-not so much because the decisions are worse, but because most people assume banks are more careful and security-minded.
Today's submitter, Kato, worked at Inibank, where they used a commercial product called T24 as the core of their banking system. T24 is used by hundreds of banks worldwide. It's customizable for a wide range of banking solutions, and so like most large customizable suites, there are programmers that specialize in writing custom code for it and consultants that will hold your hand through major upgrades.
Inibank brought in a consultant to take on a special project while their resources were busy. At the end of the business day, there is a Close Of Business process that has to be done to ensure all the money gets where it's going, all the appropriate outputs are recalculated, and all the relevant reports are run. In banks, this also changes the system's date to the next working day-which is why if you do online banking on a Sunday, none of it begins to process until Monday morning. The consultant was meant to create a new report that would run during the Close Of Business process, which would do extra processing if it were also the End of Month.
Kato sat down with the new guy, showing him how they'd set up their end of day reports. "You see here, there's a global for the last working day, one for today, and one for the next working day. Those are YYMMDD, so they're easier to work with."
"Right, right okay, gotcha. Gotcha. And what format is that?"
"... I don't know the standard off the top of my head, but it's year, month, day."
"Right, right, okay. Cool. I'll get right to work, then."
Kato walked away from the conversation with a sinking feeling in the pit of his stomach, but he tried to ignore it. The consultant said he was all set up and ready. Surely he knew what he was doing, right? Kato put it out of his mind, and didn't worry about it again until it came time to review the code, and he found this gem:
TH.DATE = R.DATES(EB.DAT.NEXT.WORKING.DAY)[1,6]:"01"CALL CDT('ES00',TH.DATE,"-1C")WTODAY = OCONV(DATE(),"DY") : FMT(OCONV(DATE(),"DM"),'R%2') : FMT(OCONV(DATE(),"DD"),'R%2')IF TH.DATE EQ WTODAY THEN
In layman's terms:
- Take the next working day and change the day to 01 in order to get the first day of the month.
- Change that date by subtracting 1 calendar day, in the Spain calendar.
- Take the server's date and put in format YYYYMMDD by calling 3 times for the command Date.
- If the date calculated in step 2 is the same as the date calculated in step 3, run the process.
Now, this ... works. Mostly. Except that if for some reason close of day ticked over past midnight on the second-to-last day of the month-not uncommon-it would incorrectly think it was the last day of the month and run the report. Which worked well with the next problem: if the same thing happened on the last day of the month, it would incorrectly not run the report. And the best bug yet: if the last day of the month was a Sunday, the server's calendar would never be set to it, since it skips non-working days.
Speaking of non-working days: as Inibank was US-based, there was no reason to use the Spain calendar. Sure, your months and weeks are the same, but the US bank holidays would need to be set in the Spain calendar in the software, or else it would still run. Finally, as if all this weren't bad enough, calling for the Date three times meant you could have inconsistencies if it straddled midnight exactly: the month retrieved before midnight, the day after.
Kato put in a comment, suggesting that the code be changed to:
IF R.DATES(EB.DAT.TODAY)[5,2] # R.DATES(EB.DAT.LAST.WORKING.DAY)[5,2] THEN
Five minutes later, the contractor was at his desk. "What is this change?"
Kato was in no mood to argue by this point. "Your code's broken, dude. You didn't need to do all that."
"I see, I see. Well, it's just, this is the standard operating procedure in the industry. But no matter."
Kato highly doubted this, but he shrugged it off. "Industry's wrong, then. I explained it all in the comment."
"I see. Yes, I read this. But I will read it again." And then he was gone, as suddenly as he'd appeared at Kato's desk.
The edits were made, Kato approved the PR, and the consultant vanished into the night.
Sometimes, late at night, Kato lies awake wondering if the consultant really understood what he did wrong, or if he were just paying lip service, collecting his check, and writing terrible code for twice Kato's salary somewhere else. Somewhere without in-house staff to look over the code.
But don't put all your money in bitcoin. That's even worse.
[Advertisement] Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.