<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kent Phung</title>
    <description>The latest articles on DEV Community by Kent Phung (@khapu2906).</description>
    <link>https://dev.to/khapu2906</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F459745%2F8ae6c506-691f-48d5-89a4-0ad11e004519.jpg</url>
      <title>DEV Community: Kent Phung</title>
      <link>https://dev.to/khapu2906</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khapu2906"/>
    <language>en</language>
    <item>
      <title>A CEO Said AI Replaced Developers. Then an Entire Engineering Community Opened DevTools.</title>
      <dc:creator>Kent Phung</dc:creator>
      <pubDate>Wed, 22 Jul 2026 02:36:51 +0000</pubDate>
      <link>https://dev.to/khapu2906/a-ceo-said-ai-replaced-developers-then-an-entire-engineering-community-opened-devtools-2k7l</link>
      <guid>https://dev.to/khapu2906/a-ceo-said-ai-replaced-developers-then-an-entire-engineering-community-opened-devtools-2k7l</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feoya8ncydjit2q39jkyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feoya8ncydjit2q39jkyg.png" alt=" " width="800" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A story about AI, software engineering, and the difference between shipping code and shipping production systems.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few days ago, a post from a Vietnamese CEO sent shockwaves through the local tech community.&lt;/p&gt;

&lt;p&gt;His claim was bold.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I pay around $20/month for Claude. It replaced developers for our internal software."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He argued that small and medium businesses no longer needed software developers, expensive SaaS subscriptions, or months of development.&lt;/p&gt;

&lt;p&gt;Instead, they could simply describe what they wanted in natural language, and AI would build it.&lt;/p&gt;

&lt;p&gt;The post spread rapidly across social media.&lt;/p&gt;

&lt;p&gt;Thousands of people agreed.&lt;/p&gt;

&lt;p&gt;Some celebrated it as the future of software development.&lt;/p&gt;

&lt;p&gt;Others saw it as the beginning of the end for software engineers.&lt;/p&gt;

&lt;p&gt;Everyone seemed to have an opinion.&lt;/p&gt;

&lt;p&gt;Then, a few days later, something interesting happened.&lt;/p&gt;

&lt;p&gt;A handful of engineers managed to find the application behind the viral post.&lt;/p&gt;

&lt;p&gt;Out of curiosity, they did what engineers naturally do.&lt;/p&gt;

&lt;p&gt;They opened the website.&lt;/p&gt;

&lt;p&gt;They pressed F12.&lt;/p&gt;

&lt;p&gt;They opened DevTools.&lt;/p&gt;

&lt;p&gt;At first, nobody was trying to prove anyone wrong. They simply wanted to understand how it had been built.&lt;/p&gt;

&lt;p&gt;Then the first screenshot appeared.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Wait... why is this exposed in the frontend?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few minutes later, another one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This credential shouldn't be here."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then another.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is the admin page actually protected?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More engineers joined in.&lt;/p&gt;

&lt;p&gt;Some inspected the JavaScript bundle.&lt;/p&gt;

&lt;p&gt;Others monitored the network requests.&lt;/p&gt;

&lt;p&gt;Some traced the API calls.&lt;/p&gt;

&lt;p&gt;Within hours, screenshots, code snippets, and technical analyses started spreading across engineering groups in Vietnam.&lt;/p&gt;

&lt;p&gt;One finding became five.&lt;/p&gt;

&lt;p&gt;Five became twenty.&lt;/p&gt;

&lt;p&gt;The conversation was no longer about whether AI could generate code.&lt;/p&gt;

&lt;p&gt;It had evolved into a much more interesting question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What's the difference between software that works and software that's ready for production?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  First Impression
&lt;/h2&gt;

&lt;p&gt;To be fair, the application looked surprisingly good.&lt;/p&gt;

&lt;p&gt;The UI was clean.&lt;/p&gt;

&lt;p&gt;Authentication existed.&lt;/p&gt;

&lt;p&gt;Users could log in.&lt;/p&gt;

&lt;p&gt;Data could be created and updated.&lt;/p&gt;

&lt;p&gt;If someone had shown me only the demo video, I probably would've said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Wow. AI is getting incredibly good."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And honestly, I still believe that.&lt;/p&gt;

&lt;p&gt;Because what happened next wasn't evidence that AI is bad.&lt;/p&gt;

&lt;p&gt;It was evidence that software engineering is much bigger than writing code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The First Five Minutes
&lt;/h2&gt;

&lt;p&gt;The first thing experienced engineers inspect usually isn't the UI.&lt;/p&gt;

&lt;p&gt;It's what the browser already knows.&lt;/p&gt;

&lt;p&gt;Within minutes, several issues became obvious.&lt;/p&gt;

&lt;p&gt;Sensitive configuration values were exposed directly in the frontend.&lt;/p&gt;

&lt;p&gt;Credentials that should never live inside client-side code were accessible.&lt;/p&gt;

&lt;p&gt;Administrative functionality wasn't actually protected by authorization.&lt;/p&gt;

&lt;p&gt;In one case, it was simply hidden from users using CSS.&lt;/p&gt;

&lt;p&gt;The browser wasn't supposed to display it.&lt;/p&gt;

&lt;p&gt;But nothing stopped someone from navigating there directly.&lt;/p&gt;

&lt;p&gt;Some API endpoints trusted the frontend far more than they should.&lt;/p&gt;

&lt;p&gt;Several security checks that normally belong on the server appeared to be missing.&lt;/p&gt;

&lt;p&gt;In several places, the application assumed users would behave honestly.&lt;/p&gt;

&lt;p&gt;Software rarely gets attacked by honest users.&lt;/p&gt;

&lt;p&gt;The most interesting part?&lt;/p&gt;

&lt;p&gt;None of these findings required sophisticated hacking techniques.&lt;/p&gt;

&lt;p&gt;Just a browser.&lt;/p&gt;

&lt;p&gt;A few minutes.&lt;/p&gt;

&lt;p&gt;And DevTools.&lt;/p&gt;




&lt;h2&gt;
  
  
  None of These Were AI Bugs
&lt;/h2&gt;

&lt;p&gt;This is where I think many discussions go wrong.&lt;/p&gt;

&lt;p&gt;People immediately say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"See? AI writes terrible code."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don't think that's true.&lt;/p&gt;

&lt;p&gt;Claude didn't randomly decide to expose secrets.&lt;/p&gt;

&lt;p&gt;It didn't intentionally replace authorization with CSS.&lt;/p&gt;

&lt;p&gt;It didn't wake up one morning and think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Today I'm going to ignore security best practices."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It simply optimized for the task it was given.&lt;/p&gt;

&lt;p&gt;If the prompt was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Build me an admin dashboard."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it built an admin dashboard.&lt;/p&gt;

&lt;p&gt;Not a secure production system.&lt;/p&gt;

&lt;p&gt;Those are two very different requests.&lt;/p&gt;

&lt;p&gt;AI did exactly what it was asked to do.&lt;/p&gt;

&lt;p&gt;The real problem wasn't AI.&lt;/p&gt;

&lt;p&gt;The real problem was assuming that generating code is the same as engineering software.&lt;/p&gt;

&lt;p&gt;It isn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Demo Was Successful. The Engineering Wasn't Finished.
&lt;/h2&gt;

&lt;p&gt;This is something our industry has struggled to explain for years.&lt;/p&gt;

&lt;p&gt;Many people think software engineering is writing code.&lt;/p&gt;

&lt;p&gt;It isn't.&lt;/p&gt;

&lt;p&gt;Writing code is only one small part of the job.&lt;/p&gt;

&lt;p&gt;Real engineering happens in the invisible layers.&lt;/p&gt;

