1<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="astro-view-transitions-enabled" content="true"><meta name="astro-view-transitions-fallback" content="animate">
1<script type="module" src="/_astro/ClientRouter.astro_astro_type_script_index_0_lang.j56hQv-j.js"></script>
1<!-- Primary SEO --><title>Oursky - Blog</title><meta name="description" content="Thoughts on software engineering, product design, and building remarkable digital products from the Oursky team."><link rel="canonical" href="https://www.oursky.com/blog/"><!-- Open Graph --><meta property="og:type" content="website"><meta property="og:title" content="Oursky - Blog"><meta property="og:description" content="Thoughts on software engineering, product design, and building remarkable digital products from the Oursky team."><meta property="og:url" content="https://www.oursky.com/blog/"><meta property="og:image" content="https://www.oursky.com/images/og-default.png"><meta property="og:site_name" content="Oursky"><!-- Twitter Card --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="Oursky - Blog"><meta name="twitter:description" content="Thoughts on software engineering, product design, and building remarkable digital products from the Oursky team."><meta name="twitter:image" content="https://www.oursky.com/images/og-default.png"><!-- Favicon --><link rel="icon" type="image/png" href="/favicon.png"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- Borna Webfont is self-hosted via @font-face in global.css --><!-- Preload the most-used weights for faster LCP --><link rel="preload" href="/fonts/borna-regular.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="/fonts/borna-medium.woff2" as="font" type="font/woff2" crossorigin><!-- Structured data -->
1<script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","@id":"https://www.oursky.com/#organization","name":"Oursky","url":"https://www.oursky.com/","logo":"https://www.oursky.com/images/og-default.png","sameAs":["https://www.linkedin.com/company/oursky-limited/","https://www.facebook.com/oursky.hk","https://www.instagram.com/oursky.hk/","https://twitter.com/oursky","https://github.com/oursky"]}</script>
1<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","@id":"https://www.oursky.com/#website","url":"https://www.oursky.com/","name":"Oursky","publisher":{"@id":"https://www.oursky.com/#organization"},"inLanguage":"en"}</script>
1<script async src="https://plausible.io/js/pa-wM4pfvIYRQVuIgaXue7ry.js"></script>
1<script> 2 window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}}; 3 plausible.init() 4 </script>
4<link rel="stylesheet" href="/_astro/BaseLayout.9rkPZlJE.css"> 5<style>.blog-page-title[data-astro-cid-5tznm7mj]{background-image:var(--gradient-page-title);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text} 6</style></head> <body> <div id="site-header" class="header-wrapper" data-astro-cid-qlfjksao> <header class="header relative flex w-full max-w-full items-center justify-between gap-1 max-md:justify-center max-md:gap-2 sm:gap-2 md:max-w-none mx-auto pointer-events-auto" data-astro-cid-qlfjksao> <!-- Logo pill (tablet+ â Webflow hides separate header icon below md) --> <!-- data-astro-reload: home page loads Brevo's main.js (is:inline) to wire 7 the newsletter form; ClientRouter swaps would skip that bootstrap. --> <a href="/" data-astro-reload class="pill logo-pill relative z-[2] mr-2 hidden flex-none items-center justify-center no-underline sm:mr-4 md:flex lg:mr-5" aria-label="Oursky home" data-astro-cid-qlfjksao> <img src="/images/oursky-logo.svg" alt="Oursky" width="80" height="36" class="block h-6 w-auto max-w-full object-contain sm:h-7 lg:h-8" onerror="this.style.display='none';this.nextElementSibling.style.display='block'" data-astro-cid-qlfjksao> <span class="text-lg font-bold text-black" style="display:none" data-astro-cid-qlfjksao>Oursky</span> </a> <!-- Nav: centered in remaining space <md; absolutely centered md+ (tablet + desktop). Retracts on scroll down at md+. --> <div class="header__nav-center header__nav-center--desktop relative z-[1] flex min-w-0 flex-1 justify-center px-0.5 max-md:max-w-[min(100%,26rem)] max-md:flex-none md:pointer-events-none md:absolute md:inset-x-0 md:top-1/2 md:z-[1] md:flex md:w-full md:max-w-none md:flex-none md:-translate-y-1/2 md:justify-center md:px-0" data-astro-cid-qlfjksao> <nav class="pill nav-pill flex max-w-full flex-none gap-0.5 overflow-x-auto px-1.5 py-0.5 max-md:gap-1 sm:gap-1 sm:px-1.5 sm:py-1 md:pointer-events-auto lg:gap-1 lg:px-3 lg:py-2" aria-label="Main navigation" data-astro-cid-qlfjksao> <!-- Phone: logo inside nav bar replaces Home (ref: Webflow .navbar__icon) --> <a href="/" data-astro-reload class="nav-pill__brand md:hidden mr-0.5 flex shrink-0 items-center justify-center rounded-full no-underline transition-transform duration-300" aria-label="Oursky home" data-astro-cid-qlfjksao> <img src="/images/oursky-logo.svg" alt="" width="50" height="11" class="nav-pill__brand-img pointer-events-none block h-[0.68rem] w-auto max-w-[3.4rem] object-contain" aria-hidden="true" data-astro-cid-qlfjksao> </a> <a href="/" data-astro-reload class="nav-link flex h-full shrink-0 items-center rounded-full px-1.5 py-0.5 text-xs font-medium leading-tight text-black no-underline whitespace-nowrap transition-transform duration-300 sm:px-2 sm:text-sm sm:leading-snug lg:px-3 lg:text-lg lg:leading-9 nav-link--hide-below-md" data-astro-cid-qlfjksao> Home </a><a href="/about/" class="nav-link flex h-full shrink-0 items-center rounded-full px-1.5 py-0.5 text-xs font-medium leading-tight text-black no-underline whitespace-nowrap transition-transform duration-300 sm:px-2 sm:text-sm sm:leading-snug lg:px-3 lg:text-lg lg:leading-9" data-astro-cid-qlfjksao> About </a><a href="/services/" class="nav-link flex h-full shrink-0 items-center rounded-full px-1.5 py-0.5 text-xs font-medium leading-tight text-black no-underline whitespace-nowrap transition-transform duration-300 sm:px-2 sm:text-sm sm:leading-snug lg:px-3 lg:text-lg lg:leading-9" data-astro-cid-qlfjksao> Services </a><a href="/blog/" class="nav-link flex h-full shrink-0 items-center rounded-full px-1.5 py-0.5 text-xs font-medium leading-tight text-black no-underline whitespace-nowrap transition-transform duration-300 sm:px-2 sm:text-sm sm:leading-snug lg:px-3 lg:text-lg lg:leading-9 nav-link--active text-white nav-link--hide-below-md" aria-current="page" data-astro-cid-qlfjksao> Blog </a><a href="/works/" class="nav-link flex h-full shrink-0 items-center rounded-full px-1.5 py-0.5 text-xs font-medium leading-tight text-black no-underline whitespace-nowrap transition-transform duration-300 sm:px-2 sm:text-sm sm:leading-snug lg:px-3 lg:text-lg lg:leading-9" data-astro-cid-qlfjksao> Works </a> </nav> </div> <!-- Contact: icon-only <lg; label lg+ --> <a href="/contact/" class="pill contact-pill relative z-[2] flex flex-none items-center justify-center rounded-full no-underline text-black lg:min-h-[4.25rem] lg:px-[3.125rem] lg:py-4 lg:text-lg lg:font-semibold" aria-label="Contact" data-astro-cid-qlfjksao> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 16" fill="none" class="h-3.5 w-4 shrink-0 sm:h-4 sm:w-5 lg:hidden" aria-hidden="true" data-astro-cid-qlfjksao> <path d="M2.5 2.64011C2.14844 2.64011 1.875 2.95261 1.875 3.26511V4.16354L8.59375 9.67136C9.41406 10.3354 10.5469 10.3354 11.3672 9.67136L18.125 4.16354V3.26511C18.125 2.95261 17.8125 2.64011 17.5 2.64011H2.5ZM1.875 6.58542V13.2651C1.875 13.6167 2.14844 13.8901 2.5 13.8901H17.5C17.8125 13.8901 18.125 13.6167 18.125 13.2651V6.58542L12.5781 11.
71167C11.0547 12.3667 8.90625 12.3667 7.42188 11.1167L1.875 6.58542ZM0 3.26511C0 1.89792 1.09375 0.765106 2.5 0.765106H17.5C18.8672 0.765106 20 1.89792 20 3.26511V13.2651C20 14.6714 18.8672 15.7651 17.5 15.7651H2.5C1.09375 15.7651 0 14.6714 0 13.2651V3.26511Z" fill="currentColor" data-astro-cid-qlfjksao></path> </svg> <span class="hidden lg:inline" data-astro-cid-qlfjksao>Contact</span> </a> </header> </div>
7<script type="module">(()=>{const s=document.getElementById("site-header");if(!(s instanceof HTMLElement))return;const r=s.querySelector(".header__nav-center--desktop");if(!(r instanceof HTMLElement))return;const l=s,c=r,o=window.matchMedia("(min-width: 768px)"),a=window.matchMedia("(prefers-reduced-motion: reduce)");let n=window.scrollY;const h=10,f=6,u=40;function t(e){l.classList.toggle("site-header--nav-retracted",e),e?c.setAttribute("aria-hidden","true"):c.removeAttribute("aria-hidden")}function i(){if(!o.matches||a.matches){t(!1),n=window.scrollY;return}const e=window.scrollY;e<=u?t(!1):e>n+h?t(!0):e<n-f&&t(!1),n=e}function d(){(!o.matches||a.matches)&&t(!1)}window.addEventListener("scroll",i,{passive:!0}),o.addEventListener("change",d),a.addEventListener("change",d),i()})();</script>
7 <main class="min-w-0 max-w-full"> <main class="blog-page max-w-[var(--home-rail-max)] mx-auto pt-page-top px-[var(--home-rail-gutter)] pb-16 max-lg:pt-page-top-tablet box-border" data-astro-cid-5tznm7mj> <header class="scroll-reveal-group mb-12" data-astro-cid-5tznm7mj> <div class="ml-5 max-sm:ml-0 scroll-reveal-item" style="--sr-delay: 0ms" data-astro-cid-5tznm7mj> <h1 class="blog-page-title inline-block m-0 mb-4 text-5xl font-semibold leading-hero pb-2 max-md:text-hero-secondary max-md:leading-hero-sm" data-astro-cid-5tznm7mj>Blog</h1> </div> <p class="ml-5 max-sm:ml-0 text-xl text-black m-0 scroll-reveal-item" style="--sr-delay: 80ms" data-astro-cid-5tznm7mj> 8Our latest news and insights 9</p> </header> <ul class="scroll-reveal-group grid gap-6 sm:grid-cols-2 list-none p-0 m-0"><li class="scroll-reveal-item flex" style="--sr-delay: 0ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/customer-identity-management-why-and-how-to-implement-multifactor-authentication-mfa-in-consumer-apps/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Multifactor authentication </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/67785e4e21_66e303fdbf76331a3fa1bfd1_franck-DoWZMPZ-M9s-unsplash-1160x870.jpg" alt="Customer Identity Management: Why and How to Implement Multifactor Authentication (MFA) in Consumer Apps" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> Customer Identity Management: Why and How to Implement Multifactor Authentication (MFA) in Consumer Apps </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/development/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Development </a><a href="/blog-category/authgear/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Authgear </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 80ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/a-practical-guide-automating-passkey-testing-with-playwright-and-authgear/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Automated Testing </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/3fa40beebc_68109c18d0e0e55f13d361cf_image (2).webp" alt="A Practical Guide: Automating Passkey Testing with Playwright and Authgear" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> A Practical Guide: Automating Passkey Testing with Playwright and Authgear </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/authgear/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Authgear </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 0ms">
9<article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/a-minimum-viable-product-is-not-a-product----its-a-mindset/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Growth </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/91a94d5083_6799597c7e076a22d075685b_leon-vbxyFxlgpjM-unsplash-1-scaled.webp" alt="A Minimum Viable Product is Not a Product â Itâs a Mindset" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> A Minimum Viable Product is Not a Product â Itâs a Mindset </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/product-growth/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Product Growth </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 80ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/ai-vs-human-test-case-generation/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Software QA </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/8110973e01_66e300c2bdcd1bb946551a3f_8137885-scaled.webp" alt="AI vs Human: Test Case Generation" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> AI vs Human: Test Case Generation </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/qa/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> QA </a><a href="/blog-category/machine-learning-and-ai/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Machine learning and AI </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 0ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/geeks-way-to-say-things/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Code </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/753677757f_673e2cf2f36902869c96caaa_cover.webp" alt="Geekâs way to say things" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> Geekâs way to say things </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/code/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Code </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 80ms">
9<article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/ready-grow-your-clientbase-5-ultimate-project-management-templates/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Project Management </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/3172a64696_67994c2a974cebaa3edf8e4f_oursky-blog-img-220916.webp" alt="Ready Grow your Clientbase? 5 Ultimate Project Management Templates" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> Ready Grow your Clientbase? 5 Ultimate Project Management Templates </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/project-management/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Project Management </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 0ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/viper---ios-app-architecture-beyond-mvc-mega-viewcontroller/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Code </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/404d12a10d_673e2c371a8b4b3fe0c235c3_viper-.png" alt="VIPER â iOS App Architecture Beyond MVC (Mega-ViewController)" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> VIPER â iOS App Architecture Beyond MVC (Mega-ViewController) </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/code/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Code </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 80ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/10-best-ai-coding-assistant-tools---2024/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> AI and Machine Learning </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/b951f9150c_66e3fc0e1ff91c70fd6eafbe_deep-learning-ai-empowering-businesses-with-intel-2023-11-27-04-58-50-utc.webp" alt="10 Best AI Coding Assistant Tools - 2024" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> 10 Best AI Coding Assistant Tools - 2024 </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/machine-learning-and-ai/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Machine learning and AI </a><a href="/blog-category/development/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Development </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 0ms">
9<article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/10-motivational-quotes-from-women-in-tech/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Culture </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/0875377e54_67994ccf0615a7e0ea6f72f1_photo-1477724902304-4d75535625a0-768x512.jpeg" alt="10 Motivational Quotes from Women in Tech" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> 10 Motivational Quotes from Women in Tech </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/culture/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Culture </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 80ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/11-command-line-tips-that-you-probably-missed/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Geek </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/28e3fe7eff_67993db647f7923e8b796257_keep-calm-and-sudo.webp" alt="11 Command Line Tips That You Probably Missed" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> 11 Command Line Tips That You Probably Missed </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/engineering/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Engineering </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 0ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/12-things-we-wish-we-knew-before-we-became-developers/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> Culture </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44">
9 <img src="/images/blogs/f6c83c9e61_67994dd1b3407cd04b04cf46_Group-1.webp" alt="12 things we wish we knew before we became developers" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> 12 things we wish we knew before we became developers </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/culture/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Culture </a> </div> </article></li><li class="scroll-reveal-item flex" style="--sr-delay: 80ms"><article class="w-full bg-surface border border-[#E0E9EC] rounded-[20px] overflow-hidden transition-shadow hover:shadow-[0_2px_5px_rgba(0,0,0,0.1)] flex flex-col h-full"> <a href="/blogs/14-apps-to-help-you-work-smarter-not-harder/" class="group flex flex-col gap-4 no-underline p-10 pb-0 max-md:p-4 max-md:pb-0 max-md:gap-3"> <h3 class="text-base font-medium text-black uppercase tracking-[0.02em] leading-[38px] truncate m-0 max-md:text-sm max-md:leading-6"> GROWTH </h3> <div class="w-full h-[17.5rem] overflow-hidden rounded-md bg-muted max-md:h-44"> <img src="/images/blogs/55ad83deff_67994d9a86e9c74f13e4eb6f_Screen-Shot-2016-11-08-at-12.webp" alt="14 Apps to Help You Work Smarter, Not Harder" class="w-full h-full object-cover block transition-transform duration-300 group-hover:scale-[1.04]" loading="lazy" width="560" height="280"> </div> <h2 class="text-xl-plus font-normal text-black leading-[34px] m-0 line-clamp-3 min-h-[102px] group-hover:text-primary max-md:text-xl max-md:leading-7 max-md:min-h-[84px] max-sm:min-h-0"> 14 Apps to Help You Work Smarter, Not Harder </h2> </a> <div class="mt-auto flex flex-wrap items-center gap-1.5 px-10 pt-5 pb-10 max-md:px-4 max-md:pt-3 max-md:pb-5"> <a href="/blog-category/product-growth/" class="inline-flex items-center h-9 px-2.5 bg-muted text-sm font-semibold text-black tracking-[0.02em] whitespace-nowrap no-underline transition-colors hover:bg-accent"> Product Growth </a> </div> </article></li></ul> <nav class="mt-12 flex flex-wrap items-center justify-center gap-2 sm:gap-3" aria-label="Blog pagination"><ol class="flex flex-wrap items-center justify-center gap-1.5 list-none p-0 m-0" role="list"><li role="listitem"><span class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-semibold text-black bg-muted rounded-md" aria-current="page">1</span></li><li role="listitem"><a href="/blog/2/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">2</a></li><li role="listitem"><a href="/blog/3/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">3</a></li><li role="listitem"><a href="/blog/4/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">4</a></li><li role="listitem"><a href="/blog/5/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">5</a></li><li role="listitem"><a href="/blog/6/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">6</a></li><li role="listitem"><a href="/blog/7/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">7</a></li><li role="listitem"><a href="/blog/8/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">8</a></li><li role="listitem"><a href="/blog/9/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">9</a></li><li role="listitem"><a href="/blog/10/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">10</a></li><li role="listitem"><a href="/blog/11/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">11</a></li><li role="listitem"><a href="/blog/12/" class="inline-flex min-w-[2.5rem] justify-center px-3 py-2 text-sm font-medium text-text-muted no-underline rounded-md hover:bg-muted hover:text-primary transition-colors">12</a></li></ol><a href="/blog/2/" class="inline-flex items-center px-3 py-2 text-sm font-medium text-primary border border-border rounded-md hover:bg-muted no-underline transition-colors" rel="next"> 10Next → 11</a></nav> </main> </main> <footer class="site-footer w-full bg-bg"> <div class="w-full max-w-[1360px] mx-auto px-10 pb-10 box-border max-md:px-5 max-md:pb-5"> <!-- Dark card: logo + clocks --> <div class="bg-black rounded-lg flex justify-between items-center px-10 py-20 gap-8 mb-8 max-lg:flex-col max-lg:items-start max-lg:px-8 max-lg:py-16 max-md:px-6 max-md:py-12 max-md:mb-6"> <!-- Left: OURSKY logo + "We are hiring!" --> <div class="flex flex-col gap-3 justify-between shrink-0"> <div class="flex items-center gap-2 pr-10"> <a id="footer-logo-link" href="/" data-astro-reload class="inline-flex items-center gap-2 no-underline" aria-label="Oursky home"> <div id="footer-logo-lottie" class="w-20 h-20 shrink-0" aria-hidden="true"></div> <img src="/images/oursky-logo-footer.svg" alt="Oursky" width="141" height="30" class="block h-auto" style="width: 10rem"> </a> </div> <a href="https://jobs.oursky.com" target="_blank" rel="noopener noreferrer" class="inline-flex items-center gap-1 text-primary-dark text-lg font-bold leading-footer no-underline transition-opacity hover:opacity-60"> 12We are hiring! 13<span class="font-bold" aria-hidden="true">â</span> </a> </div> <!-- Right: two live clocks --> <div class="flex gap-12 items-start max-lg:gap-8 max-md:flex-col max-md:gap-6"> <!-- HK clock --> <div class="flex gap-8 flex-wrap items-start max-md:gap-5"> <div id="clock-container--hk" class="flex flex-col items-center justify-center"> <div class="flex justify-center items-center w-[6.3762rem] h-[6.3762rem] relative"> <svg class="w-full h-full" width="103" height="103" viewBox="0 0 103 103" fill="none" xmlns="http://www.w3.org/2000/svg"> 14 <path d="M54.5098 0H48.7708L51.5862 4.40147L54.5098 0Z" fill="#D9D9D9"/> 15 <path d="M54.5098 102.017H48.7708L51.5862 97.6151L54.5098 102.017Z" fill="#D9D9D9"/> 16 <path d="M28.621 5.39904L23.6509 8.26855L28.2899 10.6726L28.621 5.39904Z" fill="#D9D9D9"/> 17 <path d="M79.6293 93.7482L74.6592 96.6177L74.8967 91.3982L79.6293 93.7482Z" fill="#D9D9D9"/> 18 <path d="M102.648 53.8777L102.648 48.1387L98.247 50.9541L102.648 53.8777Z" fill="#D9D9D9"/> 19 <path d="M0.631836 53.8777L0.631836 48.1387L5.03331 50.9541L0.631836 53.8777Z" fill="#D9D9D9"/>
20 <path d="M97.2494 27.9892L94.3799 23.019L91.9758 27.658L97.2494 27.9892Z" fill="#D9D9D9"/> 21 <path d="M8.90052 78.9975L6.03101 74.0273L11.2505 74.2649L8.90052 78.9975Z" fill="#D9D9D9"/> 22 <path d="M79.6293 8.26844L74.6592 5.39893L74.8967 10.6184L79.6293 8.26844Z" fill="#D9D9D9"/> 23 <path d="M28.621 96.6176L23.6509 93.748L28.2899 91.344L28.621 96.6176Z" fill="#D9D9D9"/> 24 <path d="M94.38 78.9975L97.2495 74.0273L92.03 74.2649L94.38 78.9975Z" fill="#D9D9D9"/> 25 <path d="M6.03088 27.9892L8.90039 23.019L11.3045 27.658L6.03088 27.9892Z" fill="#D9D9D9"/> 26 <circle cx="51.6928" cy="51.0082" r="2.86951" fill="white"/> 27 <path class="clock__hand--hour" d="M49.1198 32.6873L51.7019 51.0098L54.1075 32.6741C52.5607 30.4796 51.6389 27.2997 51.6389 27.2997C51.6389 27.2997 50.6561 30.4053 49.1198 32.6873Z" fill="white"/> 28 <path class="clock__hand--minute" d="M49.0737 16.8969L51.7007 51.0147L54.0613 16.8832C52.5143 14.6888 51.5794 6.81542 51.5794 6.81542C51.5794 6.81542 50.6098 14.6147 49.0737 16.8969Z" fill="white"/> 29 </svg> </div> <p class="text-white mt-3 mb-0 text-lg leading-footer max-md:text-base">--:--</p> </div> <div class="flex flex-col gap-0"> <h3 class="text-white m-0 text-lg font-semibold leading-footer max-md:text-base max-md:leading-[1.8rem]">Oursky</h3> <p class="text-white m-0 text-lg leading-footer opacity-80 max-md:text-base max-md:leading-[1.8rem]">Hong Kong</p> <p class="text-white m-0 text-lg leading-footer opacity-80 max-md:text-base max-md:leading-[1.8rem]">Taipei</p> </div> </div> <!-- London clock --> <div class="flex gap-8 flex-wrap items-start max-md:gap-5"> <div id="clock-container--london" class="flex flex-col items-center justify-center"> <div class="flex justify-center items-center w-[6.3762rem] h-[6.3762rem] relative"> <svg class="w-full h-full" width="103" height="103" viewBox="0 0 103 103" fill="none" xmlns="http://www.w3.org/2000/svg"> 30 <path d="M54.5098 0H48.7708L51.5862 4.40147L54.5098 0Z" fill="#D9D9D9"/> 31 <path d="M54.5098 102.017H48.7708L51.5862 97.6151L54.5098 102.017Z" fill="#D9D9D9"/> 32 <path d="M28.621 5.39904L23.6509 8.26855L28.2899 10.6726L28.621 5.39904Z" fill="#D9D9D9"/> 33 <path d="M79.6293 93.7482L74.6592 96.6177L74.8967 91.3982L79.6293 93.7482Z" fill="#D9D9D9"/> 34 <path d="M102.648 53.8777L102.648 48.1387L98.247 50.9541L102.648 53.8777Z" fill="#D9D9D9"/> 35 <path d="M0.631836 53.8777L0.631836 48.1387L5.03331 50.9541L0.631836 53.8777Z" fill="#D9D9D9"/> 36 <path d="M97.2494 27.9892L94.3799 23.019L91.9758 27.658L97.2494 27.9892Z" fill="#D9D9D9"/> 37 <path d="M8.90052 78.9975L6.03101 74.0273L11.2505 74.2649L8.90052 78.9975Z" fill="#D9D9D9"/> 38 <path d="M79.6293 8.26844L74.6592 5.39893L74.8967 10.6184L79.6293 8.26844Z" fill="#D9D9D9"/> 39 <path d="M28.621 96.6176L23.6509 93.748L28.2899 91.344L28.621 96.6176Z" fill="#D9D9D9"/> 40 <path d="M94.38 78.9975L97.2495 74.0273L92.03 74.2649L94.38 78.9975Z" fill="#D9D9D9"/> 41 <path d="M6.03088 27.9892L8.90039 23.019L11.3045 27.658L6.03088 27.9892Z" fill="#D9D9D9"/> 42 <circle cx="51.6928" cy="51.0082" r="2.86951" fill="white"/> 43 <path class="clock__hand--hour" d="M49.1198 32.6873L51.7019 51.0098L54.1075 32.6741C52.5607 30.4796 51.6389 27.2997 51.6389 27.2997C51.6389 27.2997 50.6561 30.4053 49.1198 32.6873Z" fill="white"/> 44 <path class="clock__hand--minute" d="M49.0737 16.8969L51.7007 51.0147L54.0613 16.8832C52.5143 14.6888 51.5794 6.81542 51.5794 6.81542C51.5794 6.81542 50.6098 14.6147 49.0737 16.8969Z" fill="white"/> 45 </svg> </div> <p class="text-white mt-3 mb-0 text-lg leading-footer max-md:text-base">--:--</p> </div> <div class="flex flex-col gap-0"> <h3 class="text-white m-0 text-lg font-semibold leading-footer max-md:text-base max-md:leading-[1.8rem]">Skymakers</h3> <p class="text-white m-0 text-lg leading-footer opacity-80 max-md:text-base max-md:leading-[1.8rem]">London</p> <p class="text-white m-0 text-lg leading-footer opacity-80 max-md:text-base max-md:leading-[1.8rem]">Manchester</p> </div> </div> </div> </div> <!-- Open Source bar --> <div class="bg-footer-opensource rounded-lg px-8 py-5 max-md:px-6 max-md:py-4"> <a href="/open-source/" class="flex items-center justify-between no-u
45nderline transition-opacity hover:opacity-60"> <span class="text-black text-lg font-bold max-md:text-base">We ð» Open Source!</span> <span class="text-black text-lg font-bold max-md:text-base" aria-hidden="true">â</span> </a> </div> <!-- Copyright --> <p class="text-center text-black/60 text-sm mt-3 mb-0">Oursky Ltd. © 2026</p> </div> </footer>
45<script type="module">const h="Asia/Hong_Kong",g="Europe/London";function r(t,c,e){if(!t)return;const n=new Intl.DateTimeFormat("en-HK",{hour:"numeric",minute:"numeric",hour12:!0,timeZone:e}).formatToParts(c),o={};n.forEach(f=>o[f.type]=f.value);const i=t.querySelector(".clock__hand--minute"),s=t.querySelector(".clock__hand--hour"),u=t.querySelector("p"),d=parseInt(o.minute??"0"),m=parseInt(o.hour??"0"),I=o.dayPeriod??"",l=d/60,k=(l+m)/12;u&&(u.textContent=`${m}:${String(d).padStart(2,"0")}${I}`),i&&i.setAttribute("transform",`rotate(${l*360}, 51.6928, 51.0082)`),s&&s.setAttribute("transform",`rotate(${k*360}, 51.6928, 51.0082)`)}let y;function p(){clearInterval(y);const t=document.getElementById("clock-container--hk"),c=document.getElementById("clock-container--london"),e=new Date;r(t,e,h),r(c,e,g);let a=e.getUTCMinutes();y=setInterval(()=>{const n=new Date;n.getUTCMinutes()!==a&&(a=n.getUTCMinutes(),r(document.getElementById("clock-container--hk"),n,h),r(document.getElementById("clock-container--london"),n,g))},1e3)}document.addEventListener("astro:page-load",p);</script>
45
45<script type="module" src="/_astro/Footer.astro_astro_type_script_index_1_lang.BMosPksR.js"></script>
45 </body></html>
45<script type="module">function n(){const o=document.querySelector(".blog-page");if(!o)return;const s=o.querySelectorAll(".scroll-reveal"),l=o.querySelectorAll(".scroll-reveal-group");if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)s.forEach(e=>e.classList.add("scroll-reveal--visible")),l.forEach(e=>e.classList.add("scroll-reveal-group--visible"));else if(s.length||l.length){const e=new IntersectionObserver((r,i)=>{for(const c of r){if(!c.isIntersecting)continue;const t=c.target;t.classList.add(t.classList.contains("scroll-reveal-group")?"scroll-reveal-group--visible":"scroll-reveal--visible"),i.unobserve(t)}},{root:null,rootMargin:"0px 0px -5% 0px",threshold:.05});s.forEach(r=>e.observe(r)),l.forEach(r=>e.observe(r))}}n();document.addEventListener("astro:page-load",n);</script>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.