• Why Government Tech Tenders in Singapore Needs Revamp

    I recently spent a considerable amount of time working with a government client to explore an app development project. We went deep into understanding the problem, brainstorming possible solutions, identifying constraints, and scoping out practical approaches. But just as we were starting to make progress, the project got yanked into the familiar black hole of bureaucracy: a rigid, poorly-defined tender was issued, seemingly designed to tick boxes than solve the actual problem.

    This isn’t the first time. But each time it happens, it’s disheartening.

    A Process That Punishes Innovation

    These government procurement processes are built to be transparent and fair, and rightly so. It would work prefectly fine for buying a bunch of laptops, or constructing a basketball court. But when it comes to technology projects, the structure of these tenders is fundamentally broken. The system rewards those who can respond to overly prescriptive, unrealistic tender documents, not those who best understand or can solve the underlying problem.

    Too often, these tenders are written after the agency has already gone out and sought informal advice – sometimes even prototyped or trialed solutions – but instead of incorporating these learnings into an agile, iterative approach, they fall back on old-school waterfall RFPs.

    The Problem with Fixed Requirements

    Technology, unlike construction or hardware supply, is not a domain where you can define everything upfront. The entire software industry has moved away from rigid requirements-gathering for good reason: we don’t always know the end solution, but we do know the problem we’re trying to solve.

    That’s why #Agile practices have become the norm – because they accept uncertainty as a reality and focus on iterative progress toward a shared goal. Yet in the tendering process, government agencies are forced to cast vague assumptions into stone, creating a scope that no vendor can fulfill without overcharging, over-engineering, or outright guessing.

    The result? Vendors quote sky-high prices to protect themselves from the ambiguity – or worse, they underquote, win the bid, and the project collapses mid-flight due to unrealistic expectations, scope creep, or misalignment between the stated requirements and actual user needs.

    Focusing on Process Instead of Problems

    Perhaps the most frustrating aspect is the focus on process over outcomes. So many tenders are framed around implementation timelines, documentation deliverables, and checkbox compliance without clearly articulating the real-world pain points or desired business outcomes.

    We should be seeing tenders that begin with:

    • “Here’s the problem we are trying to solve.”
    • “Here are the constraints and stakeholders.”
    • “We want your expertise in helping us figure out the best solution.”

    Instead, what we get is a 20-page legal document and:

    • “Build X, Y, and Z with ABC tech stack.”
    • “Deliver within six months.”
    • “Provide five user manuals and a training deck.”

    A Call for Change

    Singapore has bold ambitions in tech: Smart Nation, GovTech, digital transformation across the public sector. But these ambitions are being held hostage by legacy procurement practices that actively undermine the principles of good software design and delivery.

    What we need is a new paradigm for technology procurement, one that:

    • Starts with problem statements, not rigid feature lists
    • Embraces agile, iterative delivery models
    • Allows for co-creation with vendors, not just transactional handoffs
    • Encourages value-based evaluation, not just lowest cost or most compliant

    Let’s stop punishing good faith collaboration with broken processes. Let’s start solving real problems together.

    Because if we keep doing this the old way, we’re not just wasting vendors’ time – we’re wasting taxpayers’ money.

  • What is Good Code?

    What is Good Code?

    Many junior to mid-level engineers have misconceptions about what “good code” truly mean. Unfortunately, these misunderstandings are often reinforced by flawed hiring practices. LeetCode problems, parroting SOLID principles, or memorizing framework features might showcase technical knowledge, but they don’t inherently make someone a good Software Engineer.

    Mess is Everywhere

    Throughout my career, I’ve encountered my fair share of messy codebases. An example would be functions/methods that stretched over a thousand lines of business logic—an unmaintainable monstrosity. Such code is a hallmark of inexperienced teams and often plagues poorly managed software outsourcing projects. I’ve probably written my share of such code when younger too.

    Seasoned engineers would say that this is “common.” Even at tech giants like Google or Microsoft, codebases aren’t pristine. Messes are inevitable, and documentation can also be inconsistent.

    Still, there’s a difference between an unavoidable mess and a completely avoidable disaster.

    If It Ain’t Broke, Don’t Touch It?

    A few years ago, I was troubleshooting a particularly stubborn issue with another team. The tech lead said that adding more code to an already bloated, thousand-line controller method was risky. He wasn’t wrong—it could take days to figure out where to make even minor changes, and the risk of breaking something was high. To add to the problem, the codebase did not have unit tests.

    But what happened next left me speechless.

    The Undocumented, Untraceable Code

    The tech lead decided to “solve” the issue by writing a standalone PHP script, completely outside the Laravel framework we were using. His justification? Frameworks were “too slow” and “too complicated.”

    His script lived in some random folder on the server, undocumented and untracked. Hours of debugging later, we stumbled upon it by sheer luck. And it wasn’t a one-off—we later found there were several such scripts scattered across the server, mostly undocumented and introducing untraceable logic into production.

    At that point, nobody cared about the quality of his algorithms (they were terrible, by the way) or whether his code followed SOLID principles (it didn’t). The real issue was far worse: he prioritized personal convenience over team collaboration. His decisions created a codebase that was not only a nightmare to maintain but also actively sabotaged the team’s ability to function effectively.

    Coding Beyond Yourself

    As software engineers, we don’t work in silos. Writing code that you alone can understand is easy. Writing code that a hundred others can maintain? That’s the real challenge.

    The example above is a cautionary tale of what not to do. Good engineering isn’t about showing off your technical prowess; it’s about making thoughtful decisions that benefit the team, ensure long-term maintainability, and foster a culture of collaboration.

  • Rethinking Technical Interviews: Lessons from My Experience

    Rethinking Technical Interviews: Lessons from My Experience

    Earlier this year, after being laid off, I went through several interviews for technical roles. These interviews often involved take-home tests, coding assignments, and live coding sessions. While I completed a few, I eventually started declining most of them, finding many to be time-consuming and, frankly, ineffective.

    The Limits of Coding Tests

    Coding tests can serve as a basic filter for entry-level positions, but their value diminishes when applied to senior-level roles. If you’re hiring a Senior Engineer with 10–20 years of experience, coding proficiency isn’t the primary skill to assess—especially in a world where AI tools like ChatGPT can handle many coding tasks faster and more efficiently.

    Instead, the focus should shift to evaluating Problem-Solving, Critical Thinking, Learning Aptitude, and Communication Skills—competencies that I find many interviews overlook. These are the skills that enable senior engineers to lead, adapt, and contribute meaningfully to a team.

    The Core Skills: Problem Solving, Critical Thinking, Learning, and Communication

    These skills apply to candidates across all experience levels. Over the years, I’ve hired many mid-career switchers, often with limited coding backgrounds. People ask how I gauge their suitability, and my approach is simple:

    • Assess their problem-solving ability.
    • Understand their interests and what excites them.
    • Observe the quality of their questions and how well they articulate their thoughts.

    While I do conduct technical screenings to ensure foundational competency, I avoid assigning time-wasting take-home tasks or algorithmic puzzles that don’t reflect real-world job demands.

    Navigating the Era of AI-Assisted Interviews

    The rise of AI tools this year has also transformed interviews. Candidates can now use AI dicatation off-screen to assist with technical questions, making traditional coding tests even less reliable indicators of ability.

    To counter this, I focus on questions AI can’t answer effectively:

    • What are your hobbies?
    • What are you learning now, and why?
    • If you could explore something new tomorrow, what would it be?
    • What’s the most challenging or interesting project you’ve worked on?
    • How would you approach solving this real-world problem based on a scenario?

    These questions help reveal a candidate’s genuine interests, adaptability, and approach to problem-solving.

    The Rapid Pace of Technology

    Over my 20-year career, technology has evolved very quickly. I’ve worked with Turbo Pascal, PERL, Java, PHP, C, C#/.NET, Swift, Python, JavaScript, and countless frameworks, libraries, tools and operating systems. Every shift required adaptability and a willingness to learn.

    A person who can learn and adapt will thrive as technologies, tools, and frameworks continue to change.

    Final Thoughts

    Hiring the right people isn’t about filtering for a specific tech stack or testing for algorithmic skills your team may never need. It’s about finding individuals who can solve problems, adapt quickly, and communicate effectively. Those are the qualities that matter—and they’re what will drive your team forward.

  • How AI will transform Learning and Hiring in Software Development

    How AI will transform Learning and Hiring in Software Development

    The era of Google

    I remember my time as a student back in 1999: a new search engine, Google, was starting to edge out AltaVista and Yahoo — both of which dominated the Internet search landscape throughout the 90s. It was an exciting time for Computer Engineering, as open-source software like Linux was gaining traction in Enterprises. Microsoft and the Java ecosystem were also equipping us with powerful IDEs like Visual Studio, JBuilder, and IntelliJ with features like code completion. Yet, despite these advancements, we still relied heavily on books as primary sources of information. Exams were still handwritten, even for coding: we memorised library functions and syntax, despite having access to the Internet and some fairly advanced tools.

    Our schools insisted on handwritten code and taught us programming using Notepad instead of IDEs. At the time, student laptops were underpowered, and IDEs were huge memory and CPU hogs, running painfully slow. Despite the inconvenience, students like me made every endeavour to set them up, knowing the efficiencies they offered.

    Today, this all sounds ridiculous. With modern IDEs, who would memorise hundreds of function calls or API structures? I actively work across multiple programming languages and frameworks and use countless DevOps tools and certainly can not memorise everything; perhaps it’s age, but it’s nearly impossible to keep all these details in my head.

    The rise of AI

    Twenty-five years on, the world is vastly different, but education systems still lag in adapting to technological shifts. Educators remain cautious about how AI impacts academic integrity and the assessment of written or coding assignments. While AI use isn’t necessarily discouraged, it’s also not fully encouraged; students are however already using AI, much as we once turned to Google and IDEs in place of traditional textbooks.

    For Software Development, AI coding assistants are here to stay, yet they’re unlikely to replace Software Developers soon — especially those who leverage AI-enabled tools. There are stories of startups built by non-technical founders using AI-generated code, but the actual efficacy of purely AI-driven development remains unproven. 

    So, what should we teach students, and how should we evaluate professionals?

    Educational institutions and hiring managers must rethink how they assess skills in this new landscape.

    Developing Strong Fundamentals

    AI models today, especially large language models (LLMs), are not infallible. They can produce erroneous or nonsensical responses. Strong foundational knowledge enables students and professionals to evaluate AI outputs critically and refine prompts to achieve the desired results. From my experience with students using AI-generated code, those lacking fundamentals struggle to interpret the code correctly and often can’t integrate it with existing codebases. For instance, AI models can generate verbose scaffolding or unnecessary details that may disrupt the intended functionality. Without solid fundamentals, these additional complexities create confusion instead of clarity.

    Cultivating Critical Thinking

    Critical thinking is crucial for discerning when and how to use AI solutions effectively. Humans bring valuable contextual knowledge to problem-solving — something not easily available to AI. Tackling complex real-world problems often involves navigating nuances such as geographical, cultural, and political factors. As a simple example, a form with “first and last name” fields may not be culturally appropriate in some countries, especially in parts of Asia where such naming conventions are uncommon. While an AI model might “know” this in theory, it often requires a user’s insight and critical thinking to specify it in an AI prompt when generating a form.

    Mastering Communication

    Although AI can generate well-structured text, effective communication remains a uniquely human skill. Communication goes beyond words to include emotional intelligence, empathy, and cultural sensitivity. AI may one day grow up with us and learn every little bit of detail of our lives (it is a scary thought, but absolutely possible future) but it won’t easily replicate the nuances of face-to-face interactions, emotional cues, or the subtleties involved in team dynamics. Communication skills, therefore, remain vital for collaborating with others and expressing complex ideas in ways that are both clear and motivating.

    Conclusion

    As we move forward, Software Developers will still need to synthesize large amounts of information before even engaging AI. We may no longer need to memorise every technical detail or write every bit of code, but we’ll still need a robust foundation to understand, prompt, and critically evaluate AI-generated responses. AI is reshaping learning and hiring, but the fundamentals of understanding, thinking critically, and communicating effectively will remain core competencies in software development for the foreseeable future.

    This article was also posted on Medium.com:
    https://medium.com/@detach8/how-ai-will-transform-learning-and-hiring-in-software-development-642e3d678cc5

  • Modding the Armaggeddon MKA-2C keyboard

    I had this keyboard sitting around the house for a while and decided to modify it – specifically, change the switches to a silent one so I can use it in an office environment.

    tl;dr It’s not as “hot-swappable” as it was advertised to be.

    Switch compatibility

    It seems to be only compatible with Outemu 3-pin switches. The electrical pins are narrower than usual, which fits the board.

    I tried using an Akko 5-pin switch by cutting off the the two extra plastic pins on the sides, but it still didn’t fit well. The electrical pins and the center supporting stem are a little bit too thick. Even after shaving down the electrical pins, the switch does not sit flush with the top plate, so I’d advise to not use any 5-pin switches as it seems the dimensions are slightly off. Some other 3-pin switches may work, but I’m sticking with Outemu 3-pin for now.

    I went with the Outemu Lemon silent tactile 3-pin switches (NOT the V2 which are 5-pin), and they work great. They have a good amount of tactility and are very quiet. The only noise I have now are the rattling stabilizers which I will get to later.

    Removing the old switches

    Removing the old switches was a massive PITA. The cheaply-made sockets are inconsistent and some switches are very tightly seated; some pins have also corroded over time making it impossible to pull the switch out from the top with just a switch puller.

    I found that the best way to remove all the switches was to unscrew the bottom cover and push the center stem out from the back while slowly prying the top/bottom of the switch up from the front using a small, flat screwdriver. This took me over an hour and a lot of elbow grease, and also damaged a dozen switches along the way (broken pins, damaged outer casing) – so be prepared to toss the old switches (which are crap anyway).

    Installing new switches, reassembly

    The switch installation process was straightforward. Since I had the keyboard apart, it was also good to ensure that every switch sat nicely on the board. The same problem with the socket exists during installation – some are tighter than the others, so pushing them while the case is apart ensures the board sits flat with the switches.

    Extra dampening – painter’s tape

    I also added two layers of painter’s tape (aka masking tape – I use a high quality one from 3M so it doesn’t leave sticky residue) over the bottom of the circuit board to add some extra dampening.

    Stabiliser noise

    After having extremely silent switches, the only noise you notice are rattling from the cheap stabilisers that can’t be replaced. There are only two stabilizers on this keyboard: spacebar and right shift key.

    It seems the rattle is primarily from the hinge on the keyboard plate. Adding some dielectric grease can help reduce the noise. I didn’t have any, but would try it if I did.

    Conclusion

    I know this is a cheap keyboard, but I didn’t want to add it to the landfill so being able to reuse it for the office would be a great. The new pack of 90 switches costs me less than SGD $30 on Aliexpress, and is cheaper than buying another keyboard.

    After typing (including this blog post) on the keyboard for a while, I must say I like the Outemu Lemon switches are much better than the original blue clicky ones which I felt were too noisy, wobbly and inconsistent.

  • Obins Anne Pro (v1) User Guide

    Obins Anne Pro (v1) User Guide

    I was gifted this keyboard and decided to write a proper English User Guide as a contribution back to the community for the blessing. I believe many people are still using this keyboard even though it’s rather old, and the only other English user guide that exists is poorly translated from Chinese.

    Tested with firmware 1.40.00.

    Bluetooth/setup mode

    Enter setup mode by pressing FN+B. Pressing ESC or FN+B again exits the mode.

    When in setup mode, the keys 1, 2, 3, 4, A, B, 0, and + are lit.

    Once in setup mode, press the following to configure specific settings:

    • “+” – Enable bluetooth broadcast
    • “-” – Disable bluetooth (radio off)
    • FN+1, 2, 3 or 4 – Save current connection to a profile (1 thru 4) – bluetooth must be connected to device before saving
      • Red = no device saved
      • Yellow = device saved
      • Green = current connected device
    • 1, 2, 3 or 4 – Quick switch to a saved profile
    • FN+0 – Switch between Bluetooth Low Energy (BLE) mode and normal mode
      • Green – BLE mode (discovered device name contains “L0”)
      • Yellow – Normal mode (discovered device name contains “L1”)
      • Takes about a second or two to switch after you press the key
    • A – Enable/disable backlight auto-sleep (new in 1.40.00)
      • Green = Auto-sleep on (backlight will switch off after 1 minute)
      • Red = Auto-sleep off (backlight will not switch off)

    Switching layouts

    The keyboard has four different layouts:

    • Windows
    • Windows with ALT/FN/Menu/? keys as arrows
    • Mac (Alt and Win swapped)
    • Not sure (undocumented)

    How to switch modes:

    • Press L CTRL + R CTRL
    • Release either one CTRL while still holding the other down
    • Tap the released CTRL key to cycle through the modes

    You will see the numbers 1, 2, 3, 4 light up in green indicating the current layout mode.

    FN mode lock

    To activate FN lock:

    • Press ALT+ALT
    • Press ALT+ALT again to revert to normal mode

    There are no visual indicators to tell if you are in FN lock.

    Backlight modes

    Various backlight options are controlled through four function toggles:

    • FN+R – Turn off/on backlight
    • FN+T – Rate/speed change (for animated modes)
    • FN+Y – Backlight brightness (10 levels)
    • FN+U – Cycle through different backlight modes

    Available modes:

    • Static red
    • Static yellow
    • Static green
    • Static cyan
    • Static blue
    • Static purple
    • Static pink
    • Static orange
    • Static white
    • Static blue/white/red (France flag)
    • Static green/white/red (Italy flag)
    • Static cyan with white middle row (row 3)
    • Animated pulsing colour cycle
    • Animated rainbow scrolling/marquee
    • Random colour on keypress (fades away)
    • Random colour on keypress (remains lit)
    • Animated light spread on keypress
    • Animated random colour on keys

    Win key disable

    To disable the Win key (or Command key in Mac mode):

    • FN+WIN – Disable the WIN key
    • FN+WIN again to enable

    There’s no visual indicator on whether the key is locked or not. In Mac mode, FN+ALT locks the command key.

    DFU mode

    DFU mode is required for upgrading firmware.

    To enter DFU mode:

    • Unplug the USB cable
    • Hold ESC while poking the reset button behind the keyboard
    • Connect the USB cable

    These instructions are also posted as a README in GitHub:
    https://github.com/detach8/obins-anne-pro-user-guide/tree/master