The Developer Skills Nobody Puts on the Job Description

9 31 161
calendar_today agoschedule17 min read

You can learn a programming language. You can learn a framework. You can learn Docker, Kubernetes, cloud platforms, databases, APIs, and AI tools.

But there are some skills that rarely appear in a job description.

They don't have a certification.

You can't easily put them in a GitHub repository.

And you probably won't see them listed under "Requirements."

Yet these skills often determine whether a developer becomes someone people trust—or someone who is constantly struggling despite having excellent technical knowledge.

I'm talking about the skills behind the code.

Things like knowing when not to write code.

Knowing how to ask a good question.

Knowing how to explain a complicated problem without making it more complicated.

Knowing how to deal with a production incident without panicking.

Knowing when your solution is becoming too clever.

Knowing how to disagree with another developer without turning the discussion into a personal argument.

And perhaps most importantly:

Knowing how to keep learning without feeling like you're always falling behind.


1. The Programming Skill That Isn't Programming

When people talk about becoming a better developer, the conversation usually starts with technology.

"Learn React."

"Learn Python."

"Learn Java."

"Learn TypeScript."

"Learn AWS."

"Learn Kubernetes."

"Learn AI."

"Learn system design."

All of these things can be valuable.

But there is another skill that sits underneath almost everything:

Problem decomposition.

A difficult problem rarely arrives in the form of:

"Please implement function X with these five requirements."

Real-world problems are usually messy.

A customer says:

"The application is slow."

A manager says:

"We need this feature urgently."

A designer says:

"This interaction doesn't feel right."

A support person says:

"Some users can't log in."

A business person says:

"Can we make this automatic?"

None of these statements is a technical specification.

The developer has to transform an unclear problem into something that can actually be investigated and solved.

That means asking:

  • What exactly is happening?
  • Who is affected?
  • When did it start?
  • Can we reproduce it?
  • What changed recently?
  • What is the expected behavior?
  • What is the current behavior?
  • What constraints exist?
  • What happens if we do nothing?
  • What is the smallest useful solution?

This is engineering.

Writing the code is only one part of it.


2. Asking Better Questions Can Make You a Better Developer

One of the biggest differences between inexperienced and experienced developers isn't necessarily how much code they can write.

It is the quality of the questions they ask.

Imagine someone tells you:

"The API is broken."

A junior developer might immediately open the code and start changing things.

An experienced developer might ask:

"What makes us think the API is broken?"

That's a very different starting point.

Maybe the API is working perfectly.

Maybe the frontend is sending the wrong payload.

Maybe authentication expired.

Maybe a database migration changed a column.

Maybe only one specific customer is affected.

Maybe the API returns a successful response but the UI doesn't handle it correctly.

Maybe the problem isn't technical at all.

The first question should often be:

"What evidence do we have?"

This simple habit can save hours.

Before changing code, understand the problem.

Before adding a dependency, understand the requirement.

Before rewriting a component, understand why it needs rewriting.

Before blaming the database, check the logs.

Before blaming the network, reproduce the issue.

Before blaming another developer's code, investigate.

Good developers don't just find answers.

They learn how to ask questions that lead to useful answers.


3. The Most Expensive Code Is Sometimes the Code You Write

Developers naturally want to solve problems.

That's what we're trained to do.

A ticket arrives.

We open the editor.

We create files.

We write functions.

We submit a pull request.

It feels productive.

But sometimes the best solution is not to write anything.

Consider a feature request:

"We need another dashboard."

Before building it, ask:

  • Who needs it?
  • What decision will they make from it?
  • Do they already have this information somewhere?
  • Could an existing report solve the problem?
  • Is the dashboard actually necessary?
  • How often will it be used?
  • What happens if we don't build it?

Maybe the answer is still:

"Yes, we need the dashboard."

Great.

Now you understand why you're building it.

But sometimes you discover that the real requirement is much smaller.

Instead of building a complex system, maybe you need a CSV export.

Instead of creating a new microservice, maybe a function is enough.

Instead of introducing a new state-management library, maybe local state works.

