Good code is not just code that runs. It is code that solves the real problem, behaves as expected, and remains understandable when someone needs to change it. In his June 6, 2025 DEV Community essay, Ibrahima D. offers a practical set of principles for making those decisions: start with a working solution, avoid speculative complexity, favor predictable behavior, and change systems in small, validated steps. These are useful defaults—not a formal standard or a universal ranking.
What these coding principles are for
Ibrahima D. frames his ideas as a personal compass assembled from experience with both new and legacy software, rather than as original inventions or rules that apply identically to every project. The point is to make everyday choices less arbitrary: what to build now, what to simplify, when to abstract, and how to reduce risk when changing code. His concise premise is: “Frameworks come and go. Principles stay.” Read the essay on DEV Community.
The examples below are illustrations of the author’s advice, not results from controlled tests. Their value is in the questions they help a developer ask before committing to a design.
Start with a working, correct solution before optimizing
Make it work, make it right, make it fast
The sequence attributed to Kent Beck is: first get a solution working, then improve its clarity and correctness, and optimize when there is a real performance reason. For a user list, that could mean fetching and displaying the data, then refactoring and testing the implementation, and only then considering a cache if the page is demonstrably slow.
#1 Best Overall
This is a decision aid, not a guarantee that every task should follow the same stages. The important distinction is between measured or observed performance trouble and optimization based only on speculation. A fast implementation that is incorrect is not a finished solution; an optimization that adds complexity without addressing a real problem may not be worthwhile.
Avoid building for imagined requirements
YAGNI: You Aren’t Gonna Need It
YAGNI is a reminder to build for needs that are known, rather than adding features because they might someday be useful. If a request is for CSV export, a general-purpose exporter supporting JSON, XML, and PDF is not automatically a better answer. Implement the requested capability and expand it when actual requirements call for expansion.
This does not mean ignoring credible constraints or making change impossible. It means treating hypothetical future flexibility as a cost: extra paths must be understood, tested, and maintained even if nobody uses them.
Make behavior easy to predict
Principle of Least Surprise
A function should do what its name and the surrounding conventions lead a teammate to expect. A getUser() function that also writes a last-login timestamp hides a side effect behind a name that sounds like a read. Making the write explicit—or giving the operation a name that communicates it—helps callers reason about what will happen.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Predictability also argues against clever compact code when the cleverness makes behavior harder to anticipate. Shorter is not automatically clearer.
KISS: Keep It Simple
Prefer a design teammates can read and change. A 200-line function controlled by multiple flags may be harder to understand than several small, named functions with clear responsibilities. Simplicity, however, is not a license to hide surprising behavior or remove structure that genuinely helps explain the problem.
Rank #3
Reduce duplication without creating the wrong abstraction
DRY: Don’t Repeat Yourself
DRY is most useful when duplicated code represents the same piece of knowledge. If password validation is separately implemented in signup, password reset, and backend code, a policy change applied in only some places can leave inconsistent behavior. One authoritative rule can make that knowledge easier to update consistently.
But two snippets that look alike today may need to change in different ways tomorrow. Extracting them prematurely can couple separate concerns and make later edits awkward. Before consolidating code, ask whether it is genuinely the same rule, not merely similar text.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →SOLID: five design principles, not a checklist
SOLID names five object-oriented design ideas. The examples here show the kinds of design pressure each is meant to address; they are teaching illustrations, not formal definitions or proof that applying a principle guarantees a better outcome.
Rank #4
- Single Responsibility: A class that handles user data, notifications, and persistence has several reasons to change. Separating responsibilities can make those changes less entangled.
- Open/Closed: A payment design should make it possible to add a new payment method without repeatedly rewriting stable existing logic.
- Liskov Substitution: A subtype should work where its base type is expected. A square/rectangle example can expose trouble when a subtype’s behavior violates assumptions callers make about the parent.
- Interface Segregation: Avoid forcing a client to depend on a large interface when it only needs a small part of it.
- Dependency Inversion: Keep business logic from being tightly tied to a concrete implementation such as a specific database; depend on an appropriate abstraction where that flexibility addresses a real need.
These ideas are most useful when the system’s actual change patterns justify the additional structure. Applying them mechanically can conflict with YAGNI and make a straightforward solution harder to follow.
Make risky changes in small, validated increments
Baby steps
Instead of making a large change and testing only at the end, work in short cycles: make a small edit, check it, and commit a coherent increment. When a check fails, fewer changes need to be investigated. A useful sequence of commits can also make tools such as git bisect more effective when tracking down which change introduced a regression.
Small steps do not eliminate defects, but they can make failures easier to locate and changes easier to review or reverse.
Best Value
The Mikado Method
For a refactor with dependencies, such as a library upgrade that breaks several files, first try the desired change and record the failures and prerequisites it reveals. Then revert that attempt, address the prerequisites in small, validated changes, and retry the goal once the code is ready.
- Attempt the end goal so the required work becomes visible.
- Note the dependencies and failures that block it.
- Revert the broad attempt rather than leaving the project in a broken intermediate state.
- Resolve prerequisites in small changes, checking each one as you go.
- Try the goal again and validate the result.
The method turns an intimidating refactor into a sequence of smaller problems, while preserving a working baseline between attempts.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.How to choose when the principles conflict
The principles can pull in different directions. DRY may suggest extracting shared code, while KISS or Least Surprise may favor keeping two similar pieces separate if they serve different purposes. SOLID may suggest a flexible abstraction that YAGNI says is not yet needed. Performance work can compete with readability when no concrete slowdown has been established.
Ibrahima D. proposes this rough priority order: working solution, YAGNI, least surprise, KISS, DRY, SOLID, then performance. Treat it as his decision aid, not an industry-wide standard. Its practical message is that a lower item should not be pursued in a way that breaks a more important need—for example, do not optimize at the expense of correctness, or abstract speculative features into a design that is harder to understand.
Recommended Free Tools
For a real decision, consider the tradeoff directly:
- Build now or anticipate later? Solve demonstrated requirements; revisit added flexibility when a real need appears.
- Remove duplication or preserve independence? Centralize a shared rule, but do not bind together code that is likely to evolve differently.
- Make it compact or predictable? Prefer names and behavior that let a teammate understand side effects without decoding cleverness.
- Add structure or keep the present solution simple? Use SOLID where it addresses a real source of change pressure, not as a checklist.
- Make a large refactor or take validated steps? Expose dependencies, then reduce risk through smaller, reversible changes.
- Optimize or improve correctness and clarity? Establish that the solution works and is right before spending complexity on speed without a real performance need.
A useful closing question is the author’s own: “What’s the smallest, simplest thing that makes this work?” It does not settle every design choice, but it helps expose when a proposed feature, abstraction, or optimization has outrun the problem it is meant to solve.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




