Quick Answer

The habits that make you look junior aren't about knowing less syntax, they're about process: commit messages like "fix", leftover console.log calls in a pull request, code that breaks the moment someone types something unexpected, and copy-pasted code you can't explain if asked. Senior-looking code isn't smarter, it's just more honest about what it does and doesn't handle.

Commit Messages That Say Nothing

Open a strong developer's git log and you can read the story of a feature without opening a single file: Add pagination to search results, Fix crash when API returns null, Remove unused auth middleware. Open a junior's log and you often get fix, update, changes, and the occasional asdf or final final v2 from 2 a.m.

This is one of the first things a reviewer notices, because git log --oneline takes three seconds to skim and tells them exactly how you think. A vague message doesn't just look sloppy, it means that six months from now, nobody (including you) can find the commit that introduced a bug without opening every diff one by one.

  • The fix costs nothing. Finish the sentence "This commit will..." and use that as your message.
  • One commit, one idea. If you're describing a commit with "and", it's probably two commits.

Debug Leftovers Still Sitting in the Diff

You added console.log(data) to check what the API was returning, it worked, and then you shipped the pull request with the console.log still in it. Every developer has done this at least once, the difference is whether it happens once a year or once a week.

Reviewers read leftover debug prints, commented-out blocks of old code, and // TODO: fix this later with no ticket attached as a sign that nobody looked at the diff before submitting it. It's a small thing, but small things are exactly what reviewers actually see, because they usually don't have time to trace your algorithm line by line first, they skim the diff.

Before you open a pull request, do one pass just looking for stray print or console.log calls, blocks of code commented out "just in case", and debugging flags left switched on.

Code That Only Works on the Happy Path

It works when you demo it. It works with the exact input you tested. Then someone submits an empty form, uploads a 40MB file to a field that expected an avatar, or hits the API twice in half a second, and it falls over, because nothing in the code ever considered that those things could happen.

This is one of the clearest tells of junior code, because writing the happy path is genuinely the easy 80%. The senior-looking 20% is asking, for every input, what happens if this is missing, empty, too long, negative, or arrives twice. You don't need to handle every case perfectly on day one, you need to visibly have thought about it, even if the answer is a deliberate, commented "we don't support this yet."

  • What happens if the array is empty?
  • What happens if the network call fails?
  • What happens if two users do this at the same time?

Code You Copied But Can't Explain

There's nothing wrong with pulling a snippet from Stack Overflow or asking an AI tool to write a first draft, every working developer does it. What reads as junior is not being able to explain, line by line, what the code you just pasted into your own pull request actually does.

A reviewer will eventually ask "why did you do it this way?" If the honest answer is "I'm not sure, it worked," that's the moment the diff's earlier polish stops mattering. The same goes for error messages: if you paste the full stack trace into a search bar or an AI chat without reading it top to bottom first, you'll often copy a fix for the wrong problem.

The habit that fixes this is small: before you paste something in, spend two minutes making sure you could rewrite it from memory in your own words.

Reinventing What Already Exists

Writing your own string-trimming function, your own date formatter, or a hand-rolled loop to deduplicate a list is a great exercise the first time you do it, and a quiet red flag the tenth time, when the language's standard library already does it, tested, in one line.

Senior developers reach for what's already been solved, a standard library function, a well-known package, a documented pattern, and save the custom code for the actual problem they're being paid to solve. Writing everything from scratch doesn't read as skill to a reviewer, it reads as not knowing what's already there.

Treating Code Review Like a Personal Attack

A comment on your pull request that says "why not use a map here instead of three nested loops?" is not a comment on your worth as a developer. Junior reactions tend to be defensive: over-explaining, arguing the point instead of asking a follow-up, or silently resenting the reviewer. Senior reactions tend to be curious: "good point, let me try that" or "I considered that, here's why I didn't, open to being wrong."

Reviewers remember who was easy to give feedback to far longer than they remember any specific bug. This one habit alone changes how quickly you get trusted with bigger pull requests.

Testing by Clicking Around Instead of Automating It

Manually clicking through the app after every change works, until the app has more than a handful of screens and you're doing it fifteen times a day. Junior-looking code is verified once, by hand, right before the pull request goes up. Senior-looking code has at least a few automated tests that anyone, including future-you, can re-run in seconds.

You don't need full coverage to make this shift. Even three or four tests around the trickiest part of a feature signals that you're thinking about how this code fails later, not just whether it works right now.

Frequently Asked Questions

Will one of these habits actually get me rejected in an interview? Rarely on its own, but reviewers form an impression fast, and several of these habits together in the same pull request add up to "needs a lot of oversight," which affects who gets trusted with bigger work even if it doesn't cost you the interview itself.
Is it bad to use ChatGPT or Copilot to write code? No, using AI tools is normal at every level now. What reads as junior is submitting code you can't explain, not the fact that a tool helped write the first draft.
How specific do commit messages need to be? Specific enough that someone reading only the git log, with no other context, understands what changed and roughly why. One clear sentence in the imperative mood is usually enough.
I'm a beginner, should I really be writing automated tests already? Start small. A few tests around the part of your code most likely to break communicates the right instinct, even if the rest of the project has none yet.
What's the single fastest habit to fix from this list? Commit messages. It costs nothing to write one clear sentence instead of "fix", and it's the first thing most reviewers actually read.