DEV Community

Cover image for Episode 1: I Was a Junior Developer and I Must Be Stopped
Adam - The Developer
Adam - The Developer

Posted on

Episode 1: I Was a Junior Developer and I Must Be Stopped

We all start somewhere.

Some developers begin their careers writing clean, well-structured code, carefully following best practices, naming variables properly, and writing tests like responsible adults.

Others start by shipping a few bugs here and there, learning, improving, and slowly developing their own style.

And then there's me.

Today, we are reviewing a function I wrote years ago that is somehow still running in production, untouched, unbothered, and — against all odds — still working. No one has dared to refactor it. No one has tried to rewrite it. It has achieved something most code never will:

It became too scary to change.

This function is called multipleUpdate.
It lives in a Laravel application.
It updates multiple items.
I think.

Here it is, in all its glory:

public function multipleUpdate(
    Scenario $scenario,
    Request $request
) {
    $r_arr = intval($request->right_arr);
    $id_array = $request->item_number ?? $r_arr;
    $name_ja_array = $request->name_ja ?? null;
    $name_en_array = $request->name_en ?? null;
    $type_array = $request->type ?? null;

    $added = []; // final res
    array_push($added, $r_arr);
    $difference = [];

    for ($i = 0; $i < count($id_array) - 1; $i++) {
        array_push($difference, $id_array[$i + 1] - $id_array[$i]);
    }

    for ($i = 0; $i < count($difference); $i++) {
        array_push($added, $r_arr += $difference[$i]);
    }

    for ($i = 0; $i < count($added); $i++) {
        if ($scenario->items()->where('item_number', $added[$i])->exists()) {
            $scenario->items()->where('item_number', $added[$i])->update([
                'name_ja' => ($name_ja_array[$i] ?? $request->default_name_ja) ?? null,
                'name_en' => ($name_en_array[$i] ?? $request->default_name_en) ?? null,
                'kind' => ($type_array[$i] ?? $request->default_type) ?? null,
            ]);
        } else {
            $scenario->items()->create([
                'scenario_id' => $scenario->id ?? null,
                'item_number' => $added[$i] ?? null,
                'name_ja' => $name_ja_array[$i] ?? null,
                'name_en' => $name_en_array[$i] ?? null,
                'kind' => $type_array[$i] ?? null,
            ]);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Take a moment. Let it wash over you. I'll be here.

Now let's go through it together, line by line, like a crime scene investigator who is also crying.


The Mysterious $r_arr Variable

// oh cool, a variable named $r_arr. what does r stand for? right? raw? random?
// who the hell knows. the author was apparently too busy to leave a single hint.
$r_arr = intval($request->right_arr);
Enter fullscreen mode Exit fullscreen mode

$r_arr. Short for right_arr, which comes from the request field right_arr.

What is "right"? Right as in correct? Right as in direction? Right as in the author just started typing and committed before their brain caught up?

We will never know. There are no comments. There is no documentation. There is only $r_arr, staring back at you, completely unashamed.


Sir, This Is an Int

// sir this is an int. you are about to count() and loop over a single goddamn int.
// i genuinely hope you tested this. i genuinely fear that you did.
$id_array = $request->item_number ?? $r_arr;
Enter fullscreen mode Exit fullscreen mode

The variable is called $id_array. It implies an array. It promises an array. It has the word array right there in the name.

The fallback is $r_arr, which we just established is an int.

So if $request->item_number is missing, $id_array is a single integer, and we are about to call count() on it, loop over it, and index into it like it's an array.

PHP, famously lenient, will try its best. PHP will not succeed.


The ?? null Epidemic

// breaking news: local developer discovers that $request->name_ja ?? null
// and $request->name_ja are the same fucking thing. more at 11.
$name_ja_array = $request->name_ja ?? null;
$name_en_array = $request->name_en ?? null; // still doing it. unbelievable.
$type_array = $request->type ?? null;       // i am losing my mind.
Enter fullscreen mode Exit fullscreen mode

$x ?? null means: "if $x is null, use... null."

This is the coding equivalent of a safety net made of holes. It is null, wearing a seatbelt, driving into a wall.

The author wrote this three times in a row. On three separate lines. Without stopping to wonder if something had gone wrong in their life.


The Comment That Explains Nothing

$added = []; // final res
Enter fullscreen mode Exit fullscreen mode

"final res."

Final result? Final response? Final resignation letter?

You cannot write // final res and then disappear like a deadbeat dad. Come back. Explain yourself. We deserve that much.

Also: array_push($added, $r_arr) to append a single value. The author could have written $added[] = $r_arr. It's shorter. It's faster. It doesn't make me feel things.

But they didn't. They used array_push. For one value. And then kept going.


The Round Trip to Nowhere

Now we reach the heart of it. The crown jewel. The part that made me go outside and stand in a field for ten minutes.

// oh no. oh hell no. i see where this is going and i am grabbing you by the shoulders.
// you're going to calculate the gaps between IDs, aren't you.
// you absolute disaster of a human being.
for ($i = 0; $i < count($id_array) - 1; $i++) {
    array_push($difference, $id_array[$i + 1] - $id_array[$i]);
}

// and NOW you're adding them back together. you took [10, 12, 15],
// blew it up into [2, 3], and then painstakingly rebuilt [10, 12, 15].
// you did a round trip to absolutely nowhere and burned CPU cycles for the privilege.
// i am genuinely asking: are you okay? do you need water?
// did someone hurt you?
for ($i = 0; $i < count($difference); $i++) {
    array_push($added, $r_arr += $difference[$i]);
}
Enter fullscreen mode Exit fullscreen mode

Let me walk you through what's happening here.

We have an array of IDs: [10, 12, 15].

Loop one: compute the differences between consecutive IDs. [2, 3].

Loop two: add those differences back, cumulatively, to reconstruct... [10, 12, 15].

We took the array. We destroyed it. We rebuilt it. We are exactly where we started.

This is a mathematical round trip that accomplishes zero. The only thing it changes is $r_arr, which started life as a request input, briefly became a loop accumulator, and is now something else entirely.

$r_arr has had more identity changes in one function than most people have in a lifetime. Leave $r_arr alone. $r_arr has been through enough.


The Database Loop of Sadness

We are now in loop three. The database loop. God help us.

for ($i = 0; $i < count($added); $i++) {
    if ($scenario->items()->where('item_number', $added[$i])->exists()) {
        $scenario->items()->where('item_number', $added[$i])->update([...]);
    } else {
        $scenario->items()->create([...]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Two database queries per item. One to check if it exists. One to update or create it.

No transaction wrapper. No bulk operation. Just a prayer and a dream that nothing fails halfway through and leaves the database looking like it was updated by a raccoon who found a keyboard.

And then there's this:

$scenario->items()->create([
    'scenario_id' => $scenario->id ?? null,
    'item_number' => $added[$i] ?? null,
    ...
]);
Enter fullscreen mode Exit fullscreen mode

$scenario->id ?? null. We dependency-injected $scenario into the function signature. Laravel loaded it, validated it, handed it to us on a silver platter. If $scenario->id is null at this point, ?? null is not saving us. Nothing is saving us. Say your goodbyes.

$added[$i] ?? null. We are inside the loop that iterates over $added. $added[$i] is guaranteed to exist. The ?? null is not a safety net. It is a tiny umbrella in a drink that is already on fire.


The Method That Was Right There the Whole Time

Here is the part that gets me.

Laravel has had updateOrCreate() since version 5.3.

$scenario->items()->updateOrCreate(
    ['item_number' => $added[$i]],
    [
        'name_ja' => $name_ja_array[$i] ?? $request->default_name_ja,
        'name_en' => $name_en_array[$i] ?? $request->default_name_en,
        'kind'    => $type_array[$i] ?? $request->default_type,
    ]
);
Enter fullscreen mode Exit fullscreen mode

One method. One query. Handles both cases. No manual existence check. No separate create/update branch.

It was sitting right there the whole time, like a golden retriever waiting by the door.

And I looked it in the face, said "no thanks," and wrote a three-loop differential equation instead.

I'm not angry at myself.

I'm disappointed.

(I am absolutely furious.)


The Final Tally

crimes committed:
- 3 loops to rebuild the array we already had:                       ✅
- up to 2N db queries with zero transaction safety:                  ✅
- $r_arr living three different lives in one function:               ✅
- ?? null deployed purely as emotional support:                      ✅
- updateOrCreate() left completely untouched like a jilted lover:    ✅
- "final res" as a comment explaining nothing:                       ✅
Enter fullscreen mode Exit fullscreen mode

And yet.

And yet.

It works. It has always worked. It is running in production right now, at this very moment, as you read this. No one has touched it. No one will. It works and that is the most infuriating part of all of this.


The real multipleUpdate was the trust issues we developed along the way.

If you have code like this living rent-free in your production environment — code that works, code that you are afraid to touch, code that you wrote and no longer recognize — I want you to know: you are not alone.

We all have a multipleUpdate. Some of us just haven't found ours yet.

Episode 2 coming whenever I'm emotionally ready.

Top comments (2)

Collapse
 
mrdisloyal profile image
Mr Disloyal

Stop personally attacking me with this content! My junior-dev days weren't about coding; they were about performing high-stakes, unscripted chaos directly into the codebase. I occasionally peer into the abyss of my old repositories and marvel at the sheer audacity of whoever gave me keyboard privileges. Can't wait for Episode 2 – I've already emotionally prepared for further self-incrimination.

Collapse
 
adamthedeveloper profile image
Adam - The Developer • Edited

If you've never spewed chaos and disaster into a codebase once, you were never a junior!
Episode 2 coming out soon, there's just so many more of these pre-AI, peak-stack overflow era disastrous junior code of mine that I had to do something about them.

you know, I still remember the senior who reviewed this piece of code, I still vividly remember the look on his face - the moment he saw this piece of code, he shook his head a few times after reading it, tested it and decided to merge it and if I'm not wrong, I could've heard: " I'm not being paid enough for this "