Instead of building an elaborate automation system, maybe a scheduled job solves the problem.

Engineering isn't about maximizing code.

Engineering is about maximizing useful outcomes while minimizing unnecessary complexity.


4. Simplicity Is Not the Same as Easy

This is something developers often learn late.

Simple systems can be difficult to design.

Complex systems can be surprisingly easy to create.

Adding another abstraction is easy.

Creating another service is easy.

Adding another library is easy.

Adding another configuration file is easy.

Adding another layer is easy.

Removing unnecessary complexity is harder.

Imagine an application with:

Frontend → API Gateway → Service A → Service B → Message Queue → Service C → Database

It may be completely justified.

But if the actual problem could be solved with:

Frontend → API → Database

then the additional architecture isn't sophistication.

It's overhead.

Every additional component creates something else to:

  • deploy
  • monitor
  • debug
  • document
  • secure
  • maintain
  • upgrade
  • understand

The goal isn't to create the architecture that looks most impressive in a diagram.

The goal is to create the architecture that solves the actual problem.

Complexity should be earned.


5. Your Future Self Is Also a User of Your Code

Developers often think about users.

We think about:

  • customers
  • administrators
  • employees
  • API consumers
  • mobile users

But there is another user we should consider.

The developer who maintains the code six months from now.

Sometimes that developer will be you.

Imagine opening code you wrote eight months ago.

You see:

processData()

Then:

handle()

Then:

execute()

And somewhere:

if (x && !y && z !== null)

You might remember exactly why you wrote it.

But someone else probably won't.

And six months later, you might not either.

Good code isn't merely code that works.

Good code communicates intent.

Instead of asking:

"Can I make this shorter?"

Sometimes ask:

"Can another developer understand why this exists?"

Readable code is a form of teamwork.

Comments shouldn't explain obvious syntax.

They should explain things that aren't obvious.

For example:

// Retry only idempotent requests because repeating payment operations
// could result in duplicate transactions.

That comment provides valuable context.

This one:

// Increment counter
counter++;

doesn't.

The best documentation often explains why, not what.


6. Technical Debt Isn't Always Bad

"Technical debt" has become one of those phrases developers use whenever they dislike old code.

But technical debt isn't automatically a failure.

Sometimes taking on technical debt is a rational business decision.

Imagine you need to launch a product in two weeks.

You have two choices:

Option A

Spend three months building a perfectly abstract architecture.

Option B

Build a reasonable version in two weeks, validate whether customers actually want it, and improve the architecture afterward.

Option B may be the better engineering decision.

The problem isn't taking technical debt.

The problem is taking technical debt without knowing that you took it.

Debt becomes dangerous when everyone forgets it exists.

If you intentionally make a shortcut, document it.

Write down:

  • Why the shortcut was taken.
  • What problem it creates.
  • What would need to change later.
  • What conditions would justify paying it back.

Then technical debt becomes a conscious trade-off rather than accidental decay.


7. "Works on My Machine" Is Not a Debugging Strategy

Every developer has experienced this.

Everything works locally.

Then production says:

No.

The problem might be:

  • environment variables
  • database versions
  • operating-system differences
  • missing dependencies
  • permissions
  • configuration
  • networking
  • caching
  • timing
  • race conditions
  • timezone differences
  • data differences

This is why reproducibility matters.

A mature engineering process tries to reduce the distance between development and production.

Containers can help.

Automated tests can help.

CI/CD can help.

Infrastructure as code can help.

Observability can help.

But tools aren't enough.

There must also be a mindset:

Don't just fix the current bug. Ask why the system allowed the bug to reach this point.

If a production bug happened because an environment variable was missing, perhaps the long-term solution isn't simply adding the variable.

Maybe the application should fail clearly during startup.

Maybe configuration should be validated automatically.

Maybe deployment should verify required settings.

Fixing the symptom prevents one incident.

Fixing the process can prevent many.


8. Debugging Is an Investigation, Not a Guessing Game

One of the most valuable developer habits is learning to debug systematically.

