DEV Community

Cover image for 10 Coding Mistakes Developers Should Avoid in 2026 (and How to Fix Them)
Dhruv Joshi
Dhruv Joshi

Posted on Edited on

10 Coding Mistakes Developers Should Avoid in 2026 (and How to Fix Them)

Writing code that works is only the beginning.

In 2026, developers are shipping software faster than ever with AI coding assistants, code-generation tools, automation, frameworks, APIs, and reusable packages.

That speed is useful but it creates a new problem:

It is becoming easier to generate code faster than we can understand, review, test, and maintain it.

The best developers are not necessarily the ones who write the most code. They are the ones who can consistently ship code that is:

  • Easy to understand
  • Easy to change
  • Secure by default
  • Testable
  • Observable
  • Reviewable
  • Maintainable by someone other than the original author

I’m Dhruv Joshi, an AI web and mobile app developer and tech writer with 10 years of experience building software products, working with development teams, and writing about modern software engineering.

In this guide, I'll cover 10 common coding mistakes developers should avoid in 2026, including mistakes that have become more important as AI-assisted development becomes part of everyday engineering workflows.


TL;DR: 10 Coding Mistakes to Avoid in 2026

If you only remember one thing from this article, remember this:

Do not optimize for writing more code. Optimize for making correct code easier to understand, verify, change, and operate.

Here are the 10 mistakes:

  1. Overengineering simple problems
  2. Blindly trusting AI-generated or copied code
  3. Hardcoding configuration, secrets, and environment values
  4. Ignoring errors, logs, and observability
  5. Writing comments and documentation that add no context
  6. Ignoring dependency and runtime lifecycle health
  7. Skipping tests or writing low-value tests
  8. Optimizing performance before measuring it
  9. Using Git and pull requests poorly
  10. Staying stuck instead of asking for review or help

Let's look at each one.


1. Overengineering Simple Problems

One of the easiest ways to make a codebase difficult to maintain is to solve a simple problem with unnecessary complexity.

Developers sometimes add:

  • Extra abstractions
  • Unnecessary design patterns
  • Deep inheritance hierarchies
  • Premature microservices
  • Generic systems for one specific use case
  • Layers that exist only because they might be useful later

This often makes the code look sophisticated while making the actual problem harder to understand.

Bad approach

const result = users
  .map(user => ({
    ...user,
    activeStatus: user.status === "active" ? true : false
  }))
  .filter(user => user.activeStatus === true)
  .reduce((acc, user) => {
    acc.push(user.name);
    return acc;
  }, []);
Enter fullscreen mode Exit fullscreen mode

Better approach

const activeUserNames = users
  .filter(user => user.status === "active")
  .map(user => user.name);
Enter fullscreen mode Exit fullscreen mode

Both can produce the same result.

The second version communicates the intention almost immediately.

How to avoid overengineering

  • Prefer the simplest solution that satisfies the real requirement.
  • Keep functions focused on one responsibility.
  • Introduce abstractions when repeated complexity actually exists.
  • Use meaningful variable and function names.
  • Avoid design patterns just because they are popular.
  • Do not build infrastructure for imaginary future requirements.
  • Refactor when the codebase gives you evidence that an abstraction is needed.

A useful rule is:

Solve today's real problem cleanly before designing for tomorrow's hypothetical problem.

Clean code is not about being clever.

It is about reducing the amount of thinking required to understand what the code does.


2. Blindly Trusting AI-Generated or Copied Code

Copy-pasting code without understanding it has always been risky.

In 2026, that problem is bigger because the code may now come from:

  • AI coding assistants
  • Autonomous coding agents
  • Chatbots
  • Stack Overflow answers
  • GitHub repositories
  • Tutorials
  • Internal snippets
  • Generated boilerplate

AI can be extremely useful for implementation, debugging, refactoring, tests, documentation, and explaining unfamiliar code.

But generated code is still code you are responsible for shipping.

It may:

  • Solve the wrong problem
  • Use an outdated API
  • Invent a method or package
  • Miss an edge case
  • Introduce a security vulnerability
  • Break existing architecture
  • Add unnecessary dependencies
  • Pass simple tests while failing in production conditions

Bad workflow

Prompt AI
↓
Copy code
↓
It compiles
↓
Ship it
Enter fullscreen mode Exit fullscreen mode