&lt;p&gt;The things users never notice.&lt;/p&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Secret management&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Audit logging&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Backup strategies&lt;/li&gt;
&lt;li&gt;Disaster recovery&lt;/li&gt;
&lt;li&gt;Database migrations&lt;/li&gt;
&lt;li&gt;Infrastructure&lt;/li&gt;
&lt;li&gt;Threat modeling&lt;/li&gt;
&lt;li&gt;Performance under load&lt;/li&gt;
&lt;li&gt;Compliance&lt;/li&gt;
&lt;li&gt;Security reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these appear in a product demo.&lt;/p&gt;

&lt;p&gt;None of these make a startup launch video look cooler.&lt;/p&gt;

&lt;p&gt;Yet these are the things that determine whether software survives in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI Has Changed the Cost Curve
&lt;/h2&gt;

&lt;p&gt;This is actually the exciting part.&lt;/p&gt;

&lt;p&gt;Five years ago, building an MVP required a team.&lt;/p&gt;

&lt;p&gt;Today?&lt;/p&gt;

&lt;p&gt;One founder with AI can build something surprisingly impressive over a weekend.&lt;/p&gt;

&lt;p&gt;That's incredible.&lt;/p&gt;

&lt;p&gt;And honestly, I love it.&lt;/p&gt;

&lt;p&gt;More people can validate ideas.&lt;/p&gt;

&lt;p&gt;More startups can experiment.&lt;/p&gt;

&lt;p&gt;More businesses can automate repetitive work.&lt;/p&gt;

&lt;p&gt;AI has dramatically lowered the cost of creating software.&lt;/p&gt;

&lt;p&gt;That is unquestionably a good thing.&lt;/p&gt;

&lt;p&gt;But lowering the cost of creating software doesn't eliminate the need for engineering.&lt;/p&gt;

&lt;p&gt;It simply changes where engineering creates value.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Job Was Never Just Writing Code
&lt;/h2&gt;

&lt;p&gt;This is probably the biggest misconception I see online.&lt;/p&gt;

&lt;p&gt;People assume developers are paid to type.&lt;/p&gt;

&lt;p&gt;They're not.&lt;/p&gt;

&lt;p&gt;We're paid to reduce uncertainty.&lt;/p&gt;

&lt;p&gt;We're paid to reduce risk.&lt;/p&gt;

&lt;p&gt;Anyone can generate code.&lt;/p&gt;

&lt;p&gt;Experience helps answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens if someone bypasses the frontend?&lt;/li&gt;
&lt;li&gt;Can users access another customer's data?&lt;/li&gt;
&lt;li&gt;What if this service goes offline?&lt;/li&gt;
&lt;li&gt;How do we rotate secrets without downtime?&lt;/li&gt;
&lt;li&gt;Will this architecture still work with one million users?&lt;/li&gt;
&lt;li&gt;How do we recover after a failed deployment?&lt;/li&gt;
&lt;li&gt;What telemetry do we need when production breaks at 2 AM?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions rarely appear in prompts.&lt;/p&gt;

&lt;p&gt;But they appear every single day in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vibe Coding Isn't the Enemy
&lt;/h2&gt;

&lt;p&gt;In fact, I use AI every day.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude&lt;/li&gt;
&lt;li&gt;GPT&lt;/li&gt;
&lt;li&gt;Gemini&lt;/li&gt;
&lt;li&gt;Cursor&lt;/li&gt;
&lt;li&gt;GitHub Copilot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They've made me dramatically faster.&lt;/p&gt;

&lt;p&gt;AI writes boilerplate.&lt;/p&gt;

&lt;p&gt;AI explains unfamiliar code.&lt;/p&gt;

&lt;p&gt;AI generates tests.&lt;/p&gt;

&lt;p&gt;AI reviews pull requests.&lt;/p&gt;

&lt;p&gt;AI helps me prototype ideas in hours instead of days.&lt;/p&gt;

&lt;p&gt;It's one of the best productivity tools I've ever used.&lt;/p&gt;

&lt;p&gt;But I don't confuse acceleration with expertise.&lt;/p&gt;

&lt;p&gt;Giving a Formula 1 car to someone who just got a driver's license doesn't create a Formula 1 driver.&lt;/p&gt;

&lt;p&gt;It creates a faster beginner.&lt;/p&gt;

&lt;p&gt;AI works the same way.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Happened Here?
&lt;/h2&gt;

&lt;p&gt;Ironically, this story wasn't about a CEO.&lt;/p&gt;

&lt;p&gt;It wasn't about Claude.&lt;/p&gt;

&lt;p&gt;It wasn't even about security vulnerabilities.&lt;/p&gt;

&lt;p&gt;It exposed something much deeper.&lt;/p&gt;

&lt;p&gt;For years, many people—including our own industry—mistakenly equated software engineering with writing code.&lt;/p&gt;

&lt;p&gt;AI shattered that illusion.&lt;/p&gt;

&lt;p&gt;Writing code is becoming cheaper every month.&lt;/p&gt;

&lt;p&gt;Engineering judgment isn't.&lt;/p&gt;

&lt;p&gt;If anything, AI has made it even more valuable.&lt;/p&gt;

&lt;p&gt;Because now anyone can generate thousands of lines of code.&lt;/p&gt;

&lt;p&gt;The difficult part is knowing whether those thousands of lines should ever reach production.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Take
&lt;/h2&gt;

&lt;p&gt;I don't think AI is replacing software engineers.&lt;/p&gt;

&lt;p&gt;I think AI is replacing the part of software engineering that we mistakenly believed was the job.&lt;/p&gt;

&lt;p&gt;Typing code.&lt;/p&gt;

&lt;p&gt;The real work has always been:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding systems.&lt;/li&gt;
&lt;li&gt;Managing complexity.&lt;/li&gt;
&lt;li&gt;Designing for failure.&lt;/li&gt;
&lt;li&gt;Protecting users.&lt;/li&gt;
&lt;li&gt;Making good engineering decisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ironically, AI is making those skills more valuable than ever.&lt;/p&gt;

&lt;p&gt;Because when anyone can generate code...&lt;/p&gt;

&lt;p&gt;The hardest part is no longer writing software.&lt;/p&gt;

&lt;p&gt;It's knowing whether that software deserves to be deployed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The viral post wasn't wrong about one thing.&lt;/p&gt;

&lt;p&gt;AI has fundamentally changed software development.&lt;/p&gt;

&lt;p&gt;It has lowered barriers.&lt;/p&gt;

&lt;p&gt;It has empowered founders.&lt;/p&gt;

&lt;p&gt;It has made individual developers dramatically more productive.&lt;/p&gt;

&lt;p&gt;That's worth celebrating.&lt;/p&gt;

&lt;p&gt;But the engineering community's response reminded us of something equally important.&lt;/p&gt;

&lt;p&gt;There's a huge difference between &lt;strong&gt;software that impresses in a demo&lt;/strong&gt; and &lt;strong&gt;software that survives in production&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One proves an idea.&lt;/p&gt;

&lt;p&gt;The other earns trust.&lt;/p&gt;

&lt;p&gt;And trust has always been the hardest thing to engineer.&lt;/p&gt;

&lt;p&gt;Perhaps the biggest lesson from this story isn't that AI will or won't replace developers.&lt;/p&gt;

&lt;p&gt;It's that AI has finally forced us to answer a question our industry has been avoiding for years:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What do software engineers actually do?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And maybe, for the first time, we now have a better answer than simply saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We write code."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;What do you think?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Has AI changed what it means to be a software engineer?&lt;/p&gt;