When something breaks, developers sometimes start changing random things.

"Maybe this line."

"Maybe that query."

"Maybe restart the server."

"Maybe clear the cache."

"Maybe reinstall the package."

Sometimes one of those works.

But you don't necessarily learn anything.

A better process is:

Step 1: Reproduce

Can you reliably make the problem happen?

Step 2: Observe

What exactly happens?

Step 3: Narrow

Where does the behavior change from correct to incorrect?

Step 4: Form a hypothesis

What do you currently believe is causing it?

Step 5: Test the hypothesis

Change one thing or gather evidence.

Step 6: Verify

Did the evidence support your theory?

Step 7: Fix

Implement the smallest appropriate correction.

Step 8: Prevent

Can tests, monitoring, validation, or process changes prevent recurrence?

This turns debugging from:

"Let's try random stuff."

into:

"Let's reduce uncertainty."

And that is a much more powerful mindset.


9. AI Changed Coding, But It Didn't Remove Engineering

We can't talk about modern development without talking about AI.

AI coding tools can generate code extremely quickly.

They can:

  • explain errors
  • generate functions
  • create tests
  • refactor code
  • translate between languages
  • write documentation
  • suggest implementations
  • analyze unfamiliar code

That's useful.

But there's an important distinction.

Generating code is not the same as understanding a system.

An AI tool can generate a beautiful function that solves the wrong problem.

It can produce code that passes simple tests but fails under real-world conditions.

It can introduce subtle security issues.

It can misunderstand business rules.

It can use an outdated API.

It can create unnecessary complexity.

It can confidently suggest something incorrect.

So the valuable skill isn't simply:

"Can I use AI to write code?"

The better question is:

"Can I evaluate whether the code produced by AI is actually correct, appropriate, secure, maintainable, and aligned with the requirements?"

That requires engineering judgment.

AI may reduce the cost of producing code.

That makes judgment more valuable, not less.


10. Don't Become Dependent on Your Tools

Modern developers have more tools than ever.

IDEs.

Copilots.

AI assistants.

Linters.

Formatters.

Debuggers.

Frameworks.

Cloud platforms.

Package managers.

Monitoring systems.

Automation platforms.

These tools are fantastic.

But occasionally try solving a problem without the shortcut.

Why?

Because tools can hide your gaps.

If an AI assistant always tells you what an error means, you may never learn how to read stack traces properly.

If an IDE automatically fixes everything, you may not understand what changed.

If a framework handles database operations for you, you may forget what actually happens underneath.

You don't need to avoid tools.

You need to understand the layer beneath them.

Use abstractions.

But know enough about the abstraction to debug it when it breaks.


11. Communication Is a Technical Skill

Many developers don't think of communication as part of engineering.

It absolutely is.

Suppose you discover a serious production problem.

You can say:

"The authentication service is broken."

Or:

"Users who haven't refreshed their sessions since yesterday may receive a 401 response. The issue appears related to token validation after the latest deployment. We're investigating the authentication middleware now."

The second message is dramatically more useful.

It communicates:

  • scope
  • impact
  • evidence
  • current hypothesis
  • next action

That's engineering communication.

The same applies to pull requests.

Instead of:

"Fixed bug."

Write:

"Fixed duplicate order creation when users double-submit the checkout form. Added idempotency handling and regression tests."

Your teammates now understand what changed.

Communication reduces coordination cost.

And in larger teams, coordination cost can become more expensive than writing the code itself.


12. Learn to Disagree Without Becoming Difficult

Software development involves decisions.

People will disagree.

Should we use PostgreSQL or MySQL?

REST or GraphQL?

Monolith or microservices?

React or another framework?

SQL or NoSQL?

Build or buy?

These discussions can become surprisingly emotional.

But technical disagreement doesn't need to become personal.

Instead of:

"That's a terrible idea."

Try:

"I'm concerned about the operational cost of that approach because..."

Instead of:

"This architecture makes no sense."

Try:

"What problem are we solving with this additional service?"

Instead of:

"You're wrong."