Better workflow

Generate suggestion
↓
Understand the approach
↓
Compare it with the existing codebase
↓
Check documentation
↓
Review security implications
↓
Run tests
↓
Review the diff
↓
Ship
Enter fullscreen mode Exit fullscreen mode

Before accepting AI-generated code, ask:

  1. Do I understand what this code does?
  2. Does it match the actual requirement?
  3. Does it fit the existing architecture?
  4. Are the APIs and dependencies real and current?
  5. Could it expose secrets or sensitive data?
  6. What happens when the input is invalid?
  7. What happens when a network call fails?
  8. Are authorization checks missing?
  9. Are there tests for important edge cases?
  10. Could I explain this implementation during code review?

If you cannot explain the code, you are not ready to own it.

AI should accelerate engineering judgment, not replace it.

Recommended Reading: 12 Secrets to Use an Android App Developer for a Successful Business Product


3. Hardcoding Configuration, Secrets, and Environment Values

Hardcoding is more than a maintainability problem.

In the wrong place, it becomes a security and deployment problem.

Bad example

const API_URL = "https://production-api.example.com";
const API_KEY = "my-secret-key";
Enter fullscreen mode Exit fullscreen mode

Do not put credentials, tokens, private keys, database passwords, or production secrets directly inside source code.

Even private repositories should not be treated as secret-management systems.

Better approach

const API_URL = process.env.API_URL;
const API_KEY = process.env.API_KEY;
Enter fullscreen mode Exit fullscreen mode

Use the appropriate mechanism for your environment, such as:

  • Environment variables
  • Secret managers
  • Configuration files
  • CI/CD secret storage
  • Platform-specific configuration
  • Constants for genuine application constants

Important distinction

Not every literal value is automatically bad.

This is perfectly reasonable:

const MAX_LOGIN_ATTEMPTS = 5;
Enter fullscreen mode Exit fullscreen mode

The problem is scattering values that represent configuration, secrets, business rules, or environment-specific behavior throughout your codebase.

A good rule

Use:

  • Constants for stable application values
  • Configuration for behavior that may change
  • Environment variables for environment-specific values
  • Secret-management systems for credentials

And if a secret accidentally reaches Git history, changing the current file is not enough.

Rotate the exposed credential.


4. Ignoring Errors, Logs, and Observability

An application working on your laptop does not mean it will behave correctly in production.

Real systems experience:

  • Invalid user input
  • Timeouts
  • Network failures
  • Database errors
  • Rate limits
  • Third-party API failures
  • Partial failures
  • Unexpected states
  • Resource exhaustion
  • Deployment mistakes

Ignoring these conditions makes debugging much harder.

Bad approach

try {
  await saveUser(user);
} catch (error) {
  console.log("Something went wrong");
}
Enter fullscreen mode Exit fullscreen mode

This tells you almost nothing.

Better approach

try {
  await saveUser(user);
} catch (error) {
  logger.error("Failed to save user", {
    userId: user.id,
    error: error.message
  });

  throw error;
}
Enter fullscreen mode Exit fullscreen mode

The exact implementation depends on your application, but the principle is universal:

Errors should contain enough context to help you understand what failed without leaking sensitive information.

Good production code should answer questions like:

  • What failed?
  • Where did it fail?
  • When did it fail?
  • Which request or operation was involved?
  • How often is it happening?
  • Is the problem getting worse?
  • Can the user recover?
  • Should the system retry?
  • Does someone need to be alerted?

Logs are only one piece of observability.

Depending on the application, also consider:

  • Metrics
  • Traces
  • Error tracking
  • Performance monitoring
  • Request IDs
  • Health checks
  • Alerts

Also avoid logging passwords, access tokens, payment information, or other sensitive user data.


5. Writing Comments That Explain the Obvious

This comment does not help:

// Increment count by 1
count++;
Enter fullscreen mode Exit fullscreen mode

The code already communicates that.

A useful comment explains why something exists, especially when the reason cannot be understood from the code alone.

Better example

// Keep this timeout below the load balancer's 30-second limit
// so requests fail here instead of being terminated upstream.
const REQUEST_TIMEOUT_MS = 25_000;
Enter fullscreen mode Exit fullscreen mode

That comment preserves important engineering context.