&lt;p&gt;Or has it simply revealed what software engineering has always been about?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vibecoding</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Why Were Our AI Interviews Getting Easier?</title>
      <dc:creator>Kent Phung</dc:creator>
      <pubDate>Tue, 21 Jul 2026 07:35:14 +0000</pubDate>
      <link>https://dev.to/khapu2906/why-were-our-ai-interviews-getting-easier-dko</link>
      <guid>https://dev.to/khapu2906/why-were-our-ai-interviews-getting-easier-dko</guid>
      <description>&lt;p&gt;&lt;em&gt;The strange thing wasn't that more candidates were passing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The strange thing was that nobody thought it was strange.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Six months after we launched our AI interview system, everyone was happy.&lt;/p&gt;

&lt;p&gt;Recruiters were happy.&lt;/p&gt;

&lt;p&gt;Hiring managers were happy.&lt;/p&gt;

&lt;p&gt;Candidates were happy.&lt;/p&gt;

&lt;p&gt;Even the CTO was happy.&lt;/p&gt;

&lt;p&gt;The numbers looked fantastic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Candidate pass rate: up 23%&lt;/li&gt;
&lt;li&gt;Interview completion rate: up 31%&lt;/li&gt;
&lt;li&gt;Candidate satisfaction: up 18%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every dashboard was green.&lt;/p&gt;

&lt;p&gt;Every weekly report looked better than the week before.&lt;/p&gt;

&lt;p&gt;The AI interviewer seemed to be working exactly as intended.&lt;/p&gt;

&lt;p&gt;Then someone asked an uncomfortable question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If we're hiring better people, why aren't our teams getting stronger?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody had a good answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;The question came from a senior engineering manager.&lt;/p&gt;

&lt;p&gt;Not from HR.&lt;/p&gt;

&lt;p&gt;Not from leadership.&lt;/p&gt;

&lt;p&gt;Not from the AI team.&lt;/p&gt;

&lt;p&gt;He had reviewed the performance evaluations of engineers hired during the previous two quarters.&lt;/p&gt;

&lt;p&gt;The data wasn't catastrophic.&lt;/p&gt;

&lt;p&gt;But it wasn't improving either.&lt;/p&gt;

&lt;p&gt;New hires were passing interviews more often.&lt;/p&gt;

&lt;p&gt;Yet their first six months looked almost identical to previous cohorts.&lt;/p&gt;

&lt;p&gt;The hiring funnel was getting easier.&lt;/p&gt;

&lt;p&gt;The outcome wasn't getting better.&lt;/p&gt;

&lt;p&gt;At first glance, it looked like normal variation.&lt;/p&gt;

&lt;p&gt;Then we graphed the numbers.&lt;/p&gt;

&lt;p&gt;The pass rate wasn't just increasing.&lt;/p&gt;

&lt;p&gt;It was increasing steadily.&lt;/p&gt;

&lt;p&gt;Month after month.&lt;/p&gt;

&lt;p&gt;Almost like someone was turning a dial.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Obvious Suspects
&lt;/h2&gt;

&lt;p&gt;The first explanation was ChatGPT.&lt;/p&gt;

&lt;p&gt;Maybe candidates had simply become better at using AI tools.&lt;/p&gt;

&lt;p&gt;We checked.&lt;/p&gt;

&lt;p&gt;No correlation.&lt;/p&gt;

&lt;p&gt;The increase affected coding questions, system design questions, and behavioral questions equally.&lt;/p&gt;

&lt;p&gt;That was odd.&lt;/p&gt;

&lt;p&gt;Generative AI usually improves some categories more than others.&lt;/p&gt;

&lt;p&gt;Not everything at once.&lt;/p&gt;




&lt;p&gt;The second explanation was question leakage.&lt;/p&gt;

&lt;p&gt;Maybe interview questions had spread online.&lt;/p&gt;

&lt;p&gt;We rotated the question bank.&lt;/p&gt;

&lt;p&gt;Nothing changed.&lt;/p&gt;

&lt;p&gt;Pass rates kept rising.&lt;/p&gt;




&lt;p&gt;The third explanation was model drift.&lt;/p&gt;

&lt;p&gt;Perhaps the scoring model had gradually become more lenient.&lt;/p&gt;

&lt;p&gt;The model version hadn't changed in months.&lt;/p&gt;

&lt;p&gt;No retraining.&lt;/p&gt;

&lt;p&gt;No parameter updates.&lt;/p&gt;

&lt;p&gt;Nothing.&lt;/p&gt;




&lt;p&gt;The system wasn't becoming easier because of the model.&lt;/p&gt;

&lt;p&gt;Something else was moving.&lt;/p&gt;




&lt;h2&gt;
  
  
  Following the Scores
&lt;/h2&gt;

&lt;p&gt;We stopped looking at candidates.&lt;/p&gt;

&lt;p&gt;We started looking at interviewers.&lt;/p&gt;

&lt;p&gt;Not human interviewers.&lt;/p&gt;

&lt;p&gt;Human reviewers.&lt;/p&gt;

&lt;p&gt;Our AI system generated recommendations.&lt;/p&gt;

&lt;p&gt;Humans provided feedback.&lt;/p&gt;

&lt;p&gt;Those feedback signals were later used to calibrate future scoring.&lt;/p&gt;

&lt;p&gt;The design seemed reasonable.&lt;/p&gt;

&lt;p&gt;The AI wasn't making final decisions.&lt;/p&gt;

&lt;p&gt;Humans still approved or rejected candidates.&lt;/p&gt;

&lt;p&gt;The system simply learned from those outcomes.&lt;/p&gt;

&lt;p&gt;At least that was the theory.&lt;/p&gt;




&lt;p&gt;One recruiter stood out.&lt;/p&gt;

&lt;p&gt;Not because she reviewed more candidates.&lt;/p&gt;

&lt;p&gt;Not because she hired more candidates.&lt;/p&gt;

&lt;p&gt;Because her feedback disagreed with everyone else.&lt;/p&gt;

&lt;p&gt;Consistently.&lt;/p&gt;




&lt;p&gt;Most recruiters approved around 55–65% of AI recommendations.&lt;/p&gt;

&lt;p&gt;She approved nearly 90%.&lt;/p&gt;

&lt;p&gt;Every month.&lt;/p&gt;

&lt;p&gt;Every quarter.&lt;/p&gt;

&lt;p&gt;Every role.&lt;/p&gt;

&lt;p&gt;Engineering.&lt;/p&gt;

&lt;p&gt;Product.&lt;/p&gt;

&lt;p&gt;Data.&lt;/p&gt;

&lt;p&gt;Didn't matter.&lt;/p&gt;

&lt;p&gt;Her approval rate barely moved.&lt;/p&gt;




&lt;p&gt;At first we assumed she was simply optimistic.&lt;/p&gt;

&lt;p&gt;Then we discovered something else.&lt;/p&gt;

&lt;p&gt;The AI loved candidates she loved.&lt;/p&gt;

&lt;p&gt;Far more than statistics would predict.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Loop
&lt;/h2&gt;

&lt;p&gt;The scoring model wasn't retraining itself directly.&lt;/p&gt;

&lt;p&gt;That would have been easy to find.&lt;/p&gt;

&lt;p&gt;Instead, every month we recalibrated scoring thresholds using historical hiring outcomes.&lt;/p&gt;

&lt;p&gt;The logic seemed harmless.&lt;/p&gt;

&lt;p&gt;If recruiters consistently approved certain profiles, the system adjusted future recommendations accordingly.&lt;/p&gt;

&lt;p&gt;A feedback mechanism.&lt;/p&gt;