Try:

"What evidence would change our decision?"

The goal isn't to win the argument.

The goal is to improve the decision.

A developer who can challenge ideas respectfully is extremely valuable.


13. Your Code Review Comments Say a Lot About You

Code reviews are one of the places where engineering culture becomes visible.

A poor review looks like:

"Bad."

"Why did you do this?"

"Don't do it this way."

"Rewrite."

A useful review explains the concern.

For example:

"Could we move this validation closer to the API boundary? That would keep invalid input from reaching the service layer and make the behavior consistent for both web and mobile clients."

Notice the difference.

The second comment isn't merely criticizing.

It's teaching.

Code review shouldn't be a demonstration of superiority.

It should be a mechanism for improving code and sharing knowledge.

And if you receive a review comment you disagree with, don't immediately become defensive.

Ask:

"Can you explain the concern?"

You might learn something.

Or you might discover that your reviewer misunderstood the context.

Either way, the conversation becomes productive.


14. Don't Optimize What You Haven't Measured

Performance work is another area where assumptions can become expensive.

A developer sees a slow page and immediately wants to:

  • rewrite the query
  • add caching
  • introduce Redis
  • optimize JavaScript
  • change the database
  • add a queue

But first:

Measure.

Where is the time actually going?

Maybe the database query takes 20 ms.

Maybe the network takes 800 ms.

Maybe the frontend performs an expensive calculation.

Maybe a third-party API takes two seconds.

Maybe the problem only happens with large datasets.

Without measurement, optimization is speculation.

Profilers, logs, traces, metrics, query analyzers, browser developer tools, and benchmarks exist for a reason.

The principle is simple:

Don't optimize based on what feels slow. Optimize based on what is demonstrably slow.


15. Learn to Read Code You Didn't Write

A surprising amount of professional development isn't creating new code.

It's understanding existing code.

You join a company.

There are five repositories.

One has 300,000 lines.

Documentation is incomplete.

The original developer left two years ago.

Your first ticket says:

"Fix this small issue."

There is nothing small about it.

This is why code reading is a skill.

When entering an unfamiliar system, don't immediately try to understand everything.

Start with the path of one real request.

For example:

User clicks button.

Frontend sends request.

API receives request.

Authentication runs.

Controller handles request.

Service performs business logic.

Repository queries database.

Response returns.

Follow one complete path.

Then another.

Gradually build a mental map.

You don't need to understand the entire ocean.

You need to understand the river you're currently navigating.


16. Seniority Isn't About Knowing Everything

One of the biggest misconceptions in software development is:

"Senior developers know everything."

They don't.

In fact, experienced developers often know exactly how much they don't know.

A senior engineer might say:

"I haven't worked with this technology before. Give me some time to investigate."

That's not weakness.

That's honesty.

The dangerous developer is the person who is afraid to say:

"I don't know."

Because pretending to know can create much larger problems.

A strong developer can say:

"I don't know yet, but I know how to find out."

That is a powerful skill.


17. Stop Comparing Your Chapter 2 to Someone Else's Chapter 20

Developer communities can create an unhealthy illusion.

You open social media and see:

  • developers launching startups
  • people earning huge salaries
  • engineers contributing to famous projects
  • someone learning five technologies in a month
  • impressive GitHub profiles
  • AI-generated productivity stories
  • conference talks
  • promotions
  • awards

Then you look at yourself.

And think:

"I'm behind."

But you're comparing your everyday reality with someone else's highlight reel.

You don't see:

  • their failed projects
  • rejected applications
  • bugs
  • bad decisions
  • difficult years
  • abandoned ideas
  • moments when they wanted to quit

Growth in software is rarely linear.

Some months you learn quickly.

Some months you maintain old systems.

Some months you spend weeks fighting one bug.

Some months you don't learn anything new.

That's okay.

Your career is measured over years, not one Tuesday.


18. The Best Developers Stay Curious

Technology changes constantly.

Frameworks become outdated.

Languages evolve.

Cloud services appear.

New AI tools emerge.