What deserves documentation?

Document things such as:

  • Non-obvious business rules
  • Architectural decisions
  • Unexpected workarounds
  • API contracts
  • Security-sensitive behavior
  • Operational requirements
  • Migration constraints
  • Known limitations
  • Reasons behind unusual implementation choices

But do not use comments to compensate for unnecessarily confusing code.

Instead of:

// Check whether user is allowed to edit
if (u.r === 1 || u.id === p.uid) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Prefer:

const canEditPost =
  user.isAdmin || user.id === post.authorId;

if (canEditPost) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Clear code reduces how many comments you need.

Documentation matters even more with AI

AI coding tools work better when your repository contains useful context.

Good:

  • READMEs
  • API documentation
  • Architecture notes
  • Naming conventions
  • Tests
  • Examples
  • Contribution guidelines

help both humans and AI tools understand the intended behavior of your codebase.


6. Ignoring Dependency and Runtime Lifecycle Health

"Always use the newest technology" is not good engineering advice.

But neither is running unsupported software forever.

The better principle is:

Use maintained technology and understand the lifecycle of every important dependency you introduce.

Modern applications often depend on hundreds or thousands of direct and transitive packages.

That creates risk.

A dependency can become:

  • Vulnerable
  • Unmaintained
  • Deprecated
  • Incompatible
  • Compromised
  • Abandoned

Better dependency hygiene

  • Keep your runtime on a supported version.
  • Review dependency updates regularly.
  • Remove packages you no longer use.
  • Prefer well-maintained dependencies.
  • Check changelogs before major upgrades.
  • Use automated vulnerability scanning.
  • Pin or lock versions appropriately.
  • Review new dependencies before adding them.
  • Pay attention to transitive dependencies.
  • Keep CI/CD tooling updated too.

Before installing another package, ask:

Do I really need a dependency for this?

Sometimes a package saves days of engineering effort.

Sometimes it saves five lines of code while adding another component to your software supply chain.

Those are not the same trade-off.


7. Skipping Tests or Writing Tests That Prove Nothing

Testing is not about achieving an impressive percentage on a dashboard.

It is about creating confidence that important behavior will continue to work when the code changes.

What should you test?

Prioritize:

  • Core business logic
  • Security-sensitive behavior
  • Data transformations
  • Authentication and authorization
  • Payment flows
  • Important API contracts
  • Failure scenarios
  • Regression-prone code
  • Critical user journeys

Example

function calculateDiscount(total, isPremium) {
  if (isPremium && total >= 100) {
    return total * 0.9;
  }

  return total;
}
Enter fullscreen mode Exit fullscreen mode

Useful tests would cover more than the happy path:

expect(calculateDiscount(200, true)).toBe(180);
expect(calculateDiscount(50, true)).toBe(50);
expect(calculateDiscount(200, false)).toBe(200);
expect(calculateDiscount(100, true)).toBe(90);
Enter fullscreen mode Exit fullscreen mode

Avoid testing implementation details unnecessarily

A brittle test may break every time you refactor even though user-visible behavior has not changed.

Whenever possible, test behavior and contracts rather than internal implementation details.

Your tests should help answer:

"Can I change this code without being terrified of breaking something important?"

If the answer is yes, your test suite is doing useful work.


8. Optimizing Performance Before Measuring It

Performance matters.

Premature optimization does not.

Developers often spend time optimizing code that:

  • Is not actually slow
  • Runs infrequently
  • Has no measurable effect on users
  • Makes the implementation harder to understand
  • Distracts from a much larger bottleneck

Bad approach

"This loop looks inefficient. Let's rewrite the architecture."

Better approach

Measure first.

Ask:

  • What is actually slow?
  • Is the bottleneck frontend, backend, database, network, or infrastructure?
  • How frequently does this code execute?
  • What is the current latency?
  • What improvement would users actually notice?
  • Is the optimization worth the added complexity?

Use tools such as:

  • Profilers
  • Database query analysis
  • Application performance monitoring
  • Browser performance tools
  • Load tests
  • Real production metrics

A useful development sequence is:

Make it correct
→
Make it clear
→
Measure it
→
Optimize what matters
Enter fullscreen mode Exit fullscreen mode

Do not sacrifice maintainability for a theoretical performance improvement you have never measured.


