AI 资讯
Breaking Into Full-Stack Development Without a CS Degree: What Actually Worked for Me
Breaking Into Full-Stack Development Without a CS Degree: What Actually Worked for Me I didn't go through a computer science program. What I have instead is about seven years of shipping production code, learned almost entirely from official documentation, open-source repos, developer communities, and a lot of trial and error on real client work. If you're on that same path and wondering whether it's enough — here's what actually moved the needle for me, and what turned out to be a waste of time. What worked Building things that had to work, not things that looked good on a syllabus. Tutorial projects teach syntax. Client work teaches you what happens when a payment webhook fires twice, or when your "simple" CRUD app suddenly needs to survive 10x the traffic you designed for. The fastest learning happened on real, slightly terrifying production systems — not curated coursework. Reading source code and official docs before reaching for a course. Anyone can follow a video tutorial. Fewer people will sit with Laravel's own documentation, or actually read through a library's source when the docs run out. That habit compounds — you stop being dependent on someone else pre-chewing the material for you, and you get faster at picking up whatever stack a client happens to be using. Writing about what I learned. Technical writing forced me to actually understand things well enough to explain them, not just well enough to copy-paste them into working code. If you can't write a clear paragraph about why you chose NgRx over plain component state, you probably don't understand it as well as you think. Taking freelance and agency work early, even underpriced. Nobody hands a self-taught developer a senior role on day one. What they will do is pay you to fix their bug, or build their MVP, or maintain their legacy app. That's your CS degree — it's just distributed across a dozen small, real engagements instead of four years in one building. What didn't work (or wasn't worth the time)
AI 资讯
Your AI Agent Doesn’t Need More Prompts. It Needs Skills!
Tired of explaining the same things again and again to your AI Agent? Frustrated because the AI keeps forgetting minute things custom to your codebase which needs to be kept in mind in each change? This is the current scenario for most people using AI agents to build their software. You handoff a task to it, it gives back the solution but misses something. You explain that to it, it nods back and then does it again. I myself did it until i came to know about Skills. What are Skills? Remember the CONTRIBUTING.md file we find in almost every open source repository? The file which explained anyone coming to the repo what to check, understand and keep in mind when contributing to it so that you don’t break it. The Skills works like that for any AI Agent who is going to make changes in your codebase. Its a folder that your AI checks anytime it needs to perform a specific task, specialized jobs or multi-step workflows without requiring you to prompt every time. And the best thing is, it follows an open standard that works with almost every AI agent be it Claude Code, Cursor, Copilot and more. It follows a folder-based structure around a SKILL.md file containing YAML metadata about that skill and instructions for that in markdown. How to build a Skill? Skills can vary from simple instructions to multi-step workflows depending on your need and there are 3 ways (limited by my knowledge) to build a skill: Manually First you need to create a dedicated folder for your skill and place a SKILL.md file inside it. This file needs to have 2 things: YAML frontmatter for metadata( name & description ) Instructions in markdown. Below is a basic sample SKILL.md file for your reference: — - name: word-counter description: Counts the total number of words in a given text. — - Word Counter Instructions Take the user’s input text. Count the total number of words. Return only the final word count as a number. Using a generator/CLI It is a tooling interface (command-line or script) which can
AI 资讯
HyperFrames: HTML-to-MP4 Rendering as an Agent-First Primitive
HyperFrames is a TypeScript framework that takes HTML, CSS, and GSAP animations and produces seekable MP4 files. It runs locally via CLI, integrates with AI agents through MCP and skills.sh, and ships with a hosted playground. The core promise is deterministic video output from code, which means agents can write HTML and get frame-perfect video without manual timeline editing. The project has 42K stars and is trending #11 on GitHub for TypeScript. HeyGen built it to make video generation programmatically addressable. The architecture is Puppeteer for DOM rendering, GSAP for animation timing, and FFmpeg for encoding. The interesting part is how it guarantees determinism when each layer is async by default. Why HTML-to-Video Matters for Agents Most video generation tools target human designers. You drag keyframes, adjust curves, export. Agents need something different: a function that takes structured input and returns a file. HyperFrames treats video as a build artifact. You write HTML with animation code, run a command, get an MP4. This shifts video from creative workflow to infrastructure. An agent can generate a data visualization, encode it as HTML with GSAP transitions, and call HyperFrames to render. No GUI, no manual export, no non-deterministic output. The same HTML always produces the same video. The MCP server integration means agents can invoke HyperFrames as a tool. The skills.sh distribution packages it as a skill set that coding agents can install and call. This is video rendering as a first-class agent capability, not a side effect of screen recording. Architecture: Puppeteer, GSAP, and FFmpeg HyperFrames chains three components: Puppeteer launches a headless Chromium instance and loads your HTML. GSAP (GreenSock Animation Platform) runs animations inside the browser. GSAP is deterministic because it uses explicit timelines, not CSS transitions or requestAnimationFrame drift. FFmpeg encodes the captured frames into MP4 with H.264 or other codecs. The p
AI 资讯
The Upload Succeeded, the Record Did Not
Originally published on hexisteme notes . I built a YouTube upload stage for a video pipeline, and the flow looked clean enough on paper: start a resumable session, PUT the file, get back a video ID, verify the upload actually landed the way it was supposed to, then write a local record marking the episode as uploaded. Four steps, each one depending on the last. It was the dependency between the last two that turned out to be the problem. The sequence, and where it breaks Verification here means re-querying the video through videos.list after the upload finishes, to confirm the visibility wasn't silently demoted, the upload wasn't rejected, and the metadata actually propagated. That's a reasonable thing to check — YouTube's upload API can report success at the transport layer while the platform-side processing does something you didn't ask for. But if that verification call raises, the exception propagates straight up, and the local record — a JSON file I'll call upload.json — never gets written. Not "gets written with an error flag." Never written, period. By the time that exception fires, though, the video already exists on YouTube. The PUT succeeded. The video ID is real. There's a public (or not-quite-public) video sitting on the channel, and there is exactly nothing on disk that knows about it. Run the same command again after that, and the guard that's supposed to answer "have I already uploaded this?" — a check for whether upload.json exists — sails right through, because it doesn't exist. The result isn't a retry. It's a second, completely independent upload of the same video. What "retries don't duplicate" actually meant The module's docstring said retries don't create duplicate videos. That line wasn't wrong, exactly — it was scoped narrower than it read. It was true for retries inside the low-level file-PUT function, which reuses the same resumable session URI on retry, so transport-layer hiccups during the upload itself are genuinely safe to retry. What
AI 资讯
Building a Modular C++ Static Library: Clean Architecture, Encapsulation, and Safe Input Handling
As C++ codebases scale, housing utility routines, state management, and primary execution logic inside a single main.cpp file inevitably leads to technical debt. Code duplication increases, compilation times degrade, and testing isolated features becomes virtually impossible. Modular architecture solves this problem by enforcing a strict separation of concerns. By decoupling function declarations from their definitions and compiling utility modules into reusable static libraries, developers can achieve clean abstraction boundaries, simplify unit testing, and eliminate memory corruption vulnerabilities associated with unvalidated inputs. In this tutorial, you will learn how to build a production-grade C++ utility module from scratch, complete with boundary guards and static compilation. Prerequisites Before diving in, ensure you have: A modern C++ compiler supporting C++17 or higher (GCC, Clang, or MSVC). Basic familiarity with header files ( .h ) and translation units ( .cpp ). A Code Editor or IDE such as Visual Studio Code or Visual Studio . Project Structure To keep boundaries clean, we structure our workspace by isolating public headers from implementation units: text ModularCppLib/ ├── include/ │ ├── ArrayUtils.h │ └── ValidationUtils.h ├── src/ │ ├── ArrayUtils.cpp │ └── ValidationUtils.cpp ├── main.cpp └── README.md Phase 1: Structural Abstraction and Memory-Safe API Design Separating Interfaces from Translation Units In production C++ engineering, headers ( .h ) serve as explicit architectural contracts. They declare what operations are available without leaking how those operations are executed. All utility routines are scoped inside the explicit CoreUtils namespace to prevent global namespace pollution: namespace CoreUtils { // Contract: Accepts array pointer and length, // returns calculated mean safely double CalculateAverage ( const int * arr , std :: size_t size ); // Formats and prints array content void PrintArray ( const int * arr , std :: size_t si
AI 资讯
Beyond Passing Tests: A 100-Lens Framework for Evaluating Context-Aware AI Coding Agents 🤖
AI coding agents are getting better at writing code. But I think we are approaching a more difficult question: How do we know that an AI agent made the right engineering decision for the current state of a software system? Passing tests is important. But passing tests alone does not necessarily tell us whether an agent understood: the current architecture, project constraints, previous engineering decisions, repository conventions, dependency relationships, security requirements, or why an existing implementation looks the way it does. This becomes particularly important as AI systems move from generating isolated code snippets toward modifying real repositories. The Problem: Correct Code Is Not Always Correct Engineering Consider a simple example. A project initially has: Architecture v1 API ↓ Service ↓ Database An AI agent is asked to add a feature. It studies the repository, follows the existing pattern, writes the code, and all tests pass. Then the architecture changes: Architecture v2 API ↓ Event Bus ↓ Service ↓ Database The same task is requested again. If the agent still generates code based on the old architecture, the implementation may be: ✓ Valid syntax ✓ Compiles ✓ Existing tests pass ✗ Violates current architecture ✗ Ignores current constraints So we have an important distinction: Functional Correctness ≠ Contextual Correctness ≠ System-Level Correctness This is the problem I want to explore. This Is Already Becoming a Real Engineering Problem This isn't simply speculation about future AI systems. Modern coding agents already depend on repository-level context. OpenAI's documentation for Codex recommends using persistent repository instructions such as AGENTS.md for naming conventions, business logic, known quirks, dependencies, and other information that may not be inferable directly from code. It also recommends providing file paths, component names, diffs, and documentation when describing tasks. OpenAI has also described a broader approach where rep
AI 资讯
reCAPTCHA: It’s Not Just “I’m Not a Robot”
How CAPTCHA evolved from typing distorted text to analyzing behavior, context, and risk When most people hear CAPTCHA, they imagine a small checkbox: ☐ I’m not a robot Or perhaps a challenge asking them to select traffic lights, bicycles, buses, or crosswalks. But modern reCAPTCHA is much more interesting than that. In many cases, you don't actually solve anything. You simply open a webpage, move your mouse, click a button, fill out a form—and somewhere in the background, a risk-analysis system is trying to answer a much harder question: “Does this interaction look like a legitimate human interaction, or automated/abusive traffic?” That is a fundamentally different problem from asking a user to identify a picture. Google describes reCAPTCHA as a service that uses advanced risk-analysis techniques to distinguish humans from bots. Modern versions can return a risk score instead of presenting a visible challenge. 1. The original CAPTCHA problem CAPTCHA originally stood for: Completely Automated Public Turing test to tell Computers and Humans Apart. The basic idea was simple: Humans are good at recognizing distorted characters. Traditional computer programs were not. So the website could display something like: but distort, rotate, or obscure the characters. The user typed: 7hK9P and the website accepted the answer. This created a simple classification: It worked reasonably well. Until machines became better. 2. Then computers learned to read the CAPTCHA This created an interesting security race. CAPTCHA became harder. Then OCR and machine learning became better. So CAPTCHA became even harder. Eventually the system was moving toward: Human intelligence vs machine vision And that created an unfortunate side effect. The better the security became, the worse the experience became for legitimate users. Instead of: «“Are you human?”» the user was suddenly being asked: «“Select every square containing a traffic light.”» And sometimes: «“Select every square containing a traffi
AI 资讯
How treating my job search like a product problem helped me see what’s really making software engineering recruitment hard in 2026
Get ready for a bit of a ramble about looking for a job as a software engineer in 2026. No, it's not about AI changing the definition of software engineering in 2026. But there's obviously some truth in that. It's about product engineering. Specifically, it's about the challenges engineers face when searching for new opportunities because of the massive shift toward product engineering. I should preface what comes next with this: Searching for a software engineering job in 2026 is really hard. Scroll through LinkedIn or any software career blog and you'll see plenty of posts about how the recruitment system is broken, how good engineers are being ghosted, how CVs are being filtered out by AI screening for keywords. These frustrations are valid, but... you know what else is really hard in 2026? Being a software engineering recruiter. Being a software engineering hiring manager. And software engineering is about solving problems. With that said, you can't solve a problem you don't define. So to lay the foundation, I want to address some challenges I've recognised before addressing what can be done about them. The Problem Space First, the thing that's been haunting me for the last 6 months. Impact articulation . I suspect this isn't a problem that's unique to product engineering, but it's certainly one I've faced as a product engineer. Earlier this year, I completed full interview processes with two separate companies. I felt confident about both. The roles were the type of engineering I'm great at: sitting close to users, working through ambiguity and owning product areas end to end. But neither resulted in a job offer. The feedback I received was surprisingly consistent: I demonstrated strong technical execution, methodical problem-solving, clear communication and product judgement, and consistently sought to understand the "why" behind the "how". But also, I struggled to connect my product decisions to business or user outcomes. It was clear that I was a great engin
AI 资讯
From Developer to Architect — What Really Changes?
One of the biggest transitions in a software engineer’s career is moving from “How do I implement this?” to “How should we design this?” As developers, we naturally focus on writing clean code, implementing features, fixing bugs, and improving performance. But as you move toward an architect role, the questions become different: 🔹 Scalability — Will this solution work when the number of users or transactions increases 10x? 🔹 Maintainability — Can another team understand and extend this solution two years from now? 🔹 Security — Are authentication, authorization, data protection, and secrets management considered from the beginning? 🔹 Performance — Where could bottlenecks occur, and how can we identify them before they become production issues? 🔹 Resilience — What happens when a dependent service goes down? 🔹 Integration — How will this solution interact with existing enterprise systems? 🔹 Technology choices — Does the technology solve the actual business problem, or are we choosing it simply because it is popular? 🔹 Trade-offs — What are we gaining, and what are we giving up with each architectural decision? A senior developer asks: “How can I build this feature?” An architect asks: “What is the right solution for the business, technical, operational, and long-term requirements?” The most important lesson I’ve learned is that architecture is not about creating complicated diagrams or using more technologies. Good architecture is about making the right decisions at the right level , understanding trade-offs, and creating solutions that can evolve with the business. And you don't suddenly become an architect because of a designation. You gradually become one by thinking beyond your code. Java #SoftwareArchitecture #SpringBoot #Microservices #SoftwareEngineering #JavaDeveloper #TechnologyLeadership #Architect
AI 资讯
Building an ASCII Art Generator with AI: The Good, The Bad, and The Figlet
The Problem I was staring at my terminal during a deploy, waiting for the build to finish, when I realized something: I'd been typing figlet "Hello World" into my terminal for years to generate ASCII art for commit messages and README files. But every time I wanted to share that art with someone who wasn't a developer, I hit a wall. "Just install figlet," I'd say. "Install what now?" they'd reply. The problem wasn't that ASCII art tools don't exist online. The problem was that the ones I found were either bloated with ads, required JavaScript frameworks that made the page take forever to load, or couldn't handle non-Latin characters gracefully. I wanted something that just worked in a browser tab, no installation, no server, no fuss. So I decided to build my own. Because apparently I enjoy reinventing wheels. The AI-Assisted Development Journey Here's where things get interesting. I've been using AI pair programming for a while now, and this project felt like the perfect test case: it's well-defined, has clear requirements, and involves a lot of repetitive font data that would be tedious to type manually. The Initial Prompt I started by describing the requirements to an AI assistant in pretty specific terms: Build a single-file HTML tool that converts text to ASCII art. Must have multiple fonts (Block, Slant, Small, Standard, Mini). Real-time preview. Copy to clipboard. Download as .txt. Support dark mode. Chinese/English i18n. Vanilla JS only. The AI came back with something surprisingly decent. It had the basic structure right, the font data was embedded, and the rendering logic was clean. But there were issues. Where AI Got It Wrong The first problem was character handling . The AI assumed that all input would be uppercase English letters. When I tested with lowercase, numbers, and special characters, it just... broke. Not crashed, but silently dropped characters. // What the AI initially wrote (simplified) function getChar ( char , font ) { return font [ char .
AI 资讯
Log bem feito na era dos agentes
Disclaimer Este texto foi inicialmente concebido pela IA Generativa em função da transcrição de um vídeo do canal Dev Eficiente, apresentado por Alberto Souza. Se preferir acompanhar por vídeo, é só dar o play. Introdução O vídeo que deu origem a este texto foi gravado há quase três anos. Na época, o que me incomodava era simples de descrever: log é um tema comum no dia a dia, mas resolvido de forma artesanal. Cada pessoa da equipe decide, no momento em que escreve o código, se aquela linha merece registro, se o nível é info ou debug, e quais informações vão junto. A comparação que eu fazia era com testes automatizados. Você juntava dez pessoas para escrever testes sobre o mesmo conjunto de classes e saíam baterias completamente diferentes, com abordagens diferentes, às vezes deixando uma branch de fora. Cada pessoa tinha uma opinião sobre o que era importante, e não havia um modelo de pensamento compartilhado por trás disso. Com log eu sentia algo parecido. Como a resposta não estava clara para mim, passei uns dois dias procurando o que o mercado discutia e o que a pesquisa acadêmica tinha investigado sobre práticas de log. Reuni umas cinco ou seis referências e é isso que este post organiza: o que cada referência contribui e quais práticas dá para extrair delas. Mantive as referências e as conclusões como estavam na época. Acrescentei apenas uma seção sobre algo que mudou bastante desde a gravação e que torna esse assunto mais relevante hoje do que era então: a quantidade de código escrito com apoio de IA e a investigação de problemas feita com apoio de agentes. Por que log bem feito importa mais hoje Nos últimos anos mudou bastante quem escreve o código e, principalmente, quem investiga o problema quando ele aparece. Quando parte relevante do código é gerada com apoio de IA, a familiaridade de quem mantém aquele trecho com cada decisão tomada ali tende a ser menor. Você definiu a intenção, revisou o resultado, aprovou. Mas não construiu, linha a linha, o modelo m
AI 资讯
How I Enforced a Privacy Rule, Commented It, Yet Still Shipped a Data Leak – Lessons Learned
AI-Powered Privacy Policy Generators LLM‑driven privacy policy generators have moved from experimental prototypes to production‑grade services in 2026, offering on‑demand, jurisdiction‑aware drafts that can be directly embedded into compliance pipelines. Tools such as PrivacyGPT and PolicyCraft combine retrieval‑augmented generation with rule‑extraction models, turning natural‑language privacy intents into enforceable policy clauses that can be exported as JSON‑LD or plain‑text templates. Deep Dive Architecture PrivacyGPT leverages a hybrid architecture: a domain‑specific transformer fine‑tuned on 10 million privacy statements, paired with a deterministic rule engine that maps extracted obligations to GDPR, CCPA, and emerging AI‑Act provisions. PolicyCraft adds a feedback loop where the generated draft is automatically validated against an internal compliance knowledge graph; mismatches trigger a self‑correcting prompt that iteratively refines the text until a confidence score above 92 % is achieved. Real-World Engineering Examples A fintech startup integrated PrivacyGPT via its CI/CD pipeline; each pull request that modifies data‑collection code triggers an API call that updates the “Data Retention” clause, keeping the public policy in sync with code changes. A multinational e‑commerce platform deployed PolicyCraft to generate locale‑specific consent banners; the system produced 27 variants in under five minutes, each certified against the EU’s Digital Services Act. Zero‑Trust Architecture for Rule Enforcement Zero‑trust architecture (ZTA) starts from the assumption that no network segment—whether on‑prem, cloud, or edge—can be implicitly trusted. Instead of a perimeter, every request is evaluated against a continuously refreshed identity profile that fuses user credentials, device posture, and behavioral risk scores. In practice, this means deploying a Policy Decision Point (PDP) that consumes attributes from an identity provider, a device‑trust service, and a tel
AI 资讯
SSKCore: Turning Production Pain Into an Android Platform [PART-2]
📚 This is part 2 of a series. Part 1: The Origin Story Part 2: [Current Article] Part 3: Coming soon... Let me tell you about the day my crash reporting UI crashed. The Grey Screen One afternoon, my Android app's crash screen rendered all-grey. No content. No report button. Just a blank slate where the app's last line of defense should have been. The root cause? A stale file from Gradle's build cache after a major refactor. The compiled resource IDs no longer matched the packaged resource table. ViewBinding inflated the wrong layout, and a silent NullPointerException killed the crash screen itself. It was invisible in CI. It only appeared in specific rebuild scenarios. And it took hours to trace. That bug taught me something important: The fix isn't done when the patch ships. It's done when the lesson becomes automated. So I wrote a build-time task that reads the compiled class files directly, compares them against the final packaged resources, and verifies every constant matches. It runs automatically after every packaging step. You never have to remember to invoke it. That was the first of many incident-driven tools I built. The FAB That Disappeared A few weeks later, a developer tools Floating Action Button vanished from consumer apps. Debug menus inaccessible. Secure screens incorrectly enabled. Turns out, my shared library's BuildConfigUtils was reading the library's own BuildConfig —which is baked as "release" at publish time. An AAR can never know the consumer's build type. 25 files across 34 call sites were silently broken. I built a Gradle plugin that generates a SskBuildConfig object per consumer module, per variant, using AGP's onVariants callback. It registers generated source via KotlinCompile.source() —not reflection, which broke across AGP versions. It detects Android plugins by extension type, not hardcoded IDs, so it works with com.android.application , com.android.library , com.android.dynamic-feature , and any future Google plugin. Same package as
AI 资讯
A Windows Desktop App Is “Not Responding”: Diagnose the Wait Before Reinstalling
A frozen desktop window is a state, not a diagnosis. Windows adds Not Responding when the UI thread stops processing messages for long enough. That can happen because the application is doing legitimate work, waiting for disk or network I/O, blocked by another process, stuck behind a modal dialog, or caught in a real deadlock. Reinstalling may replace files, but it does not tell you what the process was waiting for. Preserve a few minutes of evidence first. Define the symptom precisely Keep these cases separate: Slow: the window still repaints and eventually accepts input. Not responding: the frame is visible, but Windows reports that the app is not processing messages. Blank: the frame appears while the content surface fails to render. Invisible: the process runs without a visible main window. Crash: the process exits and may create an application error event. This distinction matters. A blank WebView surface and a blocked UI thread can look similar to a user, but they leave different evidence. Use one repeatable action Restart the application once and perform the smallest action that reproduces the freeze. Record: the exact click or file that triggers it; the time the action starts; how long the window remains responsive; whether CPU, disk, or network activity changes; whether the process recovers without being terminated. Avoid opening several test files or clicking repeatedly. Extra input can queue more work and hide the original transition. Watch the process before ending it Open Task Manager and identify the correct process ID. Expand child processes if the application uses helpers or a web-rendering runtime. Useful observations include: High sustained CPU: a loop, intensive parsing, OCR, compression, or rendering work is plausible. Near-zero CPU with disk activity: the process may be waiting for storage. Near-zero CPU with network activity: an online request, proxy, DNS, or TLS operation may be blocking progress. Near-zero activity everywhere: look for a hidd
AI 资讯
Building a Plug-and-Play JVM Compiler for Android and Desktop with Bytesmith
What if adding Kotlin and Java compilation to your application didn't mean building an entire compilation pipeline yourself? What if you could add Bytesmith, configure the filesystem once, provide your source files and output destination, and simply compile? That's the idea behind Bytesmith . Bytesmith is a Kotlin and Java compiler toolkit designed for JVM and Android applications. It provides a unified API for Kotlin, Java, and mixed-language compilation, while also supporting filesystem abstraction, custom classpaths, boot classpaths, compiler plugins, packaging, and diagnostics. Configure the environment, provide the source, specify the output, and compile. The problem Compiler tooling can become surprisingly difficult when it is tightly coupled to the environment in which it was originally designed to run. You might need to deal with: Kotlin compiler versions Kotlin standard libraries Java compilation Bootclasspath configuration Dependency classpaths Source discovery Output handling Android storage Storage Access Framework URIs Packaging Compiler diagnostics And then there is the question of where those files actually live. On a desktop JVM, you might have traditional filesystem paths: /home/user/project/src/Main.kt On Android, you might be working with application storage or files selected through the Storage Access Framework: content://... If your compiler API directly depends on java.io.File , your compilation code becomes coupled to one filesystem model. Bytesmith takes a different approach. Adding Bytesmith The goal is to make compilation something you can plug into an application. With Gradle: implementation ( "io.github.sifisofakude.bytesmith:bytesmith-common:1.0.0" ) After adding Bytesmith, configure the filesystem your application wants to use. For a JVM application: FileSystems . current = JvmFileSystem () For Android: FileSystems . current = AndroidSafFileSystem ( context ) Once the filesystem is configured, the rest of the compilation layer can opera
AI 资讯
My Caption Width Guard Passed Every Test. It Was Measuring Text the Renderer Never Drew.
Originally published on hexisteme notes . A user complaint sent me into a caption pipeline: "the subtitles cut to two words in places where the sentence doesn't make sense." The fix I shipped for that complaint introduced a second bug, one word narrower and easy to miss, because the code that measured whether a line of text would fit reproduced an assumption about the text that the code drawing the line didn't share. Every test passed the whole time. I only found it by watching the rendered video. The bug the complaint pointed at The captioning system splits a transcript into short chunks that pop onto screen a few words at a time. The chunking function was doing fixed-size slicing — take the next N words, regardless of what came before or after. That's blind to sentence boundaries, so two unrelated sentences could land in the same chunk: loss. Today reads as one visual unit even though it's the tail of one sentence and the head of the next. The fix was a rule set, not a single tweak: hard break after terminal punctuation ( . ! ? … ) soft break at commas, semicolons, and em-dashes extend or push a chunk rather than let it end on a function word ( of , the , than , is , and about thirty others) target three words per chunk, four as a ceiling a pixel-width cap on the rendered chunk, measured against the actual caption font (Montserrat ExtraBold), with a budget of 1080 × 0.92 = 993.6px The first four rules are about where a line is allowed to break. The fifth is a physical constraint: however good the break points are, a chunk still has to fit on screen at the font size actually in use. That's the one that went wrong. What the width guard actually measured To get the pixel width of a candidate chunk, the guard rendered the chunk's text through the font and measured the result — which is the correct approach in principle, not a shortcut. Text width isn't a fixed number of pixels per character; it depends on the specific glyphs, so measuring the real string through the r
AI 资讯
What if you don't have to build a login page again?
How do you usually build a login page in an application? The first project Imagine you are working on a project that needs a login page. Let's call it Aurora (Project A). The login page is the entry point to the application. Users who have access can log in to the application with the permissions they have. We are not going to talk about the details of the login method yet, such as email + password, username + password, phone + password, social login, magic link, or others. Let's say we use email + password for this example. For this, we usually need user data for the application, for example a users table in the database. If we use email and password as the login method, the users table would at least need email and password columns. Of course, the password should be hashed. After the application is developed, users can log in using the email and password registered in the database. During development, we can simply inject user data directly into the database. Adding one or two users manually is still fine. If we need more users, we can create a database script to insert them. Then another requirement appears. We need to manage users directly from the application. Previously, user data could only be accessed directly from the database. Now the application needs to show a list of users, user details, and provide features to create, update, and delete users. We need to build several new pages for this user management feature. Eventually, the feature is completed. Now you can add users whenever you want, and they can immediately use their account to log in to Aurora. At this point, the user requirements for Aurora might be enough. The second project Then you have another project that also needs a login page. Let's call it Borealis (Project B). This is a different project from Aurora, but the login works in a similar way. Since you already built the login feature in the previous project, you can duplicate the existing code into Project B, including the user management
AI 资讯
Next step to client-side storage
Next step to client-side storage In my past one blog, I wrote about how I improve the performance of the application using the local storage. And the problem local storage solves. But now I face another problem about the client storage. My project is simply about order management software for the rental clothing industry. In the rental clothing industry, Showrooms or small shops have a big problem. The problem starts when one order has a single or multiple items that are booked in a particular time range. Now, a second order wants the same item in between that particular time range. If, by mistake, the second order books that item, then the problem starts. The item is booked two times in that particular time range. That is called double booking of the item. This mistake is created by the use of traditional register booking. Now, when I need to store the items data, that is a small amount of data, so I simply use the local storage. But now I need another and a big storage for storing order details. I build two features: first one is for showing all the orders and second one is for showing the full order. To implement those features and to maintain the user experience, I decide to store a small amount of data about the order on the client side. First, I decide to store data in local storage. But to store data in the local storage is not a good option because the local storage is used for storing small details about the application, and storing order details in the local storage compromises the performance of the application. Now I want a new storage option for storing order details. And again I find out, and that is the IndexedDB. To integrate IndexedDB in my application, I want to learn about that storage. I search multiple videos about IndexedDB, but no one is teaching me properly. After finding hundreds of tutorials, I finally found one tutorial that is teaching properly how to integrate IndexedDB in the application. Now I want to share that learning with you. To i
AI 资讯
Product Engineering Alignment
A feature takes three days to code and three weeks to deliver. The difference is not always engineering capacity. A developer starts implementation and discovers that an eligibility rule is undefined. Product needs an answer from operations. A missing UX state appears next. Then engineering finds that the requested behavior conflicts with the current data model, which forces a scope decision. The code may still take three days. The delivery system takes three weeks. This is where product engineering alignment becomes an engineering leadership problem. The visible work happens in code, but much of the elapsed time happens between decisions: waiting for clarification, resolving constraints, revisiting scope, and discovering assumptions that should have surfaced earlier. The common response is to improve requirements, add meetings, or demand better estimates. Those actions may help, but they do not address the core issue. Product-engineering alignment is primarily a decision-flow problem . The useful question is not: Are product and engineering communicating enough? It is: Where does work stop because the person holding it cannot make the next decision? That question is more useful because it exposes where delivery actually slows down. Why Product and Engineering Become a Delivery Bottleneck Product and engineering approach the same feature with different knowledge. Product typically understands the customer problem, business priorities, stakeholder expectations, commercial constraints, and desired outcome. Engineering typically understands architecture, dependencies, operational risk, implementation alternatives, and the cost of changing the system. Neither side has the full picture, that is normal. The problem begins when the process assumes one side can finish its thinking before the other begins. Consider a requirement that appears simple: Allow customers to cancel an order. Engineering cannot implement that correctly without answering several questions: Until what
AI 资讯
Shipping Stock CLIs as Subprocess Instead of Static-Linking SDKs
I'm building yyzTools, which bundles 9 third-party engines (OpenSSL, FFmpeg, ImageMagick, pdfcpu, Aria2, 7-Zip, RapidOCR, Everything...). I chose to spawn them as subprocesses rather than static-link their SDKs. Here's why—and the cost. The conventional approach When your app needs OpenSSL crypto, FFmpeg video processing, ImageMagick image ops—you reach for the SDK. Link libssl, link libav*, link libMagick. One binary, no external deps, fast function calls. It's the textbook answer. I did the opposite. yyzTools ships the stock CLI binaries (openssl.exe, ffmpeg.exe, magick.exe, pdfcpu, aria2c, 7z) and spawns them as subprocesses. The C++ layer is a thin loop: build args → CreateProcess → read stdout → wrap as JSON → return. It doesn't know what -gravity southeast or sm4-cbc means. It just passes the algorithm name through. Why I went this way Upgrades without recompiling This is the big one for a desktop app. OpenSSL ships a CVE, or adds sm2/sm3/sm4 support in 3.x. If you've static-linked, you recompile the whole app, run full regression, re-release, and every user reinstalls. With the subprocess model, I drop in a new openssl.exe. Zero C++ changes. The update is a few-MB delta, not a full reinstall. For a product where users won't tolerate reinstalling for a library bump, this is the deciding factor. No symbol conflicts OpenSSL, zlib, libpng—multiple libraries want to own these symbols. Static linking them all into one binary is a recipe for "which inflate did I just call?" With subprocess CLIs, each tool brings its own dependencies in its own process. No conflict. Transparent supply chain openssl version, ffmpeg -version—auditing which version of each tool is live is trivial. It's an independent binary. Far easier than digging symbols out of a statically-linked blob. Free crash isolation If ffmpeg.exe misbehaves, it exits non-zero and my host wraps that as an error. My main process keeps running. A static-linked bug can take down the whole app. The process boundary