&lt;p&gt;Designed to align AI behavior with human decisions.&lt;/p&gt;




&lt;p&gt;The problem was scale.&lt;/p&gt;

&lt;p&gt;One recruiter reviewed nearly three times as many candidates as everyone else.&lt;/p&gt;

&lt;p&gt;Not because she was more senior.&lt;/p&gt;

&lt;p&gt;Because she worked across multiple departments.&lt;/p&gt;

&lt;p&gt;Over time her decisions became disproportionately represented in the calibration data.&lt;/p&gt;




&lt;p&gt;Nobody noticed.&lt;/p&gt;

&lt;p&gt;The dashboards tracked model accuracy.&lt;/p&gt;

&lt;p&gt;They tracked candidate satisfaction.&lt;/p&gt;

&lt;p&gt;They tracked hiring speed.&lt;/p&gt;

&lt;p&gt;Nobody tracked influence concentration.&lt;/p&gt;




&lt;p&gt;The AI wasn't learning from the company.&lt;/p&gt;

&lt;p&gt;The AI was slowly learning from one person.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Experiment
&lt;/h2&gt;

&lt;p&gt;We replayed six months of interview data.&lt;/p&gt;

&lt;p&gt;Then removed her feedback entirely.&lt;/p&gt;

&lt;p&gt;The results surprised everyone.&lt;/p&gt;

&lt;p&gt;The pass rate curve flattened almost immediately.&lt;/p&gt;

&lt;p&gt;Several recommendation patterns disappeared.&lt;/p&gt;

&lt;p&gt;The model's definition of a "strong candidate" shifted.&lt;/p&gt;

&lt;p&gt;Not dramatically.&lt;/p&gt;

&lt;p&gt;Just enough.&lt;/p&gt;

&lt;p&gt;Enough to explain nearly all of the growth we had observed.&lt;/p&gt;




&lt;p&gt;The system hadn't become smarter.&lt;/p&gt;

&lt;p&gt;It had become more aligned with one recruiter's preferences.&lt;/p&gt;




&lt;p&gt;And here's the uncomfortable part.&lt;/p&gt;

&lt;p&gt;She wasn't wrong.&lt;/p&gt;




&lt;p&gt;Many of her hires performed perfectly well.&lt;/p&gt;

&lt;p&gt;Some became top performers.&lt;/p&gt;

&lt;p&gt;The issue wasn't quality.&lt;/p&gt;

&lt;p&gt;The issue was representation.&lt;/p&gt;




&lt;p&gt;One person's judgment had become company policy.&lt;/p&gt;

&lt;p&gt;Nobody voted on it.&lt;/p&gt;

&lt;p&gt;Nobody approved it.&lt;/p&gt;

&lt;p&gt;Nobody even knew it was happening.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hardest Bug to Explain
&lt;/h2&gt;

&lt;p&gt;When we presented the findings, nobody argued with the data.&lt;/p&gt;

&lt;p&gt;The graphs were clear.&lt;/p&gt;

&lt;p&gt;The mechanism was clear.&lt;/p&gt;

&lt;p&gt;The feedback loop was clear.&lt;/p&gt;




&lt;p&gt;But one executive asked a question that stayed with me.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If her judgment was good, why is this a problem?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The room went quiet.&lt;/p&gt;

&lt;p&gt;Because technically, it wasn't a bug.&lt;/p&gt;

&lt;p&gt;The system worked exactly as designed.&lt;/p&gt;

&lt;p&gt;Humans provided feedback.&lt;/p&gt;

&lt;p&gt;The AI learned from feedback.&lt;/p&gt;

&lt;p&gt;The AI became better at predicting future feedback.&lt;/p&gt;

&lt;p&gt;Mission accomplished.&lt;/p&gt;




&lt;p&gt;The problem was that we had confused consistency with objectivity.&lt;/p&gt;

&lt;p&gt;The AI wasn't discovering what made a great engineer.&lt;/p&gt;

&lt;p&gt;It was discovering what made one recruiter say yes.&lt;/p&gt;

&lt;p&gt;Those are not the same thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Changed
&lt;/h2&gt;

&lt;p&gt;We didn't remove human feedback.&lt;/p&gt;

&lt;p&gt;That would have been the wrong lesson.&lt;/p&gt;

&lt;p&gt;Instead we started measuring something we had never measured before.&lt;/p&gt;

&lt;p&gt;Influence.&lt;/p&gt;

&lt;p&gt;Not accuracy.&lt;/p&gt;

&lt;p&gt;Not acceptance rate.&lt;/p&gt;

&lt;p&gt;Influence.&lt;/p&gt;




&lt;p&gt;Who shapes the training signal?&lt;/p&gt;

&lt;p&gt;How concentrated is that influence?&lt;/p&gt;

&lt;p&gt;How much of the system's future behavior can be traced back to a single source?&lt;/p&gt;




&lt;p&gt;Those metrics never appeared on executive dashboards before.&lt;/p&gt;

&lt;p&gt;Now they do.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;The most dangerous AI failures rarely look like failures.&lt;/p&gt;

&lt;p&gt;No outage.&lt;/p&gt;

&lt;p&gt;No incident.&lt;/p&gt;

&lt;p&gt;No security breach.&lt;/p&gt;

&lt;p&gt;No alarming stack trace.&lt;/p&gt;




&lt;p&gt;Everything was green.&lt;/p&gt;

&lt;p&gt;Every KPI was improving.&lt;/p&gt;

&lt;p&gt;Every report suggested success.&lt;/p&gt;




&lt;p&gt;That's what made this one hard to see.&lt;/p&gt;

&lt;p&gt;The system wasn't broken.&lt;/p&gt;

&lt;p&gt;The system was becoming more confident in a perspective that nobody realized it had inherited.&lt;/p&gt;




&lt;p&gt;The interviews weren't getting easier because candidates were improving.&lt;/p&gt;

&lt;p&gt;They weren't getting easier because the model was drifting.&lt;/p&gt;

&lt;p&gt;They weren't getting easier because somebody manipulated the system.&lt;/p&gt;




&lt;p&gt;They were getting easier because one person's idea of talent had quietly become the AI's idea of talent.&lt;/p&gt;

&lt;p&gt;And nobody noticed until the numbers looked too good to question.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>SOLID and OOP: Designing Software That Survives Change</title>
      <dc:creator>Kent Phung</dc:creator>
      <pubDate>Sun, 19 Jul 2026 17:13:27 +0000</pubDate>
      <link>https://dev.to/khapu2906/solid-and-oop-designing-software-that-survives-change-16ko</link>
      <guid>https://dev.to/khapu2906/solid-and-oop-designing-software-that-survives-change-16ko</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;A Quick Recap of OOP&lt;/li&gt;
&lt;li&gt;Why OOP Alone Is Not Enough&lt;/li&gt;
&lt;li&gt;What is SOLID?&lt;/li&gt;
&lt;li&gt;1. Single Responsibility Principle (SRP)&lt;/li&gt;
&lt;li&gt;2. OpenClosed Principle (OCP)&lt;/li&gt;
&lt;li&gt;3. Liskov Substitution Principle (LSP)&lt;/li&gt;
&lt;li&gt;4. Interface Segregation Principle (ISP)&lt;/li&gt;
&lt;li&gt;5. Dependency Inversion Principle (DIP)&lt;/li&gt;
&lt;li&gt;Composition Over Inheritance&lt;/li&gt;
&lt;li&gt;Common Misconceptions About SOLID&lt;/li&gt;
&lt;li&gt;When Not to Apply SOLID&lt;/li&gt;
&lt;li&gt;SOLID in a Real E-Commerce System&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Imagine you're building an application using Object-Oriented Programming (OOP).&lt;/p&gt;