9. Using Git and Pull Requests Poorly

Git is not simply a backup system.

It is part of your team's collaboration, review, history, debugging, rollback, and release process.

Common mistakes include:

  • Huge commits containing unrelated changes
  • Meaningless messages like fix, update, or changes
  • Committing generated files unnecessarily
  • Committing secrets
  • Working for days without committing
  • Giant pull requests nobody can realistically review
  • Mixing refactoring and feature changes into one massive diff
  • Pushing directly to protected production branches

Better commits

Instead of:

update stuff
Enter fullscreen mode Exit fullscreen mode

Prefer:

fix duplicate payment submission on checkout
Enter fullscreen mode Exit fullscreen mode

The message communicates what changed.

Keep changes reviewable

A good pull request should make it relatively easy to answer:

  • What problem does this solve?
  • Why was this approach chosen?
  • What changed?
  • How was it tested?
  • Is there a migration?
  • Are there security implications?
  • How can the change be rolled back?

Smaller, focused pull requests are usually easier to:

  • Review
  • Test
  • Debug
  • Revert
  • Merge safely

Your future teammates and your future self, will thank you.


10. Staying Stuck Instead of Asking for Help

There is value in struggling with a problem long enough to learn from it.

There is much less value in spending five hours silently debugging something a teammate could identify in five minutes.

Good developers know when to investigate independently and when to escalate.

Before asking for help, collect useful information:

What am I trying to achieve?

What did I expect?

What actually happened?

What have I already tried?

What does the error say?

Can I reproduce it?

What changed recently?
Enter fullscreen mode Exit fullscreen mode

Then ask a specific question.

Instead of:

"My code doesn't work. Any idea why?"

Try:

"This request returns 401 after token refresh. The refresh endpoint succeeds, but the following API call still uses the previous access token. I've verified the new token is stored correctly. Which part of the request lifecycle should I inspect next?"

That is much easier for someone to help with.

Where should developers ask for help?

Depending on the problem:

  • Teammates
  • Code reviewers
  • Senior engineers
  • Official documentation
  • Maintainer repositories
  • Stack Overflow
  • Developer communities
  • AI assistants

AI is useful here too but it should not become a substitute for asking someone who understands your product, architecture, users, or business requirements.

Sometimes human context is the missing dependency.


A 2026 Code Review Checklist

Before you merge or deploy a meaningful change, ask:

Correctness

  • [ ] Does the code solve the actual requirement?
  • [ ] Have I handled important edge cases?
  • [ ] Are failure conditions handled correctly?

AI-generated code

  • [ ] Do I understand every meaningful part of generated code?
  • [ ] Did I verify APIs, packages, and assumptions?
  • [ ] Did I review the generated code instead of trusting it automatically?

Security

  • [ ] Are secrets kept out of source code?
  • [ ] Is user-controlled input validated?
  • [ ] Are authentication and authorization checks correct?
  • [ ] Did I introduce a new dependency unnecessarily?
  • [ ] Could logs expose sensitive information?

Maintainability

  • [ ] Are names clear?
  • [ ] Is the solution more complicated than necessary?
  • [ ] Are important decisions documented?
  • [ ] Could another developer understand this six months from now?

Testing

  • [ ] Are critical paths tested?
  • [ ] Are important failure cases tested?
  • [ ] Did I manually verify behavior where appropriate?

Operations

  • [ ] Will failures produce useful logs or telemetry?
  • [ ] Can the change be safely rolled back?
  • [ ] Are configuration changes documented?

Git

  • [ ] Is the pull request focused?
  • [ ] Are commit messages meaningful?
  • [ ] Did I inspect the final diff before merging?

That final step is surprisingly valuable:

Always read your own diff before asking someone else to review it.


Frequently Asked Questions

What is the biggest coding mistake developers make in 2026?

One of the biggest mistakes is trusting code you did not understand or verify, especially AI-generated code.

AI assistants can dramatically speed up development, but developers still need to review generated code for correctness, security, maintainability, architectural fit, and edge cases.

The developer remains responsible for the software that reaches production.


Is using AI for coding a mistake?

No.

AI can be extremely useful for:

  • Generating boilerplate
  • Explaining unfamiliar code
  • Debugging
  • Refactoring
  • Writing tests
  • Exploring APIs
  • Documentation
  • Code review assistance

