Die Daily WTF sammelt seit 15 Jahren lustige, wilde und / oder traurige Geschichten aus der IT-Welt. Ich übersetzte mehrere Geschichten, die mir interessant erschienen. Alle Firmennamen und Namen wurden geändert. Frühere Ausgaben finden Sie unter dem Label "
kuriose Perversionen ".
Die erste Geschichte. Ende des Monats
[Original]Wenn Sie einen Konstrukteur fragen, ob das Überqueren einer Brücke sicher ist, teilt er Ihnen gerne mit, wie zuverlässig die Brücken sind, wie die Mathematik darin funktioniert und wie weit wir in Sachen Gebäudesicherheit gekommen sind. Wenn Sie mit ihm gesprochen haben, werden Sie den Eindruck haben, dass keine einzige Brücke auf der Erde jemals auseinanderfallen wird. Wenn Sie jedoch den Softwareentwickler nach den Banken fragen, werden Sie höchstwahrscheinlich entsetzt sein und sich mit einer Wahrscheinlichkeit von 50/50 davon überzeugen, das gesamte Geld in Bitcoin zu investieren. Banken sind für ihre schlechten Entscheidungen bei der Erstellung von Software berüchtigt - nicht weil diese Entscheidungen widerlich sind, sondern weil die meisten Leute davon ausgehen, dass Banken genauer und vorsichtiger mit Sicherheit umgehen.
Kato arbeitet bei der Inibank, wo ein kommerzielles Produkt namens T24 als Kern des Bankensystems verwendet wird. Das T24-System wird von Hunderten von Banken auf der ganzen Welt verwendet. Es kann an eine Vielzahl von Banklösungen angepasst werden. Wie bei den meisten benutzerdefinierten Paketen. Es gibt Programmierer, die sich darauf spezialisiert haben, Code dafür zu schreiben, und Berater, die Banken bei wichtigen Updates helfen.
Die Mitarbeiter der Inibank waren beschäftigt, daher lud die Bank einen Berater ein, an einem speziellen Projekt teilzunehmen. Am Ende des Arbeitstages führte die Bank den Abschlussprozess durch, der erforderlich ist, damit das gesamte Geld dorthin fließt, wohin es geleitet wurde, alle erforderlichen Ausgabedaten neu berechnet und alle erforderlichen Berichte ausgeführt werden. Bei Banken ändert dieser Prozess auch das Systemdatum auf den nächsten Geschäftstag. Aus diesem Grund wird beim Online-Banking am Sonntag erst am Montagmorgen eine einzige Transaktion verarbeitet. Der Berater musste einen neuen Bericht erstellen, der während des Abschlussprozesses ausgeführt wurde und eine zusätzliche Verarbeitung beinhaltete, wenn das Datum dem Monatsende entsprach.
Kato zeigte dem neuen Berater, wie die Bank Tagesabschlussberichte erstellt. „Sehen Sie, wir haben globale Variablen für den vorherigen Arbeitstag, für heute und für den nächsten Arbeitstag. Sie haben das Format JJMMTT, um die Arbeit zu erleichtern. "
„Ja, ja, verstanden. Ich verstehe. In welchem Format sind sie? "
"... Ähh ... ich kann nur annehmen, dass dies das Jahr, der Monat und der Tag ist."
„Ja, ja, okay. Großartig. Dann mache ich mich an die Arbeit. “
Nach diesem Gespräch hatte Kato ein schlechtes Gefühl dabei. aber er versuchte ihn loszuwerden. Der Berater sagte, dass alles eingerichtet und bereit sei. Er weiß genau, was er tut, oder? Kato warf dies aus seinem Kopf und hörte auf, sich Sorgen zu machen, bis die Zeit für die Codeüberprüfung kam und er eine solche Perle fand:
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
Erklären Sie kurz, was hier passiert:
- Nehmen Sie den nächsten Werktag und ändern Sie den Tag auf 01, um den ersten Tag des Monats zu erhalten.
- Wir ändern dieses Datum, indem wir 1 Kalendertag vom Kalender Spaniens abziehen.
- Wir nehmen das Datum vom Server und übersetzen es in das Format JJJJMMTT, wobei wir den Befehl Datum dreimal aufrufen.
- Wenn das in Schritt 2 berechnete Datum dem in Schritt 3 berechneten Datum entspricht, starten Sie den Vorgang.
Nun, eigentlich ... es funktioniert. Zum größten Teil. Es sei denn, aus irgendeinem Grund erfolgt das Ende des Tages nicht nach Mitternacht am vorletzten Tag des Monats - und dies ist nicht so selten. In diesem Fall glaubt der Code fälschlicherweise, dass dies der letzte Tag des Monats ist, und beginnt mit der Erstellung des Berichts. Was gut zu einem anderen Problem passt: Wenn am letzten Tag des Monats dasselbe passiert, wird die Erstellung des Berichts nicht versehentlich gestartet. Und der beste Fehler: Wenn sich herausstellt, dass der letzte Tag des Monats Sonntag ist, wird der Kalender des Servers niemals darauf installiert, da er arbeitsfreie Tage überspringt.
Apropos arbeitsfreie Tage: Da sich die Inibank in den USA befindet, gibt es keinen Grund, den spanischen Kalender zu verwenden. Ja, die Monate und Wochen sind gleich, aber im spanischen Softwarekalender müssen Sie Feiertage in den USA angeben, da das Programm sonst weiterhin funktioniert. Als ob all dies noch nicht genug wäre, bedeutet der dreifache Datumsaufruf, dass es zu Meinungsverschiedenheiten kommen kann, wenn genau um Mitternacht begonnen wird: Der Monatswert wird vor Mitternacht und am Tag danach angefordert.
Kato fügte einen Kommentar hinzu und schlug eine Möglichkeit vor, den Code zu ändern:
IF R.DATES(EB.DAT.TODAY)[5,2] # R.DATES(EB.DAT.LAST.WORKING.DAY)[5,2] THEN
Fünf Minuten später ging der Berater zu seinem Schreibtisch. "Was bedeutet diese Bearbeitung?"
Kato war in diesem Moment nicht in der Stimmung zu streiten. „Dein Code ist kaputt, Freund. All dies ist nicht notwendig. "
„Ich verstehe, ich verstehe. Dies ist eigentlich nur ein Standardverfahren für unsere Branche. Na gut. "
Kato bezweifelte das sehr, zuckte aber nur die Achseln. „Dann ist die Branche falsch. Ich habe alles im Kommentar erklärt. "
„Ja. Ja, ich habe es gelesen. Aber ich werde es noch einmal lesen. “ Und er verschwand so plötzlich wie er erschien.
Änderungen wurden vorgenommen, Kato genehmigte den Code und der Berater verschwand im Nebel.
Manchmal, als Kato nachts im Bett lag, fragte er sich: Hat der Berater wirklich verstanden, was er falsch gemacht hatte, oder war er nur einverstanden zu schauen, erhielt seinen Scheck und schrieb irgendwo einen schrecklichen Code für einen Preis, der doppelt so hoch war wie das Gehalt von Kato? In Banken, in denen es keine Mitarbeiter gibt, die den Code überprüfen können.
Aber investieren Sie nicht das ganze Geld in Bitcoin. Dort ist es noch schlimmer.
Die zweite Geschichte. Wie wird das gemacht?
[Original]Die Leute lieben es, Hot Dogs zu essen, bis sie herausfinden, wie sie kochen. Die meisten fragen nicht, weil sie nicht wissen wollen und weiterhin Hot Dogs essen. Bei der Entwicklung von Software müssen wir manchmal fragen. Nicht nur, um Probleme zu lösen, sondern auch, weil einige Programmierer befürchten, dass die Software in ihren Autos, die mit einer Geschwindigkeit von 100 km / h die Autobahn entlang fährt, aus Klebeband und Sticks zusammengesetzt ist.
Unsere gesamte Branche erledigt ihre Aufgaben schlecht .
Brett arbeitete als Systemanalytiker am MedStitute Medical Research Center. MedStitute verwendete eine proprietäre Software namens MedTech, um Daten zu speichern und zu analysieren. Ärzte und Forscher mochten die Ergebnisse von MedTech, aber Kollege Brett Tyree wusste, wie sie geschaffen wurden.
Die Software hatte keinen Zugriff auf das Backend und der gesamte Entwicklungsprozess fand in der GUI "Programmable Mouse" statt. Diese Oberfläche sah aus, als ob sie von einer Person geschrieben wurde, die das Programmieren mit Copy-Paste-Websites aus den 90er Jahren studierte, zehn Minuten
Jurassic Park betrachtete und nach Antworten auf StackOverflow suchte, bis etwas kompiliert werden konnte. Die "Programmiersprache" zeigte auch in der Designphilosophie ein ähnliches Maß an Nachdenklichkeit. Jeder
muss einen
else
gehabt haben. Einige Module verwendeten Boolesche Werte, andere gaben leere Zeichenfolgen zurück, um falsche Werte anzuzeigen. Aus der Dokumentation war nicht ersichtlich, in welcher Situation die eine oder andere passiert ist. Tatsächlich wurde jede
if
zu drei Anweisungen.
Brett musste eine neue Studie beginnen. Es basierte auf einer einfachen Reihe von Statistiken und gruppierten Patienten unter Verwendung einer randomisierten Variablen. Brett suchte in der Liste nach einer Variablen, die randomisiert werden konnte, fand sie aber nicht notwendig. Er schlug vor, einen Fehler zu machen, und ging ein paar Bildschirme zurück, um ihren Namen zu überprüfen, indem er ihn für eine Suche kopierte. Brett kehrte zur Liste der zufälligen Variablen zurück. Sie war nicht da. Er sah sich die Liste genauer an und stellte fest, dass die Liste der zufälligen Variablen Daten aus Multiple-Choice-Feldern enthielt. Das Feld, das er randomisieren musste, basierte auf einem berechneten Feld.
Brett wusste, dass Tyree an einem anderen Projekt arbeitete, das nach berechneten Feldern randomisiert war, und kontaktierte ihn daher bei Slack. „Wie haben Sie diese Zufallsvariable codiert? Verhindert Medtech dies? “
"Ich spreche über Konferenzen, ich rufe Sie später zurück", schrieb Tyree.
Ein paar Minuten später rief Tyree Brett an.
„Sie müssen mit zwei Feldern beginnen. Sagen wir mal. Nennen wir sie
$variable_choice
, dh eine Multiple-Choice-Frage, und
$variable_calced
, dh Ihr berechnetes Feld. Wenn Sie eine Variable erstellen möchten, die eine zufällige Auswahl basierend auf einem berechneten Feld durchführt, teilen Sie Medtech mit, dass diese zufällige Variable auf
$variable_choice
basiert. Dann löschen Sie
$variable_choice
und benennen
$variable_calced
in
$variable_choice
“
„Stop, das System erlaubt es Ihnen, aber erlaubt Ihnen nicht, die berechneten Felder auf andere Weise zufällig zu ordnen? Und sie überprüft es nicht? "
"Ich hoffe, dass sich nichts ändert, und sie beginnt erst nach Abschluss meines Projekts, dies zu überprüfen", antwortete Tyree.
„Diese Studie sollte über zehn Jahre stattfinden. Und sein erfolgreicher Abschluss hängt davon ab, ob die Entwickler diesen Trick für einen Fehler halten? “
„Ich habe nur eine solche Lösung gefunden. Lass es mich wissen, wenn du etwas Besseres findest. “
Brett befriedigte einen solchen Hack nicht und studierte wieder die Dokumentation. Er fand eine „bessere“ Lösung: Sie können ein schreibgeschütztes Multiple-Choice-Feld mit dem einzigen Standardwert erstellen - dem Wert des berechneten Felds. Leider kann der Benutzer die Liste versehentlich ändern, indem er eine Multiple-Choice-Frage beantwortet,
bevor er den Wert des berechneten Felds berechnet.
Am Ende blieb Brett nur noch eine Pause, in die Cafeteria gehen und ein paar Hot Dogs kaufen.
Die dritte Geschichte. Portabilität und Hardware
[Original]Vor vielen Monden, als PCs Schwermetall- und Kunststoffgehäuse hatten, wurden
Matt und sein Kollege gebeten, das Softwarepaket für den bevorstehenden Betrieb der Verkaufsabteilung zu evaluieren. Leider arbeiteten er und sein Kollege in verschiedenen Büros innerhalb derselben Stadt. In dieser Zeit gab es noch keine effektiven Tools für die Online-Zusammenarbeit, sodass Matt regelmäßig in ein anderes Büro reisen und einen PC mitnehmen musste. Dies bedeutete, dass jedes Mal, wenn es notwendig war, Peripheriekabel vom Gehäuse 473 zu trennen, den Computer entlang der Korridore und die Treppe hinunter zu tragen, einen Bus zu nehmen, um zu einem anderen Büro zu gelangen, in dem er dies alles in umgekehrter Reihenfolge tat. Manchmal zwang die falsche Arbeitsorganisation dieses Paar, am Wochenende zu arbeiten, was bedeutet, dass sie Arbeitsmaschinen nach Hause tragen.
Dabei lief die 20-MB-Festplatte in Matts Computer über. Von seinem Büro aus schickte er eine Anfrage an die IT-Abteilung. Um den Antrag zu erfüllen, wurde Garys Techniker ernannt, der nach einiger Zeit in Matts Würfel erschien und eine neue Festplatte und einen Schraubenzieher in der Hand hielt. Gary schickte Matt zum Kaffee, um sich auf seinen „Patienten“ zu konzentrieren. Nach einer kleinen Operation schaltete sich Matts PC ein und arbeitete mit einer großen Festplatte.
Am Tag vor Projektschluss hätte Matt seinen Teil der Arbeit fast abgeschlossen. Er musste nur ein paar Ergänzungen zu seinem Bericht vornehmen und ihn dann auf Disketten kopieren und an die Verkaufsabteilung senden. Er stellte seinen PC wieder in den Würfel und verband die Kabel, schaltete den Strom ein und hörte ein Knallen. Der PC war tot und zeigte keine Lebenszeichen.
Nach einem Panikanruf an die IT-Abteilung erschien Gary erneut mit einem Schraubenzieher in seinem Büro. Er öffnete das PC-Gehäuse und schrie sofort: „Warte eine Minute! Hast du irgendwo einen Computer gezogen? "
Matt runzelte die Stirn. „Nun ja. Ist das das Ding? "
„Ja natürlich! Das hättest du nicht tun sollen! “Gary begann zu fluchen. "Die Festplatte fing an rumzuhängen und hat alles im Inneren kurzgeschlossen!"
Matt beugte sich über Gary, um sich selbst ein Bild vom Inneren des Computers zu machen. Er bemerkte sofort, dass die neue Festplatte auf Band „repariert“ war.
„Hör auf! Das
hättest du nicht tun sollen! “ Matt zeigte auf ein Stück Klebeband. "Soll ich mich für alle Fälle an Ihren Vorgesetzten wenden?"
Garys Gesicht runzelte die Stirn. "Sie geben mir nicht die notwendigen Befestigungselemente!"
"Dann finde den, der sie hat!"
Angesichts der bevorstehenden Frist übertrug Matt mit Erlaubnis des Chefs seine Bewerbung noch weiter. Fast sofort wurde das Klebeband durch echte Hardware ersetzt. Er verstand nie,
warum die Mitarbeiter der IT-Abteilung keinen Zugang zu den erforderlichen Geräten hatten. er schlug vor, dass es die geniale Idee eines Idioten war, Geld zu sparen. Matt konnte nur raten, welche anderen verzweifelten Improvisationen ihre IT-Infrastruktur zum Funktionieren brachten und wie lange sie unbemerkt bleiben würden, wenn sein PC nicht kaputt gehen würde.
Die vierte Geschichte. So wirkt sich PL / SQL auf Ihr Gehirn aus.
[Original]Der ewige Champion unter den seltsamsten und erfolglosesten Entscheidungen wird für immer
Oracle bleiben. Heute schauen wir uns einen kleinen PL / SQL-Code an.
PL / SQL ist eine seltsame Sprache, eine Mischung aus SQL und
P rocedural (prozedural) Sprache (Sprache) mit objektorientiertem Seitenkleben. Die Syntax kann hervorragend den Eindruck erwecken, dass sie in den 1970er Jahren entwickelt wurde, und jede neue Funktion oder jeder Sprachwechsel setzt diese Tradition fort.
Die Struktur jedes PL / SQL-Codemoduls ist
blockbasiert . Jeder Block ist ein unabhängiger Namespace. Kurz gesagt, seine Anatomie sieht folgendermaßen aus:
DECLARE
Wenn Sie eine gespeicherte Prozedur oder einen Ereignishandler schreiben, ersetzen Sie das Schlüsselwort
DECLARE
durch
CREATE [OR REPLACE]
. Sie können Blöcke auch in anderen Blöcken verschachteln, sodass Sie häufig Code sehen, der folgendermaßen strukturiert ist:
BEGIN DECLARE
Ja, ziemlich schnell wird es verwirrend. Und ja, wenn Sie zumindest eine annähernd strukturierte Fehlerbehandlung bereitstellen möchten,
müssen Sie beginnen, Blöcke ineinander zu setzen.
Die Sprache und die Datenbank haben andere lustige Funktionen. Vor Version 12c hatten sie keinen
IDENTITY
. In früheren Versionen mussten Sie das
SEQUENCE
Objekt verwenden und Prozeduren oder Ereignishandler schreiben, die eine erzwungene automatische Nummerierung durchführen. In der Regel wurde der Operator
SELECT INTO…
verwendet, um einer Variablen einen Wert zuzuweisen. Bonus: Für Oracle SQL muss in der
FROM
Anweisung
immer eine Tabelle angegeben werden.
FROM
müssen Sie eine erfundene
dual
wie folgt verwenden:
CREATE TRIGGER "SOME_TABLE_AUTONUMBER" BEFORE INSERT ON "SOME_TABLE" FOR EACH ROW BEGIN SELECT myseq.nextval INTO :new.id FROM dual; END;
:new
in diesem Zusammenhang die Zeile an, für die wir automatisch nummerieren. In älteren Versionen von Oracle war dies die „übliche“ Methode zum Erstellen von Spalten mit automatischer Nummerierung.
Benoit entdeckte eine andere, etwas weniger verbreitete Methode, um dieselbe Operation durchzuführen:
CREATE OR REPLACE TRIGGER "SCHEMA1"."TABLE1_TRIGGER" BEFORE INSERT ON "SCHEMA1"."TABLE1" FOR EACH ROW BEGIN DECLARE pl_error_id table1.error_id%TYPE; CURSOR get_seq IS SELECT table1_seq.nextval FROM dual; BEGIN OPEN get_seq; FETCH get_seq INTO pl_error_id; IF get_seq%NOTFOUND THEN raise_application_error(-20001, 'Sequence TABLE1_SEQ does not exist'); CLOSE get_seq; END IF; CLOSE get_seq; :new.error_id := pl_error_id; END; END table1_trigger;
Hier ist viel los.
DECLARE
, dass der Abschnitt
CURSOR
Anweisung
DECLARE
enthält. Mit Cursorn können Sie Datensätze durchlaufen. Sie sind sehr teuer und in der Oracle-Welt ist es eine Ressource, die freigegeben werden muss.
Dieser Ereignishandler (Trigger) verwendet ohne Grund einen verschachtelten Block. Es wird auch die zusätzliche Variable
pl_error_id
, auf die verzichtet werden kann.
Aber der wirklich seltsame Teil ist der
IF get_seq%NOTFOUND
Block
IF get_seq%NOTFOUND
. Alles ist ganz einfach: Es überprüft die Bedingung, dass der Cursor keine Zeichenfolge zurückgibt. Bei diesem Cursor kann dies nicht einmal
theoretisch geschehen, sodass die darin enthaltenen Operationen niemals ausgeführt werden. Eine Sequenz gibt immer einen Wert zurück. Und das ist
gut angesichts des Codes, der weiter geht.
raise_application_error
ist ein Analogon von werfen in Oracle. Diese Anweisung geht den Stapel ausführbarer Blöcke hoch, bis der Abschnitt
EXCEPTIONS
wird, um den Fehler zu behandeln. Beachten Sie, dass wir den Cursor
nach dieser Anweisung schließen - das heißt, wir schließen den Cursor
niemals . Cursor sind, wie oben erwähnt, teuer, und Oracle erlaubt nur die Verwendung einer begrenzten Anzahl von Cursorn.
Hier sehen wir ein seltsames Beispiel dafür, wie ein Entwickler versucht, sich gegen einen Fehler zu verteidigen, der nicht auftreten kann und der im Laufe der Zeit zu neuen Fehlern führt.
Die fünfte Geschichte. Doppelte verschlüsselte Anmeldungen
[Original]Das Erstellen einer Authentifizierung für die Web-API ist eine
schwierige Aufgabe, bietet jedoch
viele etablierte Lösungen. Am schwierigsten ist es tatsächlich, eine der verschiedenen Optionen auszuwählen. Danach reicht es aus, einfach eine Komponente hinzuzufügen.
Bei korrekter Implementierung ist das System unabhängig vom Client-Typ. Ich kann über einen Browser, einen Thick Client oder über cURL auf den Dienst zugreifen. Bei falscher Implementierung erhalten Sie, was mit
Amira passiert ist.
Sie löste das Problem, die benötigten Statistiken aus dem Backend abzurufen, konnte jedoch die Authentifizierungsmethode nicht herausfinden. Daher untersuchte sie den Front-End-Code, um zu verstehen, wie er die Authentifizierung durchführt:
crypt = new JSEncrypt(); crypt.setPublicKey('<removed>'); challenge = "<removed>"; function doChallengeResponse() { document.loginForm.password.value.replace(/&/g, '%26'); document.loginForm.password.value.replace(/\\+/g, '%2B'); document.loginForm.password.value = crypt.encrypt(document.loginForm.password.value); document.loginForm.response.value = document.loginForm.password.value; document.loginForm.password.value = ''; document.loginForm.submit(); }
Einerseits kann ich davon ausgehen, dass dieser Code angesichts der
document.loginForm
die für Interaktionen mit DOM-Elementen verwendet wird, sehr alt ist. Auf der anderen Seite wurde
JSEncrypt
erstmals 2013 veröffentlicht, was uns die maximale Altersgrenze gibt.
Wir übergeben die Zugriffsparameter an das Backend, indem wir das Formular senden, das laut Codeentwickler bereinigt werden muss - alle
&
+
im Passwort werden ersetzt, aber ... dies ist nicht erforderlich, da das Formular die
POST
Anforderung erfüllen muss und
wir zusätzlich
die Daten verschlüsselt haben .
Hier ist was ich denke. Der Code
ist eigentlich ziemlich alt. Der Entwickler hat es aus einem Beitrag auf StackOverflow um 2005 kopiert, in dem keine Verschlüsselung und Formularübermittlung per
POST
. Jahr für Jahr wurden kleine Änderungen hinzugefügt. Der zugrunde liegende Mechanismus hat sich jedoch nie geändert.
Amira überprüfte den Verlauf und stellte fest, dass in der vorherigen Version keine Verschlüsselung verwendet wurde.
challenge
, MD5,
, , .
: , , , , cURL -. ,
SSL/TLS .