&lt;p&gt;At first, everything seems great:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code is clean.&lt;/li&gt;
&lt;li&gt;Features work correctly.&lt;/li&gt;
&lt;li&gt;Development moves quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then new requirements arrive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Suddenly&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixing one bug breaks another feature.&lt;/li&gt;
&lt;li&gt;A single class handles business logic, database access, and email notifications.&lt;/li&gt;
&lt;li&gt;Adding a new feature requires modifying multiple existing classes.&lt;/li&gt;
&lt;li&gt;Testing becomes increasingly difficult.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this sounds familiar, you've encountered one of the biggest challenges in software development:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Managing change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is exactly the problem SOLID was designed to address.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quick Recap of OOP
&lt;/h2&gt;

&lt;p&gt;Object-Oriented Programming is built on four fundamental concepts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encapsulation&lt;/strong&gt;: Hide internal state and expose behavior through controlled interfaces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abstraction&lt;/strong&gt;: Expose only what is necessary while hiding implementation details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;: Reuse behavior through parent-child relationships.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Polymorphism&lt;/strong&gt;: Allow different objects to respond to the same message in different ways.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why OOP Alone Is Not Enough
&lt;/h2&gt;

&lt;p&gt;OOP provides powerful tools.&lt;/p&gt;

&lt;p&gt;However, tools alone do not guarantee good design.&lt;/p&gt;

&lt;p&gt;Poorly designed OOP systems often suffer from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;God Classes&lt;/li&gt;
&lt;li&gt;Tight Coupling&lt;/li&gt;
&lt;li&gt;Fragile Inheritance Hierarchies&lt;/li&gt;
&lt;li&gt;Difficult Testing&lt;/li&gt;
&lt;li&gt;Low Maintainability&lt;/li&gt;
&lt;li&gt;Poor Extensibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SOLID provides guidelines for using OOP effectively.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is SOLID?
&lt;/h2&gt;

&lt;p&gt;SOLID is a collection of five design principles popularized by Robert C. Martin (Uncle Bob).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S — Single Responsibility Principle&lt;/li&gt;
&lt;li&gt;O — Open/Closed Principle&lt;/li&gt;
&lt;li&gt;L — Liskov Substitution Principle&lt;/li&gt;
&lt;li&gt;I — Interface Segregation Principle&lt;/li&gt;
&lt;li&gt;D — Dependency Inversion Principle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not perfect design.&lt;/p&gt;

&lt;p&gt;The goal is software that remains easy to evolve over time.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Single Responsibility Principle (SRP)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A class should have one and only one reason to change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Relationship to OOP
&lt;/h3&gt;

&lt;p&gt;SRP complements Encapsulation by encouraging related behaviors to stay together while separating unrelated concerns.&lt;/p&gt;

&lt;p&gt;It is also closely related to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cohesion&lt;/li&gt;
&lt;li&gt;Separation of Concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A highly cohesive class typically has a single responsibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Misconception
&lt;/h3&gt;

&lt;p&gt;A responsibility is not a method.&lt;/p&gt;

&lt;p&gt;This is perfectly acceptable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserValidator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;validateEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;validatePhone&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;validateName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All methods belong to the same responsibility:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Validation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  SRP Violation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveToDatabase&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class has multiple reasons to change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Higher cohesion&lt;/li&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;li&gt;Better testing&lt;/li&gt;
&lt;li&gt;Reduced coupling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Open/Closed Principle (OCP)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Software entities should be open for extension but closed for modification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Relationship to OOP
&lt;/h3&gt;

&lt;p&gt;OCP relies heavily on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstraction&lt;/li&gt;
&lt;li&gt;Polymorphism&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  OCP Violation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"credit"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"paypal"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every new payment method requires modifying existing code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreditCardPayment&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PayPalPayment&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  OCP Is Not About Interfaces
&lt;/h3&gt;

&lt;p&gt;Many developers think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OCP = Create an Interface&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Interfaces are only one implementation technique.&lt;/p&gt;

&lt;p&gt;Other approaches include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strategy Pattern&lt;/li&gt;
&lt;li&gt;Plugin Architecture&lt;/li&gt;
&lt;li&gt;Event-Driven Systems&lt;/li&gt;
&lt;li&gt;Dependency Injection&lt;/li&gt;
&lt;li&gt;Configuration-Based Extensions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Extend behavior without modifying stable code.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Liskov Substitution Principle (LSP)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Subtypes must be substitutable for their base types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Relationship to OOP
&lt;/h3&gt;

&lt;p&gt;LSP protects the correct use of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inheritance&lt;/li&gt;
&lt;li&gt;Polymorphism&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fly&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sparrow&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fly&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ostrich&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fly&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The abstraction promises that all birds can fly.&lt;/p&gt;

&lt;p&gt;Ostrich breaks that promise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FlyingBird&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Bird&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fly&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ISP vs LSP
&lt;/h3&gt;

&lt;p&gt;Although often discussed together, they solve different problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ISP&lt;/td&gt;
&lt;td&gt;Interface Design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LSP&lt;/td&gt;
&lt;td&gt;Substitutability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;LSP focuses on behavioral compatibility between abstractions and implementations.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Interface Segregation Principle (ISP)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Clients should not be forced to depend on interfaces they do not use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ISP Violation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Robot&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interface is too broad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Workable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Eatable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Smaller contracts&lt;/li&gt;
&lt;li&gt;Lower coupling&lt;/li&gt;
&lt;li&gt;Easier maintenance&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Dependency Inversion Principle (DIP)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;High-level modules should not depend on low-level modules. Both should depend on abstractions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DIP Violation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Business logic depends directly on implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;NotificationService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DIP vs Dependency Injection
&lt;/h3&gt;

&lt;p&gt;A common misconception is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DIP and DI are the same thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DIP is a design principle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DI is a technique used to implement that principle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DIP answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What should depend on what?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;DI answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How are dependencies provided?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The true goal of DIP is to ensure that business policies do not depend on implementation details.&lt;/p&gt;




&lt;h2&gt;
  
  
  Composition Over Inheritance
&lt;/h2&gt;

&lt;p&gt;A principle commonly associated with SOLID is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Favor Composition Over Inheritance&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;NotificationSender&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;NotificationSender&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SmsSender&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;NotificationSender&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;NotificationSender&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;NotificationService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NotificationSender&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that NotificationService does not inherit from EmailSender or SmsSender.&lt;/p&gt;

&lt;p&gt;Instead, it composes behavior through abstraction.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More flexibility&lt;/li&gt;
&lt;li&gt;Better testability&lt;/li&gt;
&lt;li&gt;Lower coupling&lt;/li&gt;
&lt;li&gt;Stronger support for OCP and DIP&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Misconceptions About SOLID
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Misconception #1
&lt;/h3&gt;

&lt;p&gt;"Every class must have one method."&lt;/p&gt;

&lt;p&gt;False.&lt;/p&gt;

&lt;p&gt;SRP is about responsibilities, not method count.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception #2
&lt;/h3&gt;

&lt;p&gt;"OCP means creating interfaces."&lt;/p&gt;

&lt;p&gt;False.&lt;/p&gt;

&lt;p&gt;Interfaces are only one possible implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception #3
&lt;/h3&gt;

&lt;p&gt;"DIP equals Dependency Injection."&lt;/p&gt;

&lt;p&gt;False.&lt;/p&gt;

&lt;p&gt;DI is a technique.&lt;/p&gt;

&lt;p&gt;DIP is the principle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception #4
&lt;/h3&gt;