Architectural patterns change.

But curiosity remains useful.

Don't just ask:

"How do I use this?"

Ask:

"Why does this work?"

Don't just learn:

"How to use Docker."

Understand:

"What problem is containerization solving?"

Don't just learn:

"How to use Kubernetes."

Understand:

"Why would a team need this level of orchestration?"

Don't just learn:

"How to call an AI API."

Understand:

"What makes an AI-powered feature reliable enough for production?"

Understanding principles gives you skills that survive technology changes.


19. Build Things That Teach You Something

Tutorials are useful.

Courses are useful.

Documentation is essential.

But eventually, build something.

Not because you need another GitHub repository.

Build because real projects force you to confront problems tutorials often hide.

Build an application that has:

  • authentication
  • error handling
  • logging
  • database migrations
  • background jobs
  • rate limiting
  • validation
  • tests
  • deployment
  • monitoring

Then watch what breaks.

That is where learning happens.

Maybe your first implementation is bad.

Good.

Fix it.

Maybe your database design doesn't scale.

Good.

Understand why.

Maybe deployment fails.

Good.

Now you know something you didn't know yesterday.

Projects don't have to be huge.

A small application that you deeply understand can teach more than ten copied tutorials.


20. Write Things Down

One of the most underrated developer habits is documentation.

When you solve a difficult problem, write down the solution.

When you learn something surprising, write it down.

When production breaks, document what happened.

When you make an architectural decision, record why.

This becomes your personal engineering knowledge base.

Months later, you may search for:

"Why did we add this workaround?"

And find your own answer.

Writing also exposes gaps in understanding.

If you cannot explain something simply, you may not understand it as well as you think.

You don't need to publish everything.

A private engineering notebook can be enough.


21. Protect Your Attention

There is another problem modern developers face:

Too much information.

Every day there are:

  • new frameworks
  • new AI models
  • new libraries
  • new tutorials
  • new newsletters
  • new programming trends
  • new developer tools
  • new opinions

It is easy to spend more time learning about programming than actually programming.

You don't need to know everything.

Choose a direction.

Go deep.

Build.

Reflect.

Then expand.

A developer who understands five technologies deeply can often be more effective than someone who knows fifty technologies superficially.

Depth compounds.


22. Learn the Business Behind the Software

This is one of the biggest career accelerators.

Don't only ask:

"What does this function do?"

Ask:

"Why does the business need this?"

Imagine you're building a payment system.

A technical requirement might say:

"Create payment endpoint."

But the business context could involve:

  • fraud prevention
  • refunds
  • chargebacks
  • accounting
  • taxes
  • currency conversion
  • reconciliation
  • customer notifications
  • compliance

Without understanding the business, you may build technically correct software that solves the wrong problem.

Developers who understand both technology and business context can make better decisions.

They don't just ask:

"Can we build it?"

They ask:

"Should we build it?"

That's a much more valuable question.


23. Learn From Production

A project isn't finished when the pull request is merged.

That's when another phase begins.

Production teaches things development environments can't.

You learn:

  • how users actually behave
  • which assumptions were wrong
  • which features matter
  • where performance breaks
  • what monitoring is missing
  • what edge cases were ignored

If you have access to production metrics, learn from them.

Look at:

  • error rates
  • latency
  • traffic
  • failed requests
  • usage patterns
  • database performance
  • infrastructure costs

Your users are constantly giving you information.

Good engineers listen.


24. Don't Be Afraid to Delete Code

Developers love creating.

Deleting feels dangerous.

But sometimes deleting code is the highest-value engineering work.

A feature nobody uses.

An abstraction nobody needs.

A dependency that adds complexity.

A dead endpoint.

An old configuration.

A duplicated implementation.

A workaround whose original problem no longer exists.

Every line of code has a maintenance cost.

Deleting 500 unnecessary lines can sometimes be more valuable than writing 500 new ones.

A mature developer doesn't measure productivity only by how much code they produce.

Sometimes productivity means:

"We no longer need this code."


25. What Actually Makes Someone a Great Developer?