The mistake is treating generated code as automatically correct.

Use AI as an engineering assistant, not an unquestionable authority.


Is AI-generated code safe for production?

Not automatically.

Treat AI-generated code similarly to code written by an unfamiliar contributor.

Review it, understand it, test it, validate dependencies, check security implications, and make sure it follows your application's architecture and standards before shipping it.


How can I write cleaner code?

Focus on clarity before cleverness.

A few habits help significantly:

  • Keep functions focused.
  • Use descriptive names.
  • Remove unnecessary abstractions.
  • Avoid duplicated business logic.
  • Keep dependencies intentional.
  • Handle errors explicitly.
  • Write tests around important behavior.
  • Document why unusual decisions exist.
  • Refactor when complexity becomes visible.

Clean code is code another developer can understand and safely modify.


Is hardcoding always bad?

No.

Some constants belong directly in code.

The bigger problem is hardcoding values that should change independently of the application, including:

  • Secrets
  • Credentials
  • Environment-specific URLs
  • Deployment configuration
  • Frequently changing business configuration

Choose the storage mechanism based on what the value represents.


Should beginners write automated tests?

Yes.

You do not need to master every testing framework immediately.

Start by testing small functions and important business logic. Over time, learn when to use unit, integration, API, end-to-end, and other forms of testing.

Learning to think in terms of inputs, outputs, edge cases, and failure conditions will also make you a better programmer.


How often should developers commit code?

Commit after completing a small, logical unit of work.

There is no perfect number of commits per day.

The goal is to create a history that is:

  • Understandable
  • Reviewable
  • Reversible
  • Useful during debugging

Avoid both enormous multi-day commits and meaningless commits every few minutes.


Should developers still learn programming fundamentals when AI can generate code?

Absolutely.

AI makes fundamentals more valuable, not less valuable.

To verify generated code, you need to understand concepts such as:

  • Data structures
  • Control flow
  • APIs
  • Databases
  • Networking
  • Authentication
  • Security
  • Testing
  • Architecture
  • Performance
  • Debugging

The faster code can be generated, the more valuable good engineering judgment becomes.


Final Thoughts

The biggest coding mistakes in 2026 are not necessarily syntax errors.

Modern development problems increasingly come from shipping code faster than teams can understand and verify it.

Whether the code was written manually, copied from a tutorial, suggested by an AI assistant, or created by an autonomous coding agent, the same engineering principles still matter:

Keep it simple.

Understand what you ship.

Protect secrets.

Handle failure intentionally.

Maintain your dependencies.

Test important behavior.

Measure before optimizing.

Keep changes reviewable.

Document important context.

Ask for help when it saves the team time.

Tools will continue to change.

Frameworks will change.

AI models will change.

But clear thinking, verification, maintainability, and good engineering judgment will remain valuable.


Sources That Informed This 2026 Update

This guide was updated using current engineering and search guidance, including:

  • Stack Overflow Developer Survey 2026 — AI usage, trust, verification, developer workflows, and knowledge sources
  • OWASP Top 10:2025 — software supply chain, security configuration, logging, and exceptional-condition risks
  • Google Search Central — people-first content and generative AI search guidance
  • DEV Community Editor Guide — Markdown structure, headings, front matter, and publishing conventions
  • GitHub engineering research and 2026 updates — AI-assisted development, code review, secret protection, and software security

About the Author

Dhruv Joshi is an AI web and mobile app developer and tech writer with 10 years of experience in software development, technical content, mobile applications, web applications, AI tools, and modern engineering practices.

He writes practical guides for developers, startups, and technology teams that want to build better digital products without sacrificing maintainability, security, or code quality.

💡 Building a web, mobile, or AI product and need engineering support

Contact Quokka Labs.


Last updated: October, 2026

Top comments (10)

Collapse
 
aarone4 profile image
Aaron Reese •

Avoid over simplifying your code. The code needs to be as complex and the business case needs but no MORE complicated. Follow conventions established in the industry, language or corporate culture as this leads to less cognitive load for future readers.

Copy and paste when it is appropriate to do so: save on cognitive load to implement a pattern or configuration. Do not copy-paste within your code base more than once. If you have to use it a 3rd time, refactor.