&lt;p&gt;"SOLID should always be applied everywhere."&lt;/p&gt;

&lt;p&gt;False.&lt;/p&gt;

&lt;p&gt;Over-engineering is a real problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Not to Apply SOLID
&lt;/h2&gt;

&lt;p&gt;Not every project needs enterprise-level architecture.&lt;/p&gt;

&lt;p&gt;For small applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserValidator&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserValidatorImpl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;may add unnecessary complexity.&lt;/p&gt;

&lt;p&gt;Apply SOLID when it solves a real problem.&lt;/p&gt;

&lt;p&gt;Avoid applying it purely for theoretical purity.&lt;/p&gt;




&lt;h2&gt;
  
  
  SOLID in a Real E-Commerce System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SRP
&lt;/h3&gt;

&lt;p&gt;Separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order Processing&lt;/li&gt;
&lt;li&gt;Persistence&lt;/li&gt;
&lt;li&gt;Notification&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  OCP
&lt;/h3&gt;

&lt;p&gt;Add new payment methods without modifying existing services.&lt;/p&gt;

&lt;h3&gt;
  
  
  LSP
&lt;/h3&gt;

&lt;p&gt;Allow specialized order types to safely replace base order types.&lt;/p&gt;

&lt;h3&gt;
  
  
  ISP
&lt;/h3&gt;

&lt;p&gt;Create focused contracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payable&lt;/li&gt;
&lt;li&gt;Refundable&lt;/li&gt;
&lt;li&gt;Shippable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DIP
&lt;/h3&gt;

&lt;p&gt;Depend on abstractions rather than specific database implementations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;At its core, SOLID is about managing change.&lt;/p&gt;

&lt;p&gt;As software evolves, requirements change, business rules shift, and new features emerge.&lt;/p&gt;

&lt;p&gt;Poor design makes these changes expensive and risky.&lt;/p&gt;

&lt;p&gt;Each SOLID principle addresses a different source of rigidity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SRP reduces unrelated changes.&lt;/li&gt;
&lt;li&gt;OCP minimizes modifications to stable code.&lt;/li&gt;
&lt;li&gt;LSP protects substitutability.&lt;/li&gt;
&lt;li&gt;ISP avoids unnecessary dependencies.&lt;/li&gt;
&lt;li&gt;DIP separates business rules from implementation details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these principles help developers build systems that can evolve without becoming increasingly difficult to maintain.&lt;/p&gt;

&lt;p&gt;The goal is not to eliminate change.&lt;/p&gt;

&lt;p&gt;The goal is to make change less expensive.&lt;/p&gt;

</description>
      <category>oop</category>
      <category>webdev</category>
      <category>cleancode</category>
      <category>programming</category>
    </item>
    <item>
      <title>OOP Beyond the Four Pillars: State, Behavior, and Invariants</title>
      <dc:creator>Kent Phung</dc:creator>
      <pubDate>Thu, 16 Jul 2026 11:04:06 +0000</pubDate>
      <link>https://dev.to/khapu2906/the-real-essence-of-oop-state-behavior-and-invariants-2k1d</link>
      <guid>https://dev.to/khapu2906/the-real-essence-of-oop-state-behavior-and-invariants-2k1d</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;1. From Procedural to Object-Oriented&lt;/li&gt;
&lt;li&gt;2. What Problem Does OOP Actually Solve?&lt;/li&gt;
&lt;li&gt;3. Encapsulation — Access Control, Not Lifecycle Management&lt;/li&gt;
&lt;li&gt;4. Inheritance — A Tool for Substitutability, Not a Default Fix for Duplication&lt;/li&gt;
&lt;li&gt;5. Polymorphism — The Core Is Subtype Polymorphism, Not Overloading&lt;/li&gt;
&lt;li&gt;6. Abstraction — Much Broader Than an Interface&lt;/li&gt;
&lt;li&gt;7. Behavior-State Binding and Invariants&lt;/li&gt;
&lt;li&gt;8. The Cost of OOP&lt;/li&gt;
&lt;li&gt;OOP Is About Responsibility, Not Classes&lt;/li&gt;
&lt;li&gt;A Note on Rich vs. Anemic Models&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When object-oriented programming (OOP) comes up, most people immediately list: Encapsulation, Inheritance, Polymorphism, Abstraction. But reciting four names doesn't mean understanding the substance — and worse, a lot of popular material explains these four properties in ways that are conceptually misleading.&lt;/p&gt;

&lt;p&gt;Code examples below are written in Java, purely as notation — the ideas are the point, not the language.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. From Procedural to Object-Oriented
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Procedural: data and behavior live apart
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bank&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Global/static state&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;balance&lt;/code&gt; is a static variable — any part of the program can read or write it directly, with no guarantee it's ever checked, so the data can end up in an invalid state at any time.&lt;/p&gt;