After all the frameworks, languages, tools, architectures, and technologies, I think it comes down to a few things.

A great developer:

Can turn ambiguity into clarity.

Can investigate instead of guessing.

Can simplify instead of unnecessarily complicating.

Can communicate clearly.

Can admit when they don't know something.

Can learn from mistakes.

Can understand the business problem behind the technical requirement.

Can work with other people without making every disagreement personal.

Can write code that another person can maintain.

Can use modern tools without becoming dependent on them.

Can make trade-offs consciously.

Can think beyond the immediate ticket.

And perhaps most importantly:

They care about the outcome, not just the code.


26. The Developer You Become Is Built From Small Habits

You don't suddenly wake up one morning and become a great engineer.

It happens gradually.

One better question.

One cleaner pull request.

One useful code review.

One carefully investigated bug.

One documented decision.

One unnecessary abstraction removed.

One difficult conversation handled professionally.

One production incident analyzed properly.

One technology understood deeply instead of superficially.

One mistake honestly acknowledged.

These things seem small.

But careers are made from small things repeated for years.


27. A Challenge for Developers

Here's a challenge.

For your next project, don't focus only on the code.

Try these five things:

1. Before coding, write down the actual problem.

Not the requested feature.

The underlying problem.

2. Before adding a dependency, ask whether you really need it.

Maybe you do.

Maybe you don't.

3. Before optimizing, measure.

Find the bottleneck first.

4. Before closing a bug, ask why it happened.

Fix the cause, not only the symptom.

5. Before finishing the project, ask:

"What will make this easier for the next developer?"

Then act on the answer.


The Question I Want to Leave With You

Technology will continue changing.

The tools you use today may not be the tools you use five years from now.

Some frameworks will disappear.

Some languages will become more popular.

AI will change how we write software.

Cloud infrastructure will continue evolving.

But the fundamental problems of engineering won't disappear.

We will still need to understand problems.

We will still need to make trade-offs.

We will still need to communicate.

We will still need to debug.

We will still need to design systems.

We will still need to work with people.

And we will still need judgment.

So maybe the most important question isn't:

"What technology should I learn next?"

Maybe it's:

"What kind of developer am I becoming?"

Are you becoming someone who writes more code?

Or someone who solves better problems?

Are you becoming someone who knows more tools?

Or someone who understands systems more deeply?

Are you becoming someone who always has an answer?

Or someone who knows how to find the right answer?

Are you becoming someone who wants to be right?

Or someone who wants the team to make the right decision?

Those differences may seem small today.

Over a career, they become enormous.

The future belongs not only to developers who can write code quickly, but to developers who can think clearly about what should be built, why it should be built, and how to build it responsibly.

And that's a skill no framework can install for you.


Your Turn

I'd genuinely like to hear from other developers here:

What is one developer skill you learned outside of programming that made you significantly better at your job?

It could be:

  • Communication
  • Debugging
  • Writing
  • Time management
  • System design
  • Asking questions
  • Leadership
  • Business understanding
  • Documentation
  • Code review
  • Problem solving
  • Working with difficult teammates
  • Learning how to say "I don't know"
  • Or something completely different

What skill took you the longest to learn—and what finally made it click?

Share your experience below.

Someone reading your comment might be struggling with the exact same thing you struggled with a few years ago.

Sometimes the most valuable thing we can give another developer isn't another tutorial.

It's the lesson we learned the hard way.

2 Comments

1 vote
2 votes
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23

Merancang Backend Bisnis ISP: API Pelanggan, Paket Internet, Invoice, dan Tiket Support

Masbadar - Mar 13

Your Tech Stack Isn’t Your Ceiling. Your Story Is

Karol Modelski - Apr 9

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

From Prompts to Goals: The Rise of Outcome-Driven Development

Tom Smithverified - Apr 11
chevron_left
5k Points201 Badges
81Posts
147Comments
49Connections
I enjoy building web applications and exploring new technologies. Most of my time goes into improvin... Show more

Commenters (This Week)

6 comments
2 comments
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!