Abstraction is the practice of hiding complicated details behind a simple, named way to use them. You give a piece of code a clear surface (a function name, a button, a request) and everything tangled underneath stays out of sight. The person using it only needs to know what it does, not how.
Think of driving a car. You press the accelerator and it goes faster. You don’t think about fuel injection, spark timing or the gearbox, even though all of that is happening. The pedal is the abstraction: one simple control sitting on top of a lot of machinery. Software works the same way, and a clean API is a good example of abstraction in action, because it lets one system ask another for something without knowing a thing about the code behind it.
Good abstraction is also what makes code readable. When you can call sendInvoice(customer) instead of wiring up fifty lines of email and PDF logic every time, the intent is obvious. That clarity is a big part of what people mean by clean code. It pays off most when something has to change. Say your payment provider switches from PayPal to Stripe. If every screen in the app called the raw PayPal code directly, you would be editing dozens of files and praying you missed nothing. With a good abstraction, there is one chargeCard() function and you rewrite only what is behind it. The rest of the app never notices. The trap is going too far, though. Wrap everything in five layers of indirection and the code gets harder to follow, not easier. The art is picking the few spots that genuinely benefit and leaving the rest plain.
At TopDevs we lean on abstraction deliberately so the systems we build stay easy to extend, because the parts that change most often are kept behind a stable, simple surface.