&lt;h3&gt;
  
  
  OOP: data bound to the behavior that protects it
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;(examples below use &lt;code&gt;java.math.BigDecimal&lt;/code&gt; — the standard choice for money in Java, since &lt;code&gt;double&lt;/code&gt; accumulates rounding error that a real invariant check can't tolerate)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BankAccount&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BankAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;initial&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signum&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Initial balance cannot be negative"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initial&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signum&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The point is not "hiding &lt;code&gt;balance&lt;/code&gt;."&lt;/strong&gt; The point is that &lt;code&gt;BankAccount&lt;/code&gt; exists to guarantee one rule always holds — &lt;code&gt;balance &amp;gt;= 0&lt;/code&gt; — no matter who calls what, in what order. An object isn't a box that stores data. &lt;strong&gt;One of the most important roles of an object is protecting invariants.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the starting point the rest of the article builds on.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. What Problem Does OOP Actually Solve?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem in Procedural Code&lt;/th&gt;
&lt;th&gt;OOP Mechanism&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State can be mutated arbitrarily, with no guardrails&lt;/td&gt;
&lt;td&gt;Encapsulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logic duplicated across variants of the same concept&lt;/td&gt;
&lt;td&gt;Composition / Inheritance (conditionally)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calling code has to know the concrete type it's handling&lt;/td&gt;
&lt;td&gt;Polymorphism&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System complexity makes it hard to separate levels of detail&lt;/td&gt;
&lt;td&gt;Abstraction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Inheritance is no longer the default answer to "code duplication"&lt;/strong&gt; — the reason follows in section 4.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Encapsulation — Access Control, Not Lifecycle Management
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The correct definition
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Encapsulation means controlling access to state and guaranteeing an invariant holds&lt;/strong&gt;, by only allowing state changes through a controlled set of behaviors (methods).&lt;/p&gt;

&lt;h3&gt;
  
  
  Encapsulation is not the same thing as lifecycle management
&lt;/h3&gt;

&lt;p&gt;A common conflation in OOP teaching is treating Encapsulation as if it also covers managing an object's memory or resource lifetime. It doesn't — they're different responsibilities that some languages happen to bind to the same syntax. Encapsulation is about &lt;strong&gt;who can touch state and under what conditions&lt;/strong&gt;; lifecycle management is about &lt;strong&gt;how long a resource is held and when it gets released&lt;/strong&gt;. An object can have one without the other: most objects, like &lt;code&gt;BankAccount&lt;/code&gt; above, never own an external resource at all — &lt;code&gt;private&lt;/code&gt; fields and validated methods are the whole story, no lifecycle concern in sight.&lt;/p&gt;

&lt;p&gt;Lifecycle management only becomes relevant for the minority of objects holding something outside the object itself — a file handle, a socket, a database connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileLogger&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;AutoCloseable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;BufferedWriter&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FileLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BufferedWriter&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// resource cleanup — nothing to do with access control&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;AutoCloseable&lt;/code&gt;/&lt;code&gt;close()&lt;/code&gt; exist purely to release the resource; they say nothing about who can read or write the object's state. Notice this is a separate mechanism from &lt;code&gt;private&lt;/code&gt;/getters/setters entirely — a good illustration that Encapsulation and lifecycle management are independent concerns, not two faces of the same thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; Encapsulation is a universal OOP concept that applies to every object. Lifecycle/resource management is a narrower, separate concern that only shows up when an object actually owns an external resource.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Inheritance — A Tool for Substitutability, Not a Default Fix for Duplication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overriding relies on dynamic dispatch
&lt;/h3&gt;

&lt;p&gt;Overriding only means something if the call is resolved by the object's actual type at runtime, not by the variable's declared type at compile time. That's what makes this work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Animal sound"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Woof!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;speak&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Prints "Woof!" — resolved by the actual object, not the declared type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@Override&lt;/code&gt; here isn't what makes overriding happen — it's just an annotation that lets the compiler &lt;strong&gt;flag an error if you think you're overriding but actually got the signature wrong&lt;/strong&gt; (e.g., a typo'd method name). It's a safety net for catching mistakes, not the mechanism itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritance is not the default tool for "reusing logic"
&lt;/h3&gt;

&lt;p&gt;The common guideline in modern design:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Favor Composition over Inheritance&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The classic headache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AdminUser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuperAdminUser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AdminUser&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Say &lt;code&gt;AdminUser&lt;/code&gt; can do everything a regular user can, plus manage other users. &lt;code&gt;SuperAdminUser&lt;/code&gt; adds billing access on top. That much fits a linear hierarchy fine. The trouble starts the moment &lt;code&gt;AdminUser&lt;/code&gt; also needs a capability that lives on a completely different, unrelated branch — say, the same &lt;em&gt;view-only, read-restricted&lt;/em&gt; mode that a hypothetical &lt;code&gt;ReadOnlyUser&lt;/code&gt; has. There's no clean way to "borrow" that behavior sideways: &lt;code&gt;AdminUser&lt;/code&gt; can't extend two classes, and forcing &lt;code&gt;ReadOnlyUser&lt;/code&gt; into the same chain just to share one capability distorts the whole hierarchy for everyone else using it.&lt;/p&gt;

&lt;p&gt;Composition sidesteps this entirely, because capabilities become objects you attach rather than branches you inherit from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Permissions&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// just a set of granted actions&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Permissions&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Any combination of capabilities can be composed freely — no hierarchy to fight:&lt;/span&gt;
&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Permissions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MANAGE_USERS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIEW_ONLY&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;superAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Permissions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MANAGE_USERS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BILLING&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VIEW_ONLY&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;admin&lt;/code&gt; and &lt;code&gt;superAdmin&lt;/code&gt; aren't different &lt;em&gt;classes&lt;/em&gt; anymore — they're the same &lt;code&gt;User&lt;/code&gt; class configured with a different &lt;code&gt;Permissions&lt;/code&gt; object. Adding "view-only" to &lt;code&gt;AdminUser&lt;/code&gt; is no longer a hierarchy problem; it's just handing it a different set of permissions at construction time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritance is only safe when the Liskov Substitution Principle holds
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;"is-a" relationship&lt;/strong&gt; by itself isn't the real test — plenty of things sound like "is-a" in English but break down in code. The actual condition is the &lt;strong&gt;Liskov Substitution Principle (LSP)&lt;/strong&gt;: anywhere the base class is used, substituting the subclass must work correctly without the caller needing to know it's a subclass. LSP is the reason Inheritance is trustworthy at all when it is; without it, "is-a" is just a feeling, not a guarantee.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Dog extends Animal&lt;/code&gt; holds up under this test — a &lt;code&gt;Dog&lt;/code&gt; behaves as an &lt;code&gt;Animal&lt;/code&gt; everywhere an &lt;code&gt;Animal&lt;/code&gt; is expected. Inheriting just to "borrow a few existing methods," without that substitutability guarantee, is a signal to switch to composition instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Polymorphism — The Core Is Subtype Polymorphism, Not Overloading
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overloading is ad-hoc polymorphism — useful, but not the core
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MathUtil&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is resolved at compile time and has nothing to do with dynamic dispatch — it's just syntactic convenience.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real power: subtype polymorphism
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Car moves"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bike&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bike moves"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Fleet&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;moveAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Vehicle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vehicles&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;move&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// No need to know whether it's a Car or a Bike&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the essence: &lt;strong&gt;the same call site (&lt;code&gt;v.move()&lt;/code&gt;) dispatches to different behavior at runtime, based on the object's concrete type&lt;/strong&gt; — &lt;code&gt;Fleet&lt;/code&gt; needs no changes when a &lt;code&gt;Truck&lt;/code&gt; or &lt;code&gt;Boat&lt;/code&gt; is added.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Polymorphism lets code handle a set of different types &lt;strong&gt;through the same abstraction&lt;/strong&gt;, without needing to know — or care — what the concrete type behind it is.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Abstraction — Much Broader Than an Interface
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Interfaces and abstract classes are tools, not Abstraction itself
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;area&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example is &lt;strong&gt;correct but incomplete&lt;/strong&gt; — it only illustrates one specific form called &lt;strong&gt;interface abstraction&lt;/strong&gt;. A pure contract with no state (&lt;code&gt;interface&lt;/code&gt;) and a partial implementation that can hold state (&lt;code&gt;abstract class&lt;/code&gt;) are two different tools for achieving Abstraction — but neither one &lt;em&gt;is&lt;/em&gt; Abstraction itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Abstraction actually is
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The caller doesn't need to know:&lt;/span&gt;
        &lt;span class="c1"&gt;// - SQL or NoSQL&lt;/span&gt;
        &lt;span class="c1"&gt;// - how transactions are opened/closed&lt;/span&gt;
        &lt;span class="c1"&gt;// - how the connection pool is configured&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;repository.save(user)&lt;/code&gt; is a complete abstraction even without any &lt;code&gt;interface&lt;/code&gt; — as long as the caller doesn't need the internal details. Abstraction lives in &lt;strong&gt;the level of detail exposed through a function's name and parameters&lt;/strong&gt;, not in whether &lt;code&gt;interface&lt;/code&gt;/&lt;code&gt;abstract&lt;/code&gt; is used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; &lt;code&gt;interface&lt;/code&gt;/&lt;code&gt;abstract class&lt;/code&gt; are &lt;em&gt;tools&lt;/em&gt; for achieving Abstraction, especially useful when multiple interchangeable implementations are needed. But Abstraction, as a design principle, exists at every layer of code — including a plain &lt;code&gt;private&lt;/code&gt; method.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Behavior-State Binding and Invariants
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BankAccount&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BankAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;initialBalance&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialBalance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signum&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Initial balance cannot be negative"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialBalance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signum&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important question isn't "what does this class store?" It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What rule does this class protect, that must always hold no matter the sequence of operations?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For &lt;code&gt;BankAccount&lt;/code&gt;, that rule is &lt;code&gt;balance &amp;gt;= 0&lt;/code&gt; — enforced not just in &lt;code&gt;withdraw&lt;/code&gt;, but in the constructor too, since an invariant that only holds &lt;em&gt;after&lt;/em&gt; the first call isn't really an invariant. The entire design — &lt;code&gt;private&lt;/code&gt;, the condition checks — exists solely to serve that one rule.&lt;/p&gt;

&lt;p&gt;A natural follow-up question: does &lt;code&gt;getBalance()&lt;/code&gt; returning the raw value undercut any of this? Not inherently — exposing read-only state isn't a violation by itself. What matters is &lt;em&gt;where decisions based on that state get made&lt;/em&gt;. &lt;code&gt;getBalance()&lt;/code&gt; lets a caller look; &lt;code&gt;withdraw()&lt;/code&gt; is still the only way to change anything, and it's still the one place enforcing the rule. Exposing a value for reading and protecting the rules that govern changing it are two separate questions.&lt;/p&gt;

&lt;p&gt;Protecting invariants is one of the most important responsibilities many domain objects have. In practice, this is why OOP often emphasizes keeping behavior close to the state it governs.&lt;/p&gt;

&lt;p&gt;A related concept is identity.&lt;/p&gt;

&lt;p&gt;Two objects may contain identical state and behavior while still represent different entities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;alice1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;alice2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For that reason, many classic OOP definitions describe an object as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Identity + State + Behavior&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article focuses primarily on responsibility and invariant protection, but identity remains an important part of object-oriented thinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not All Invariants Belong to a Single Object
&lt;/h3&gt;

&lt;p&gt;The examples in this article focus on invariants protected by a single object.&lt;/p&gt;

&lt;p&gt;Real systems often contain rules that span multiple objects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An order cannot be shipped unless it has been paid.&lt;/li&gt;
&lt;li&gt;Inventory cannot become negative.&lt;/li&gt;
&lt;li&gt;A bank transfer must debit one account and credit another.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protecting such rules often requires coordination beyond a single object and is one of the motivations behind concepts such as Aggregates in Domain-Driven Design. An Aggregate defines a consistency boundary within which invariants are guaranteed to hold.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. The Cost of OOP
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deep inheritance hierarchies&lt;/strong&gt;: the more &lt;code&gt;extends&lt;/code&gt; layers, the harder to test and refactor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anemic Domain Model&lt;/strong&gt;: extremely common in Spring-style Java codebases. A class ends up as nothing but fields and getters/setters:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// no validation, no rule&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anywhere that needs to change an email now has to duplicate the validation logic itself (&lt;code&gt;UserService&lt;/code&gt;, a controller, a batch job — whoever gets there first), because &lt;code&gt;User&lt;/code&gt; enforces nothing. Compare that to keeping the rule where the state lives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
          &lt;span class="o"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;setEmail&lt;/code&gt; just stores whatever it's given — the object protects no invariant, so it isn't really acting as an object in the OOP sense, just a data bag with a class-shaped label. &lt;code&gt;changeEmail&lt;/code&gt; puts the rule back where it belongs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overusing Inheritance&lt;/strong&gt; for code reuse instead of modeling a genuine "is-a" relationship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface explosion&lt;/strong&gt; — creating an &lt;code&gt;interface&lt;/code&gt; for everything "just in case" before there's an actual need (a violation of YAGNI) — a fairly common habit in the Java/Spring ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A counterbalancing principle worth knowing: &lt;strong&gt;Tell, Don't Ask&lt;/strong&gt; — instead of &lt;code&gt;if (account.getBalance().compareTo(amount) &amp;gt;= 0) { ... }&lt;/code&gt; followed by external handling, call &lt;code&gt;account.withdraw(amount)&lt;/code&gt; so the decision logic stays close to the data it governs.&lt;/p&gt;




&lt;h2&gt;
  
  
  OOP Is About Responsibility, Not Classes
&lt;/h2&gt;

&lt;p&gt;A useful test for whether a codebase is actually object-oriented, or just uses &lt;code&gt;class&lt;/code&gt; as a file-organization convention: pick a business rule and ask &lt;strong&gt;which object owns it&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt;
&lt;span class="nc"&gt;UserService&lt;/span&gt;
&lt;span class="nc"&gt;UserValidator&lt;/span&gt;
&lt;span class="nc"&gt;UserMapper&lt;/span&gt;
&lt;span class="nc"&gt;UserHelper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five classes, one entity. If the email-format rule from the example above lives in &lt;code&gt;UserValidator&lt;/code&gt;, the discount calculation lives in &lt;code&gt;UserService&lt;/code&gt;, and &lt;code&gt;User&lt;/code&gt; itself is just the anemic getter/setter bag — then no single object owns any rule. The rules float between service and helper classes that operate &lt;em&gt;on&lt;/em&gt; data rather than objects that are &lt;em&gt;responsible for&lt;/em&gt; their own data. That's a procedural program wearing class syntax, not OOP.&lt;/p&gt;

&lt;p&gt;The fix isn't to delete &lt;code&gt;UserService&lt;/code&gt; — coordinating multiple objects across a use case is a legitimate job for a service layer. The fix is narrower: &lt;strong&gt;the rule that only concerns &lt;code&gt;User&lt;/code&gt;'s own state&lt;/strong&gt; (is this email valid, can this balance go negative) belongs on &lt;code&gt;User&lt;/code&gt;, not scattered across whichever class happened to need it first. Everything in sections 3 and 7 — encapsulation as invariant protection, behavior bound to state — comes down to this one habit: before writing a rule, ask which object it actually belongs to.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Note on Rich vs. Anemic Models
&lt;/h2&gt;

&lt;p&gt;The examples in this article intentionally focus on objects that own and enforce their own invariants.&lt;/p&gt;

&lt;p&gt;That does not mean every architecture must place every business rule inside an entity.&lt;/p&gt;

&lt;p&gt;The important question is not where a piece of code physically lives, but which part of the system is responsible for maintaining correctness.&lt;/p&gt;

&lt;p&gt;Responsibility matters more than placement.&lt;/p&gt;

&lt;p&gt;CRUD applications, reporting systems, data pipelines,&lt;br&gt;
and some functional architectures intentionally separate&lt;br&gt;
data from behavior.&lt;/p&gt;

&lt;p&gt;Anemic models become a problem only when invariants&lt;br&gt;
and business rules end up scattered with no clear owner.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Core Essence&lt;/th&gt;
&lt;th&gt;Not to Be Confused With&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encapsulation&lt;/td&gt;
&lt;td&gt;Access control + invariant protection&lt;/td&gt;
&lt;td&gt;Lifecycle/resource management (&lt;code&gt;close()&lt;/code&gt;, GC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inheritance&lt;/td&gt;
&lt;td&gt;Subtype substitutability (LSP)&lt;/td&gt;
&lt;td&gt;The default tool for code reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polymorphism&lt;/td&gt;
&lt;td&gt;Runtime dispatch through a shared abstraction&lt;/td&gt;
&lt;td&gt;Overloading (ad-hoc polymorphism)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abstraction&lt;/td&gt;
&lt;td&gt;Hiding detail at the right level&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;interface&lt;/code&gt;/&lt;code&gt;abstract class&lt;/code&gt; (just a tool)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;None of this is really about Java — swap in any language with dynamic dispatch and a garbage collector and the same points hold.&lt;br&gt;
The four properties above are useful vocabulary, but they are not the essence of OOP.&lt;br&gt;
The deeper idea behind object-oriented programming is responsibility.&lt;br&gt;
An object owns identity and state, exposes behavior, and protects the invariants that define its correctness. Some invariants belong to individual objects, while others belong to larger parts of the system. The role of design is to place each responsibility where it can be protected most reliably.&lt;br&gt;
Encapsulation, Inheritance, Polymorphism, and Abstraction are valuable tools, but they matter only insofar as they help responsibilities stay in the right place and correctness remain protected.&lt;br&gt;
To go deeper: SOLID principles, Domain-Driven Design (DDD), Dependency Inversion, and Rich Domain Model vs. Anemic Domain Model.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>oop</category>
      <category>programming</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
