Hi there!
I'm Abhilashini. Over the past 11 years, my work has revolved around three core areas: building for the web, automating manual processes, data analysis and visualisation. While these areas seem distinct, they share a common thread:
solving real-world problems through thoughtful design and engineering.
In solving problems, plans often deviate as complexity creeps in, assumptions falter, and past lessons fall short. Here, I share reflections on simplifying the complex, adapting to new constraints, and the continuous learning that shapes my perspective.
Find me on LinkedIn
Make things simple
The hidden price of powerful hardware
Today’s hardware readily handles complex code, but at a human cost down the line. Verbosity, even if performant, often creates friction for those maintaining and evolving the product. Engineering with empathy prioritises clarity and conciseness, building the unseen yet essential foundation for a truly well-designed user experience.
Design for structure, not content
Whether it’s a grid of fruits or financials, the underlying structure benefits from consistency. Good design and robust code avoid coupling to specific content; they focus on adaptable systems that embody shared intent. This structural thinking is a bridge between user needs and scalable solutions.
SOS from SOS (Shiny Object Syndrome)
A 10-line script often outlives 500 lines of “modern” boilerplate. New tools are valuable when they demonstrably improve the experience for our users or streamline the team’s ability to deliver value.
Anyone can code ≠ Everyone should
Quick scripts are fine for personal use. In collaborative systems, hacky code becomes a tax on everyone — including users. Code, like design systems, is a collective artifact. It thrives on shared understanding, not isolated experiments.
Redesign for needs, not trends
UX should be user-centric, not aesthetic. If users don’t struggle with the existing UI, ‘modernizing’ it is often just theater, consuming valuable engineering resources. Redesign when user feedback and data prove the current design fails. Otherwise, focus on incremental tweaks, not costly overhauls.
Tests prevent silent failures
Tests mean more code, but ensure reliability, silently guarding user trust and the product’s promised behavior. They’re systems designed to break when changes stray from the agreed intent — exposing gaps before they become fractures.
Universal programming
Programming’s universal grammar — logic, structure, constraints — transcends stacks. These principles form a lingua franca beyond languages and frameworks: a shared foundation for aligning intent, adapting tools to problems (not trends), and building systems that outlast their code.Complexity dissolves when we focus on why systems hold, not how they’re built.
Breakdown complex things
Refactor with intent, not haste
Rewriting code on impulse risks breaking what users rely on. Even flawed systems have hidden purpose. Refactor only after tests safeguard agreed needs and plans ensure continuity for users.
Code with vision, not velocity
Clarity on requirements builds reusability, not just deliverables. Prioritise “plug and play” systems over “patch and pray” fixes.
| ✅ Plug and Play | ❌ Patch and Pray | |
![]() |
![]() |
System design is a map, not a maze
If a code block doesn’t trace to a user flow or data-driven need, it’s noise. Codebases thrive when they embody user purpose, not just how they work. Good products are anchored in code charted by what users seek, not just what engineers ship.
Code to Context, Not Frameworks
Frameworks and algorithms solve narrow problems. When they warp a product’s design, users inherit quirks that compound into design debt. Bend tools to user needs, never the reverse.
def button_label(action, device):
if device == “screen_reader”:
return f”Press to {action}”
return action.capitalize()
Maintainable systems speak human
When errors leave developers guessing, users suffer too. Maintainability begins with empathy — for our future selves, users and inheriting developers. Self-diagnosing logs and user-readable errors turn debugging from scavenger hunts into guided fixes.
Understanding the unseen: Gestalt of knowledge
We often settle for surface-level understanding—what’s visible feels sufficient. But like an iceberg, what we see is rarely the full picture. True comprehension asks more: What’s beneath this? What shaped it? Without that pause, rushed judgments multiply complexity instead of solving it.
Pages of influence
The Design of Everyday Things
Good design is invisible; bad design shouts.
Programming Pearls
Simplicity beats brute-force complexity.
The Creative Programmer
Creativity thrives under constraints.
Clean Code
Code is read far more than written.
How to Make Things Faster
Measure before optimizing; bottlenecks hide.
How to Solve It
Break problems into smaller, testable chunks.
The Nature of Software Development
Value flows from working software.
A Common-Sense Guide to Data Structures and Algorithms
Understand tradeoffs, not just implementations.
AI & I: My Learning Loop
Query-able Encyclopedia
AI collapses research time — but only when I ask the right questions. The better my inputs, the sharper its outputs.
Invisible Learning Curves
Coding with AI feels like untangling knots in the dark — it lacks the context humans intuit. Constraints and unspoken needs slip through prompts, leaving gaps only experience fills.
Pinpoint Tutoring
No more forum deep dives. Now I ask, “Explain X like I’m a novice”, and iterate until it clicks.
Code with Guardrails
AI accelerates grunt work (Codeium/Copilot), but I review every suggestion. It writes code; I write the checks.
Chain of Thought
Can GPT refine DeepSeek’s output, then Gemini critique GPT’s? Sometimes. Coherence erodes with each hop.
Voice Isn’t a Preset
AI rephrases and polishes, but it can’t replicate our quirks. Style is a template; voice is human — messy, inconsistent, and uncopyable.