Hard coded values. YUP. No argument there. Make sure you put the values in a config file and DO NOT put the config file into source code control but DO PUT a sample config file into SCC.

Always assume errors and code defensively. Your database may be slow, the API may be throttled, the user may have entered garbage in your form. But use a convention so that the happy path is easy to follow: abort early from errors, throw exceptions and handle issues in function calls to keep error processing out if the main thread

DONT comment your code. It should be perfectly able to grok the logic with clean code principles: properly named and scoped variables, classes, functions and file names. DO add comments for WHY, but not HOW or WHAT. Don't leave derelict code wrapped in comments; those are the responsibility of the source code control

Use long established, stable, reliable legacy code that has all the edge cases dealt with. Keep abreast of any security or performance issues in packages you use. Where possible use one version across your codebase. There is nothing more annoying than having solution seven different versions of Angular:)

Write your tests before your code. Firstly it ensures you understand the business problem you are trying to solve, secondly it will force you to write testable code.

Collapse
 
dhruvjoshi9 profile image
Dhruv Joshi •

Thanks for this!

Collapse
 
margarizaldi profile image
Marga Rizaldi •

Your comment is only motivated by debating purpose, to tackle someone so you will look better huh?

What's the point of "The code needs to be as complex .... but no MORE complicated." compared to the "avoid over complexity" from the post?

Then the post suggests not to copy codes from other source unless we understand it to avoid any unwanted issues, that should be clear that the case is from "other source" like stack overflow etc, then how could you think about "cognitive load"?

For config, what's wrong with it to be in the source code? Any config can be included or put everywhere as long as no credentials there.

See? One paragraph above is an example of "pointless argument" like what you did, I wrote that for you to let you know how it feels.

The same for errors, outdated tech, etc. you just wanted to argue with, again, pointless arguments.

Finally, the post talks about tips (and preference) so we don't need to be that hard to argue every single point, which is childish and embarrassing.

Thank you.

Collapse
 
aaronre16397861 profile image
Aaron Reese • • Edited

wow, passive agressive or what...
Of course it is for debating purposes, that is one of the objectives of DEV as a community. The point of my reply was to stimulate debate and to also alert less experienced members that these points are not absulutes.

Complex and complicated are not the same thing; in fact the more complex your code the LESS complicated it needs to be. Complex relates to the business requirements and the code glue for your particular stack. Complicated relates to how you approach the code base: Are you applying SOLID principals, do you have separation of concerns between front and and back end code, Are you putting different levels of functionality in separate files and namespaces etc.

Copy-Paste. Yes you should understand code you are C-Ping but I wouldn't advocate writing my own if there is tried and tested pattern already established. Just look at all the packages available in NuGet or NPM that have been battle-hardened by use in thousands of projects. That's not to say they are infallible (left-pad anyone??) but you are way less likely to get into trouble with them and you won't waste months of development time when you could be adding value.

Config should NOT be in source code control PRECISELY because it CAN contain sensitive information. If you start splitting CONFIG into safe config and risky config you are asking for trouble. I did say a SAMPLE config should be included so that future devs and anyone building the system on a new platform knows what shape it should be. Also, when deploying to production, you will should pull down from the head of the repository and having the config file in there will overwrite all your production settings with the Dev settings - not good.

For Outdated, I was trying to make the distinction between stable, known technologies that could be considered boring and the 'cutting edge' that we mostly like to work in. JQuery is still a valid choice for many projects even though many of the functions it was leveraged for are now available as native APIs in the browser. CodeIgniter is a perfectly fine MVC framework for may projects: they don't need the complexity of Laravel or Symphony.

Why is providing a counter point to every case childish? I'm not embarresed to be open to expaniding my knowlege and understanding.

Collapse
 
yolocat profile image
yolocat-dev •

Perfect explanation!

Collapse
 
sique976 profile image
San D. •

Great tips! Very well!🙂

Collapse
 
dhruvjoshi9 profile image
Dhruv Joshi •

Glad you liked it!

Collapse
 
gjeotech profile image
Onyeacholem Ifeanyi Joshua •

Lovely.. thanks 👍

Collapse
 
labsquokka profile image
Quokka Labs •

Useful tips @dhruvjoshi9. thanks for sharing

Collapse
 
dhruvjoshi9 profile image
Dhruv Joshi •

Thank you!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.