Toss

72 posts

toss.tech

Filter by tag

toss5 min readCurated summary

Getting AI to Provide Investment Information

LLMs make it easy to generate financial content, but producing trustworthy investment information requires much more than fluent summaries. Toss Securities argues that AI must pass three gates before reaching users: selecting reliable evidence, controlling how responses are generated, and making outputs measurable and improvable. The central principle is to constrain AI autonomy where reproducibility and traceability matter, while preserving it for open-ended exploration. ## Why Investment Information Is Different - **Timeliness:** Market interpretations can change within hours due to earnings, geopolitical events, or policy news. - **Accuracy:** A company mentioned in an article may not be the company whose stock moved; it could be a subsidiary, a similarly named firm, or merely a promotional mention. - **Traceability:** Every generated claim needs supporting evidence, evaluation records, and reproducible processing. - **Non-stationarity:** Market behavior changes across earnings seasons, interest-rate events, elections, and geopolitical crises. Prompts and models tuned to one period may degrade later. LLMs and autonomous agents amplify these challenges: - LLMs can produce fluent but incorrect answers when evidence is incomplete or ambiguous. - Agents add more failure points through search, tool calls, planning, and state transitions. - Errors can propagate through different execution paths, increasing operational cost and making debugging difficult. ## Gate One: Selecting What the AI Should Say The first gate is a context-engineering process that filters and organizes evidence before it reaches the LLM. ### Classify Data at Ingestion - News, disclosures, and financial data are classified as they arrive using internally developed BERT-based models. - Metadata includes: - Taxonomy tags - Related companies and entities - Embeddings for vector search - Pre-classifying data avoids waiting until retrieval to determine whether it is relevant. ### Retrieve Broadly, Then Narrow the Candidates A hybrid retriever first prioritizes recall, after which candidates are reduced through: - **Deduplication:** Semantically similar articles are clustered so one event is not treated as many independent events. - **Reranking and filtering:** Evidence is evaluated for direct relevance to the company’s price movement. - **Taxonomy labels:** Items are categorized by explanation type, such as earnings, guidance, or corporate actions. - **Failure labels:** Promotional content, insufficient evidence, and other unsuitable sources are explicitly marked and filtered out. - **Rubrics:** Evidence is ranked according to predefined relevance criteria. ### Build Reasoning-Friendly Context The final context is arranged so the model checks: - What happened - How the event connects to the target company - Whether the evidence’s polarity matches the stock’s price direction - Whether the evidence is sufficient and current This ordering combines the filtered evidence with metadata such as the company, price direction, and time window. ## Gate Two: Controlling How Responses Are Generated The second gate limits the action space of LLMs and agents to satisfy product requirements such as cost, latency, reproducibility, and observability. ### Use Task Graphs for Clearly Defined Work Instead of leaving the entire process to an autonomous agent, Toss Securities separates it into explicit stages: - Candidate retrieval - Relevance assessment - Deduplication - Evidence construction - Final response generation Each stage has defined input and output schemas, making it a debugging and evaluation point while simplifying fallbacks and operational monitoring. ### Choose Autonomy Based on Requirement Clarity - **Autonomous agents** are useful for open-ended tasks such as discovering investment ideas or exploring possible market scenarios. - **Procedural orchestration** is better for fixed tasks, such as explaining why a specific stock moved. - Long ReAct loops increase tool calls, token usage, latency, and trace-management costs. - For structured products, deterministic pipelines let LLMs focus on summarization, rewriting, and evidence-based explanation rather than tool selection. Procedural graphs are not merely a replacement for agents. Once defined, they can become reusable tools or sub-agents that other agents call through structured interfaces, such as: ```text input: ticker, direction, time_window output: explanation, evidences, reasoning_type ``` ## Gate Three: Making the System Evaluatable Subjective judgments such as “the answer feels weak” do not provide a reliable improvement loop. The system therefore generates structured classifications alongside natural-language responses. ### Generate Rubric Categories with Each Answer - Outputs include event or reasoning types and failure categories. - Structured fields make it possible to measure: - Relevance false positives - Directional mismatches - Irrelevant evidence passing the filter - Precision, recall, and F1 score - The taxonomy must evolve as new market regimes and failure patterns appear. - Operational failures, evaluation sets, prompt versions, and model versions should be linked so improvements can be reproduced and quantified. ### Retrieve Context-Specific Few-Shot Examples Fixed few-shot examples are insufficient because event and failure types vary widely across market conditions. Instead: - Store operational samples with their decisions, failure labels, and embeddings. - Embed each new classification or verification task. - Retrieve similar positive and negative examples. - Include both successful and failed examples to show the model the decision boundary. This approach reuses production failures as future evaluation guidance and significantly improves precision and accuracy while preserving recall. Since false positives are especially damaging in investment services, filtering out unsupported explanations is more important than producing fluent text alone. ## Work Beyond Prompts and Model Training Building an investment-information AI service also requires substantial infrastructure outside the model itself: - Retrieval strategies and embedding models for finding relevant evidence - Separately trained classifiers for categorization - Evidence filtering, validation, and metadata management - Structured orchestration, monitoring, evaluation, and feedback loops The practical recommendation is to treat the LLM as one component in a controlled evidence pipeline—not as the sole decision-maker. Use autonomous agents for exploratory tasks, but rely on traceable procedural graphs, evolving taxonomies, and retrieval-based examples when the product must deliver repeatable, defensible financial information.

Read original(opens in new tab)
toss5 min readCurated summary

Toss’s Speed and Quality: Are Commercial Tools Enough? — Tossion

Toss’s QA Platform team built Tossion to replace a rigid commercial test case management system with a platform they could continuously adapt. It unifies test cases, manual and automated results, evidence, history, and release snapshots while preserving a clear record of what was tested at each point in time. The platform later expanded into AI-assisted PR analysis, test case generation, and real-device regression testing, enabling QA processes to evolve at Toss’s speed. ## Why Tossion Was Needed - Previous QA information was scattered across automation results, manual test results, test cases, and decision evidence. - Answering questions such as “How did this test perform last time?” required checking multiple systems. - The commercial TCM could not be modified quickly, and requests for new features often stalled. - Toss needed a platform that could be changed directly as new QA requirements emerged. ## Preserving Test History - Tossion organizes work as: - Project - Suite - Section - Test Case - Test cases continue to change as products evolve, but test runs must preserve historical reality. - When a test run is created, it copies the test case’s assignee, steps, and description instead of merely referencing the current test case. - Status changes create history entries showing who made the decision, when, and against which version. - Closed test runs store snapshots of test cases, comments, and automation results, so reports remain available even if the original test cases are later deleted. - Manually selected test cases override Type or Platform filters. ## Collaborative Test Execution - Test runs progress through `Active → Completed → Closed`. - Assignee-based charts show each person’s remaining work at a glance. - Fields such as Status, Type, Assignee, Version, Platform, RNR, and History are added or removed based on actual usage. - Multiple users can work in the same test run simultaneously: - Active viewers appear as avatars. - Editing locks prevent conflicts. - Locks are automatically released when users leave or disconnect. - Status changes are synchronized without requiring a refresh. - The main benefit is short feedback loops: requested improvements can be built and deployed immediately. ## AI-Assisted Release and PR Analysis - Toss planned to use AI for test case creation, PR analysis, regression automation, and execution. - Tossion analyzes every PR included in a release, separating those with QA labels from those marked as not requiring QA. - The goal is not merely to summarize changes, but to audit whether “no QA needed” classifications are correct. - An agent running on a QA server: - Registers with Tossion. - Polls for work. - Executes the AI already authenticated on the server. - Hundreds of PRs are divided into smaller batches and analyzed in parallel for deeper review. - Results are checked for vague or unusable content, such as: - Missing screens or conditions. - Repeated PR titles. - Raw function names. - Missing reproduction steps, expected results, failure symptoms, or reasoning. - Invalid analyses are retried, and the number of merged PRs is compared with the number of analyzed PRs to detect omissions. - Historical incident data increases risk when a new PR touches files associated with past outages. - Results are uploaded after each batch, allowing interrupted jobs to resume without repeating completed analysis. - The resulting “must-test” list defines the scope of the Sprint test run. ## AI-Generated Test Cases - AI generates test cases for new features, but Tossion controls their placement in the test case tree. - AI returns paths such as `Assets > Account Connection > Select Bank`; Tossion converts them into actual sections, reusing existing sections or creating missing ones. - Reliability is checked in three layers: - AI reviews its own output for missing branches, error cases, and boundary values. - Scripts validate naming, numbering, screen coverage, and requirements coverage. - A separate AI creates an independent test plan based on ISTQB and ISO/IEC 29119 practices. - The plan and generated cases are compared: - Planned but missing cases indicate omissions. - Cases outside the plan indicate unplanned scope. - This catches state-based scenarios that screen-oriented test generation might miss. - Generated cases are uploaded through a portable CLI rather than direct UI integration, reducing dependency on local packages, runtimes, and paths. - Stable cases can later become regression tests. ## Running Regression Tests on Real Devices - A Tossion execution modal specifies: - Device - Build - Test scope - Target test run - Runners connected to Android and iOS physical devices register themselves with Tossion but require administrator approval before receiving work. - Runners report device status every 30 seconds. - Tossion supplies the correct build for installation, ensuring results are tied to a known version. - Users can run the full regression suite or a selected section. - Progress is streamed as scenarios finish, including duration and failure messages. - Results are stored at the step level: - Status - Duration - Error message - Screenshot - Scenario-level video - Automation results can be attached directly to the relevant Sprint test run, making them part of the same record used for manual testing. ## Linking Automation Results to Test Cases - Aggregate reports such as “200 regression tests, 3 failures” do not identify which manual test case rows were covered. - Tossion aims to connect test cases and automation in both directions: - Generate automation code from test cases. - Write automation results back into individual test cases. - This removes the need for QA engineers to manually reconcile separate reports with test case lists. Tossion’s central value is not just test management, but ownership and adaptability. By combining immutable test history, collaborative execution, AI validation, and real-device automation in one extensible platform, Toss’s QA team can adjust its tools and processes as quickly as product requirements change.

Read original(opens in new tab)
toss4 min readCurated summary

The Monorepo Hope Edition: One Year to Bring a Despairing Repo Back to Hope

Toss argues that a monorepo alone does not guarantee a consistent or efficient frontend development experience. The real problem was dependency-version fragmentation across services, which made installations slow, platform changes risky, and upgrades difficult. Toss addressed this by introducing shared dependency “catalogs,” standardizing core libraries while preserving controlled, gradual upgrades. ## Toss’s Frontend Development Environment - More than 100 frontend engineers maintain products inside and outside the Toss app. - Despite the large number of products, services use nearly identical versions of React 19, Next.js 15, TypeScript, bundlers, and linters. - A shared monorepo makes it easier to: - Maintain a consistent development environment. - Share code across services. - Propagate platform-wide changes. - Give users access to features such as React Concurrent Mode and Server Components. ## Problems with an Unmanaged Monorepo - Services used widely different dependency versions, including outdated React and supporting libraries. - This created fragmented developer experiences: - Some services had fast development servers and modern APIs. - Older services were slower and harder to develop. - Dependency installation could take more than a minute even with caching. - Platform teams struggled to test shared libraries across many React and library versions. - Service developers avoided upgrades because compatibility risks and migration costs were high. - Older services consequently became locked into outdated dependencies. ## Why Toss Rejected a Polyrepo Strategy - Splitting the monorepo into separate repositories could reduce the size of each individual project and improve installation times. - However, polyrepos would not solve the main issues: - Development environments would remain fragmented. - Shared-code development and updates would become more expensive. - Differences between services could become even more pronounced. - Toss concluded that improving dependency management within the monorepo was preferable to abandoning it. ## Simplifying the Dependency Tree - The central issue was that services selected different versions of the same core libraries. - Toss identified roughly 10–20 commonly used libraries, including: - React - Component libraries such as TDS - Jotai - TypeScript - ESLint - Standardizing these dependencies could: - Reduce installation time. - Provide a consistent developer experience. - Make platform-library testing more predictable. - Enable automated migration scripts and compatibility layers. - Lower the cost of adopting breaking changes. - In practice, developers usually chose libraries rather than requiring specific versions, making centralized versions practical. ## Dependency Catalogs - Toss defined recommended versions as a shared **Catalog** using pnpm or Yarn workspace configuration. - Services reference catalog-managed dependencies with the `catalog:` protocol instead of specifying independent versions. - Named catalogs can support different release channels, such as: - `stable` - `beta` - Toss initially included essential dependencies such as React, Next.js, TypeScript, TDS, and the Toss App SDK. - Catalog packages had to be tested in representative service environments before release. - New services automatically referenced the latest catalog. - CI detected cases where developers accidentally bypassed catalog versions. - Existing services were migrated collaboratively with their code owners. - Catalog changes were released as new versions and rolled out gradually rather than modifying a shared version in place. - Upgrade scripts and AI Skills reduced the effort required to migrate services. ## Results After Full Adoption - Dependency duplication fell substantially: - `.pnp.cjs` shrank from 96 MB to 15 MB, an approximately 84% reduction. - Development-server startup improved from 26.7 to 20.3 seconds, about 23% faster. - Full dependency installation decreased from 528.4 to 249.9 seconds, about 52% faster. - Developers gained greater confidence that catalog packages had already been tested in real services. - Centralized version control reduced incompatible transitive dependencies, such as one package requiring version 1 while a service used version 2. - Better dependency visibility made large architectural improvements safer, including work involving RSC, TypeScript 7, Rspack, and end-to-end testing. - Services could adopt improved platform packages more consistently and with less upgrade friction. The practical recommendation is to retain the monorepo, but enforce a curated set of shared dependency versions through catalogs, CI checks, staged releases, and automated migration tooling. This combines the sharing benefits of a monorepo with a more predictable and maintainable development environment.

Read original(opens in new tab)
toss4 min readCurated summary

How DS and MLE Work Together

The post explains how Toss Bank improved collaboration between Data Scientists (DS) and ML Engineers (MLE) by progressively formalizing their responsibilities. What began as manually transferring notebooks evolved into standardized Python files and finally into installable model packages built around explicit interfaces. The result was faster deployments, consistent observability, and clearer ownership, while AI-generated code introduced a new need to standardize coding style as well. ## Problems with Notebook-Based Handoffs Initially, DS built models and inference code in Jupyter notebooks, then handed them to MLE. - MLE had to recreate the serving code from scratch. - Dependencies, configuration files, and source code were often missing or difficult to reproduce. - Preprocessing logic could be interpreted differently by DS and MLE. - “It works in the notebook” did not guarantee that it would work in production. - As the number of models increased, communication and rework grew rapidly. This approach separated people, not code, so the division of responsibility remained unclear. ## Phase 1: Separating Logic into `.py` Files The team next moved the collaboration boundary from people to files. - DS kept notebooks for experimentation and training. - Core inference logic was extracted into `.py` files. - MLE reviewed these files and validated them through CI. - DS’s intended model behavior was preserved more reliably. - Communication costs decreased. However, the files lacked a standardized structure. - Models used inconsistent function names such as `predict()`, `run()`, and `inference()`. - Code still required modifications when moved into the serving environment. - Global configuration changes in one model could affect other models sharing the same process. - Logging, metrics, and error handling could not be applied consistently across models. ## Phase 2: Defining an Interface Contract The team ultimately standardized the boundary through the `commons-ml-model` package. - A base abstraction defines a common model structure. - DS implements three methods: - `pre_process` - `inference` - `post_process` - The base class handles shared concerns such as: - Logging - Metrics - Tracing - Timing and request tracking - DS packages the implementation as a reusable library. - MLE installs the package with `pip install` and deploys it without rewriting the model. This turns the division of work into a code-level contract. DS focuses on model behavior, while MLE owns serving infrastructure and operational concerns. Updating the base abstraction can also add observability features to every model at once. ## Monorepo Collaboration The team manages the abstraction package and individual model packages in a single monorepo using `uv` workspaces. - Changes to the abstraction and affected models can be reviewed in one pull request. - DS and MLE review the same code in the same repository. - CI, release, and versioning policies are centralized. - Switching from Poetry to `uv` improved build speed by three to five times. The tradeoff is that changes to shared packages can affect many models, and the repository becomes heavier as more packages accumulate. ## Standardizing AI-Generated Code AI-assisted development created a separate collaboration problem: consistent structure did not guarantee consistent coding style. The team introduced `pfmls-stylepack` to encode team conventions for AI tools. - Naming conventions are standardized. - Exception-handling patterns are prescribed. - Rules determine when to use enums instead of hard-coded strings. - Hooks apply conventions while code is being generated. - AI-generated code can explain when a particular rule influenced its implementation. The team therefore distinguishes between: - **Structural consistency:** interfaces define what each role implements. - **Style consistency:** shared rules define how code should be written. Both are necessary for smooth reviews. ## Lessons from the Evolution - The hardest decision is choosing the right collaboration boundary: excessive structure limits flexibility, while insufficient structure recreates inconsistency. - Documentation and early DS–MLE pairing reduce the learning curve for the package-based workflow. - Shared libraries are a double-edged sword: one change can cause broad impact, but one fix can also benefit every model. - In the age of AI-generated code, teams must standardize not only responsibilities and interfaces but also implementation style. The practical recommendation is to make collaboration contracts executable: define stable interfaces, package model code for reuse, centralize shared serving behavior, and enforce coding conventions automatically.

Read original(opens in new tab)
toss4 min readCurated summary

LLMs Are Smart, So Why Don’t They Know How Our Company Works?

LLMs handle public knowledge well but struggle with company-specific questions because relevant evidence is scattered across documents, code, meetings, and chat—and may be outdated or contradictory. The post argues that this is not merely a search problem: organizations need a shared layer for managing trustworthy context. Topic addresses this by extracting source-aware units, linking concepts and relationships, and verifying their freshness, consistency, and evidentiary support. ## Why Search Alone Is Not Enough - Search retrieves relevant text but cannot determine whether it is current, authoritative, or consistent with other sources. - A retry-policy example might contain: - Documentation saying requests fail immediately - A meeting discussion proposing three retries - Code currently implementing two retries - Agents must still determine: - Whether the meeting produced a final decision - Which source is newer - Whether the code reflects an intentional change or an unfinished implementation - Whether different sources describe the same behavior - Topic provides a shared context layer so humans and LLMs use the same sources, relationships, freshness information, and conflict states. ## Six Dimensions of Trust Rather than compressing trust into one score, Topic evaluates six separate dimensions: - **Granularity:** Whether the context is a meaningful, independently manageable unit - **Faithfulness:** Whether the source actually supports the claim - **Staleness:** Whether the evidence remains valid - **Canonicality:** Whether different names refer to the same entity - **Consistency:** Whether sources are compatible - **Coverage:** Whether important evidence or perspectives are missing Different checks use different methods: rules and hashes for deterministic validation, LLMs for semantic interpretation, and humans for ambiguous or high-impact decisions. ## Ingesting Documents, Chat, and Code Topic normalizes information into a common `ContentUnit` containing source type, unit type, original URI, content, hashes, timestamps, and source-specific metadata. It uses different boundaries for each source rather than splitting everything into fixed-size text chunks. ### Structured Document Sections - Markdown documents are divided by heading hierarchy. - Parent headings are preserved to retain context. - Long sections are split only when necessary. - URLs, document paths, and creation or modification times remain attached to the unit. ### Conversation Threads - Entire messenger threads are treated as the semantic unit, not individual messages. - Summaries preserve: - Technical identifiers such as function names and file paths - Questions, alternatives, and final outcomes - Decisions versus unresolved issues - The system avoids inventing consensus and ignores threads containing only casual conversation. ### Code Symbols and Semantic Cards - Parsers extract functions, classes, file paths, line ranges, imports, and other symbols without using an LLM. - Multiple symbols are then grouped into **code semantic cards** describing business behavior. - Cards retain domain terms, code identifiers, source spans, and the relevant commit SHA. - LLM-generated cards are checked against actual files, line ranges, supporting spans, and duplicate-card patterns. - Cards are an intermediate layer for connecting code to business concepts, not a replacement for the code itself. ## Extracting Concepts and Relationships - Topic extracts concept candidates and supporting evidence from each content unit. - It preserves the relationship between every concept and its original evidence. - Similar names are not automatically merged merely because they appear close in meaning. - Concepts can be consolidated into canonical entities only when sufficient evidence exists. ### Human Review for Ambiguous Terminology - Normalization and embeddings can identify obvious duplicates. - Internal abbreviations and aliases may require organizational knowledge. - Topic creates synonym proposals with their supporting context. - Humans approve or reject ambiguous aliases; rejected proposals are remembered to prevent repeated suggestions. ### Typed Document–Code Relationships Topic distinguishes among: - `supported_by`: code behavior supports the document’s claim - `contradicted_by`: code behavior conflicts with the document - `mentions`: both refer to the same area, but support or contradiction is unconfirmed Embedding search first narrows possible matches, after which semantic verification is performed. Low-confidence or failed checks do not create relationships; an absent relationship means “not yet verified,” not necessarily “unrelated.” ## Incremental Verification and Change Detection - Stable identifiers and content hashes allow unchanged units to reuse previous extraction and relationship results. - Deleted sources trigger cleanup of dependent relationships. - Code anchors store the validating commit and span hash. - If an anchor disappears, it is marked orphaned. - If the span remains unchanged, semantic verification can be skipped. - If the span changes, faithfulness must be checked again. - Rule-based checks happen before LLM calls, reducing cost and limiting nondeterministic reasoning to cases that require it. Topic’s practical recommendation is to treat trustworthy internal context as a managed system rather than a search result. Preserve source structure, keep evidence attached to every claim, use automation for deterministic work, and route ambiguous organizational judgments to people.

Read original(opens in new tab)
toss5 min readCurated summary

Building Toss’s Device Farm

Nebula is Toss’s centralized device farm, turning real-device testing into a simple API call instead of a team-specific infrastructure project. It grew from 15 devices and one developer into a 24/7 platform with more than 100 devices, shared across the company. The team replaced Appium with a faster, stateless custom driver and invested heavily in real-time streaming, reliability, security, and compliance. ## From Team-Owned Farms to a Central Platform - Before Nebula, teams managed their own small farms using MacBooks or Mac minis. - Each team repeatedly solved the same problems: - Appium setup and maintenance - Device detection and recovery - OS-version compatibility - USB and hardware failures - Security and compliance - Most teams could manage only five to ten devices, and resources remained isolated. - Nebula centralized device operations so product teams could focus on testing rather than infrastructure. ## One API for Real Devices Nebula’s core goal is to let anyone control a physical device from anywhere through a single API. - Clients reserve a device and invoke actions such as clicks or text input. - Users do not need to know which host owns the device or configure ADB, Xcode, cables, or test servers. - The same API supports frontend tools, SDKs, CLIs, direct API clients, and automated systems. ## Four-Layer Architecture - **Clients:** Web interfaces, SDKs, CLIs, and direct API calls. - **Server:** Orchestrates device discovery, allocation, and test execution. - Kafka distributes execution requests. - Multiple runners consume work horizontally as demand grows. - `occupy`, `assign`, and `release` provide distributed locking so tests cannot interfere with one another. - **Agents:** Run on Android/Linux and iOS/Mac hosts, discover local devices, and forward server requests. - **Devices:** Each device has a controller server and runner that execute actions on the physical phone. ## Why Nebula Replaced Appium ### Faster execution - Nebula’s click and input operations were more than ten times faster than Appium in common cases. - Much of Appium’s latency comes from `waitForIdle`, which waits for the screen to stabilize before acting. - Disabling that wait narrows the difference to roughly two or three times. - Appium prioritizes robustness against changing screens, while Nebula prioritizes immediate interaction for live remote control. ### Stateless operation - Appium requires sessions that can take 15–40 seconds to initialize. - Session startup becomes increasingly fragile and difficult to manage at scale. - Nebula keeps device controllers pre-warmed and accepts stateless HTTP requests, eliminating session setup and reducing failure points. ### Company-specific customization Because Nebula owns its driver specification, it can provide: - A custom IME that preserves Korean and emoji input. - Toss-specific signal triggers. - App Center integration for installing pre-release builds. - Built-in enforcement of internal security policies. The driver uses Android ADB and UiAutomation, and Swift/XCTest on iOS. Its OpenAPI specification generates Go and TypeScript interfaces. ## Real-Time Interaction and Screen Mirroring Nebula needed users to watch and control remote devices simultaneously, not merely replay predefined test steps. ### Android - Instead of using `scrcpy` directly, the team adapted its encoding approach. - Android’s `SurfaceControl` creates a virtual display. - `MediaCodec` encodes the output as H.264. - A broadcaster distributes the stream to multiple browser viewers. ### iOS - iOS screen capture is constrained by USB access and cannot expose the display as freely as Android. - Existing approaches such as QVH and Appium MJPEG did not support simultaneous viewing and interaction. - Nebula developed a capture path inspired by QuickTime’s iOS capture mechanism without exclusively claiming the USB connection. - Both platforms now use H.264 streaming and broadcasting, allowing the entire device farm to be viewed in a browser. ## Security and Compliance - Centralization made it possible to apply consistent security requirements across every device. - The team worked with Toss’s security organization to define mobile-device compliance standards. - Policies are enforced at the platform and driver levels rather than relying on individual developers. - Teams can therefore test on devices that already meet the company’s security requirements. ## Operating Hundreds of Devices Nebula must keep hardware and software running continuously. - **Hardware operations** - USB cables, hubs, and power delivery had to be tested and designed for large-scale use. - Physical failures still require human intervention. - Redundancy is being introduced to reduce service interruptions. - **Software operations** - Controllers and mirroring processes are orchestrated across Mac mini and Linux hosts. - Dead processes are automatically recovered. - Server, agent, controller, and mirroring deployments are performed without interrupting user tests. - Monitoring and observability cover devices, processes, and server performance. ## An Internal Ecosystem Built on the API Nebula has evolved from a device provider into shared testing infrastructure. - Web console for no-code interaction and test-step creation. - SDKs for writing E2E tests. - CLI support for terminals, CI/CD, and local AI agents. - Automated log verification during device interaction. - AI agents that plan and execute tests dynamically. - Direct API access for teams with specialized needs. Reported benefits include faster Appium migration, lower barriers to regression testing, and reducing manual verification from 30–40 minutes to under 10 minutes. Nebula’s main lesson is that a stable, simple API can become the foundation for a much broader testing ecosystem. Centralizing device infrastructure, replacing unsuitable abstractions, and treating real-time operation, compliance, and reliability as first-class requirements enabled Toss to scale physical-device testing across the company.

Read original(opens in new tab)
toss4 min readCurated summary

While Others Test Toss, We Build the Way to Test.

Every week, Toss releases a new version containing roughly 300–400 code changes, making quality assurance essential to protecting users from broken critical features. The QA Platform team combines smoke tests, regression testing, release monitoring, automation, and AI-assisted tools to make releases reliable and efficient. Its central lesson is that teams often want QA work handled responsibly—not merely more tools to operate themselves—so the team is shifting toward directly owning more of the testing process. ## Weekly Release Quality - QA begins when a Release Candidate is available. - **Toss Doctor** runs smoke tests covering core flows such as login through account deletion. - A pull-request analyzer identifies changed areas, potential impact, bug risk, and testing priorities. - **Toss Checker** performs regression testing to ensure new changes have not damaged stable functionality. - After release, the team monitors crash metrics and decides whether an immediate hotfix is necessary or whether a safer fix can wait for the next release. - Custom dashboards track crashes and hotfixes, including causes and prevention measures. - The team also supports product groups starting QA, improves internal tools, and helps establish organization-wide QA processes. ## Defining Toss’s Quality Standard The team’s goal is to go beyond basic testing and establish consistent quality standards across Toss. - **Reliable releases every time:** Quality must remain dependable week after week, not just during individual successful launches. - **High-quality testing:** The focus is on finding defects that could become real incidents, rather than simply increasing test volume. - **Efficient quality assurance:** Manual repetition alone cannot keep pace with the company’s release speed, so automation and sustainable workflows are necessary. - AI is intended to handle suitable decisions and repetitive work, allowing people to focus on areas requiring human judgment. ## Building the Tossion Platform Commercial tools did not provide enough flexibility for Toss’s release pace and evolving AI experiments, so the team built its own platform, **Tossion**. - Tossion replaced TestRail and brought test-case creation, execution, and result tracking into one system. - Multiple bots were consolidated into **Toss Butler**, optimized for the team’s workflow. - **PRCheck** analyzes pull requests and highlights where testers should focus. - **tcgen** uses PRDs, design documents, and surrounding context to generate initial test cases for review. - An automation testing platform displays manual and automated test results together. - **Crash Trend** tracks crash patterns using metrics tailored to Toss. - A hotfix dashboard categorizes causes and records measures intended to prevent recurrence. - These tools are connected by one objective: handling the growing volume of weekly changes more effectively. ## Learning What Teams Really Need The team initially assumed that making test-case creation easier would encourage more people to test. However, tcgen received less adoption than expected. - Users did not necessarily want better tools for doing QA themselves. - What they really wanted was for someone to perform testing quickly and accurately while taking responsibility for its quality. - Providing a tool could feel less like removing work and more like assigning a new task. - As a result, the team shifted toward directly handling more testing and pursuing tenfold efficiency without transferring responsibility to product teams. ## Staying Flexible as AI Evolves AI has solved many problems but has also made long-term planning difficult. - Initial hypotheses may be only partly correct, as the tcgen experience demonstrated. - Tools and methods can become outdated rapidly as AI capabilities change. - The team discarded an API testing tool, **API Labs**, after only eight hours when it proved misaligned with its goals. - Tossion, Toss Doctor, Toss Checker, and internal skills are designed with replacement in mind rather than as permanent, finished systems. - AI can accelerate tool creation, but people must still define what quality means, establish priorities, and decide what standards must be preserved. The QA Platform team’s ongoing approach is to build adaptable systems, learn from actual usage, and remain willing to replace anything that no longer serves its purpose. Its upcoming work will explore Tossion, the release-gate tools, regression automation, and intelligent AI bots in greater detail.

Read original(opens in new tab)
toss3 min readCurated summary

es-toolkit: How a Small Internal Library Became a Global Project

es-toolkit began at Toss as a modern alternative to lodash, addressing its outdated architecture, legacy-browser code, lack of native ECMAScript Module support, and inefficient implementations. By removing unnecessary logic and relying on modern browser APIs, es-toolkit achieved 2–10× performance improvements and, in some cases, reduced bundle sizes by more than 30×. Its open-source momentum attracted global contributors, eventually helping it become widely adopted. ## The Beginning of es-toolkit - Toss developers needed dependable utilities such as `throttle`, `debounce`, and `uniq`. - Although lodash was widely used, it had several limitations: - Outdated code structure and implementations. - Defensive logic for legacy browsers such as Internet Explorer. - Little use of native APIs like `Array#map`. - No ECMAScript Modules, making tree-shaking difficult. - `lodash-es` added ESM support but retained much of lodash’s older and inefficient implementation. - Toss’s internal `@toss/utils` library required significant effort to maintain and handle edge cases. - es-toolkit was created to provide a modern, efficient utility library for current web development. - Initial results showed: - At least 2× and sometimes over 10× faster execution. - Bundle-size reductions of more than 30× in some cases. ## Open-Source Adoption and Community Growth - Toss initially announced es-toolkit through its frontend social media channels. - Developers contributed missing functions, bug fixes, and performance improvements. - After gaining attention in Korea, the project was shared on Reddit and received over 100 upvotes and tens of thousands of repository visitors. - International discussions led to coverage in blogs and newsletters. - Community members created bundler plugins and migrated dependencies in established libraries from lodash to es-toolkit. ## From Contributor to Toss Developer - Dayong Lee discovered es-toolkit through Toss’s announcement and began contributing despite not being a Toss employee. - Starting with small pull requests, he gradually became the project’s second-largest contributor. - Code reviews helped him develop stronger skills in: - JavaScript language features. - API and interface design. - Open-source collaboration. - His involvement with es-toolkit eventually contributed to his joining Toss Bank. ## Making Migration Easier with `es-toolkit/compat` - Although the library was becoming more complete, adoption remained slow because many projects depended heavily on older utility libraries. - Migrating individual lodash functions across a large codebase would be tedious and risky. - es-toolkit therefore introduced `es-toolkit/compat`, a drop-in replacement designed to preserve lodash’s interfaces and behavior while modernizing its internal implementation. - This compatibility layer reduced migration effort and allowed projects to gain performance improvements by changing imports rather than rewriting utility usage. - The layer was particularly important because es-toolkit’s streamlined behavior could otherwise differ from lodash in edge cases and cause runtime errors. es-toolkit’s story demonstrates how a focused modernization effort can replace entrenched legacy dependencies. Providing both a faster native-style library and a compatibility layer made adoption more practical while enabling broad open-source participation.

Read original(opens in new tab)
toss4 min readCurated summary

5. Technical Writer, A Decision to Disappear

Toss’s technical writing team argues that documentation is essential context for AI, but manually maintaining thousands of documents is impossible with only three technical writers serving roughly 4,000 people. Their solution is to automate the technical writer’s work by teaching AI the team’s implicit standards and embedding those standards into reusable Skills. The initial system supported document creation and review, but adoption remained low because users still had to install, invoke, and supply information to the AI manually. ## Why Toss Wanted to Automate Technical Writing - Documentation gives AI the organizational context it needs to work effectively. - Toss has approximately 4,000 employees but only three technical writers. - Reviewing documents individually does not scale, especially in a fast-moving organization where features change or disappear before documentation is complete. - The team’s goal to “eliminate technical writers” means transferring routine writing and editing work to AI, not abandoning documentation quality. ## Teaching AI Technical Writing Principles - The team analyzed existing technical writing review comments to identify how writers evaluate documents. - Existing writing guidelines were converted into explicit principles, such as: - Focus each page on one subject. - Present value before implementation details. - Each principle was supplemented with incorrect and correct examples so AI would understand the intent rather than apply rules mechanically. - Common document types were converted into templates. - Templates include: - Instructions explaining what each section should contain. - `(required)` markers for information that must not be omitted. - For example, an ADR template requires an overview, context, considered alternatives, decision, and rationale, while also allowing optional sections such as expected outcomes and related references. ## Skill for Writing New Documents The document-writing Skill reproduces the four stages a technical writer typically follows: - **Clarify the purpose:** Ask about the project, document goal, audience, level of detail, source materials, and expected structure. - **Design the structure:** Use a standard structure or select a relevant template, such as onboarding guides, meeting notes, or PRDs. - **Write the content:** Apply technical writing and MDX rules while using templates as structural guidance. - **Review the draft:** Check for awkward wording, missing information, and other quality issues. The Skill also distinguishes between required and optional template sections: - Required sections remain in the draft even when source information is incomplete. - Missing information is represented with questions or comments rather than guesses. - Optional sections are omitted when there is not enough source material to complete them. ## Skill for Reviewing and Improving Documents - The team initially converted past review comments into a checklist. - This produced poor results: AI overlooked important issues while generating unnecessary comments. - The problem was that good writing follows relatively stable principles, whereas bad writing can fail in many different ways. - The revised workflow lets AI independently: - Read the technical writing principles. - Analyze the document. - Identify violations. - Explain the issue and suggest revised wording. - Perform a final checklist-based review. - Previous review comments are now used as examples of how principles apply, rather than as a rigid list of required findings. - One example principle requires descriptions of parameters or properties to include their meaning, accepted format, and usage example—not merely a type such as `date: string`. ## Low Adoption Revealed a Usability Problem - Despite creating both Skills, the team found that few employees used them. - Users still had to: - Download and install the Skill manually. - Understand CLI-based setup, which was unfamiliar to non-developers. - Remember to invoke the Skill whenever they began writing documentation. - Find and provide all relevant source materials themselves. - The team concluded that improving the AI’s capabilities was not enough; the workflow also had to reduce the effort required from users. The main lesson is that AI-based documentation succeeds only when organizational knowledge, writing principles, and templates are encoded clearly—and when the system is integrated into everyday work so employees do not have to remember to use it or prepare everything manually.

Read original(opens in new tab)
toss4 min readCurated summary

6. Beyond Tools: Standards and Responsibility

Toss’s commerce domain found that reliable organizational knowledge cannot be created by writing more documents or adding automation alone. Sustainable knowledge management requires clear standards for what should be documented, who owns it, how it is maintained, and which sources can be trusted. The proposed solution combines AI-assisted documentation with domain-level responsibility and company-wide governance. ## The Limits of Writing Alone - A commerce wiki consolidated terminology, onboarding material, code references, and policy documents. - This reduced confusion over terms such as “seller” and “store” and gave teams a shared starting point. - However, product and policy changes happened faster than one Technical Writer could document them. - Important knowledge also appeared in policy changes, temporary experiments, and chat discussions that were difficult to track manually. ## Why Culture and Participation Were Not Enough - The team promoted documentation through: - A weekly “Commerce Wiki News” newsletter - A policy-question channel and bot - AI documentation workshops - A documentation guild - These efforts increased requests, wiki usage, and adoption of official terminology. - Participation rarely continued beyond an individual’s first document because documentation was not part of normal work priorities. - Writers lacked guidance on: - What information to preserve - How much detail to include - Which audience to target - How to verify whether a document was correct - Documentation became sustainable only when it was treated as a team responsibility embedded in existing workflows. ## AI Automation Reveals the Governance Problem - AI now creates draft documents nightly from two signals: - Product deployment and policy-change announcements - Questions that the commerce Q&A bot cannot answer - AI gathers supporting context and produces drafts, while humans verify the evidence and approve them. - This removes the burden of starting documents from a blank page. - Automation also exposed new problems: - Duplicate or overlapping documents - Unclear authoritative sources - Outdated policies being used in bot answers - Difficulty distinguishing current policies from completed experiments - Automation can collect and draft information, but it cannot decide who owns a policy or whether a document should still be trusted. ## Knowledge Standards and Governance - The focus shifted from “How do we create more documents?” to “How do we create knowledge people can trust?” - Toss’s knowledge-management standards state that teams should: - Preserve recurring questions, important decisions, and information needed by newcomers. - Organize knowledge so both people and AI can find it. - Connect documents to work tools such as Q&A bots and GitHub. - Assign owners and review cycles to keep information accurate and current. - Possible classification systems include: - **Technical layers** for teams with clear data or system flows - **Service domains** for teams responsible for multiple service areas - **Functional units** for systems with distinct feature boundaries - Information becomes organizational knowledge only when it helps people understand situations and make better decisions, with sufficient context and verification. ## The Role of the Knowledge Committee - The Knowledge Committee defines and maintains company-wide documentation standards and resolves conflicts between organizational rules. - Unlike a voluntary guild, it has designated members with decision-making authority. - Governance operates at two levels: - The Technical Writing Chapter manages shared standards for sources, ownership, document status, and lifecycle. - Individual domains decide how those standards apply locally, including ownership, update schedules, and retirement rules. - This balance prevents both inconsistent practices across teams and overly centralized rules that ignore local realities. - For example, commerce teams may need separate handling for permanent deployments and temporary experiments so expired policies do not remain authoritative. The practical recommendation is to treat knowledge management as an operating system for the organization, not a documentation project. AI can reduce the effort of capturing knowledge, but clear ownership, review processes, lifecycle rules, and governance are necessary to keep that knowledge reliable and useful.

Read original(opens in new tab)
toss3 min readCurated summary

Why Does Our Team’s Documentation Fail? (2)

Documentation succeeds not through individual resolve, but through centralized knowledge, clear purpose, and systems that reduce the fear of being wrong. Interviews across a commerce domain and a server-development chapter show that documentation strategies must match an organization’s existing maturity, audience, and work patterns. AI lowers the cost of writing and sharing knowledge, while also requiring more deliberate document organization. ## Lessons from Early Attempts - The commerce wiki was initially designed as a self-service platform supported by workshops and guilds. - Workshops could encourage a first contribution, but sustaining second, third, and later contributions was difficult. - In the Ads domain, documentation was already strong, so the better approach was to respect existing conventions and help people locate knowledge rather than create another system. - Organizations with little documentation need to build foundational knowledge; organizations with mature documentation need better discovery and maintenance. ## Reducing the Fear of Asking and Writing - Developers often avoid asking questions because doing so publicly reveals what they do not know. - They may also hesitate to publish documentation because they fear their knowledge could be inaccurate. - The team addresses this through: - **“Lee’s Development Consultation Week,”** which normalizes questions and encourages teammates to answer questions Lee cannot address. - **A daily knowledge bot, “Ha,”** which shares short server-development tips automatically. - Correcting or adding to an existing shared post feels easier than writing a complete document from scratch. ## How AI Has Changed Documentation - AI makes it faster to create initial drafts and distribute knowledge through chatbots. - It also enables measurement of knowledge flow, including: - The number of questions asked. - Whether teammates provide answers. - The quality and content of those answers. - The number of new documents and week-over-week growth. - These metrics reveal knowledge gaps and recurring questions without manually reviewing every channel. - AI also creates a need for more detailed internal context than human readers typically require. - Commerce therefore separates: - Central, human-friendly documentation managed by technical writers. - Team-repository documentation containing detailed, team-specific context useful to AI but unnecessary for everyone else. ## Shared Principles and Organizational Differences - Both domains and chapters should centralize knowledge and avoid spreading it across too many channels. - Domains typically: - Connect documentation to products and code. - Change rapidly. - Serve a broad and varied audience. - Chapters typically: - Document conventions, working methods, and professional knowledge. - Change more slowly. - Focus on productivity and capability development. - Have a clearer audience, such as a specific role or discipline. - Domain documentation should be understandable even to non-developers, since developers may also lack context outside their specialties. - Separating guides, capability-based policies, glossaries, and metrics helps different readers find documents suited to their needs. ## Where to Begin - First diagnose the organization’s current documentation maturity by asking what people do when they get stuck: - **Ask coworkers or search chat:** foundational documentation is largely missing. - **Search documents:** assess whether information is easy to find; fill gaps if searches fail. - **Ask an AI or bot:** evaluate whether answers are accurate and whether the underlying documents are complete, current, centralized, and sufficiently contextualized. - Define the specific problem driving documentation, rather than starting with a vague goal. - Begin with a focused need, such as creating a glossary for inconsistent terminology or building references for sharing knowledge with other teams. The practical recommendation is to centralize knowledge, identify the organization’s biggest documentation gap, and build a low-friction system where people can contribute, correct, and consume information without relying solely on personal effort.

Read original(opens in new tab)
toss3 min readCurated summary

es-toolkit: How an Internal Little Library Became a Global Library

es-toolkit began as Toss’s effort to create a modern alternative to lodash, removing legacy code and optimizing for current JavaScript environments. By focusing on common use cases, it achieved 2–10× faster performance and reductions in bundle size of more than 30×. Community adoption, compatibility tooling, and contributions to major projects eventually pushed it beyond 20 million weekly npm downloads. ## Why es-toolkit Was Created - Developers frequently needed utilities such as `throttle`, `debounce`, and `uniq`, but existing options had drawbacks. - lodash contained legacy implementations, Internet Explorer workarounds, and limited ECMAScript Modules support. - Even `lodash-es` mainly added ESM support without modernizing the underlying code. - Toss had maintained its own `@toss/utils`, but handling utility-function edge cases internally was burdensome. - es-toolkit’s goal was to remove unnecessary logic, improve performance, and produce smaller bundles for modern web applications. ## Performance and Bundle-Size Improvements - Reimplementing core lodash-style functions produced: - At least 2× faster execution for some functions. - More than 10× faster execution for others. - Using modern built-ins such as `Array#map` eliminated compatibility code. - Bundle sizes were reduced by more than 30× in some cases. - The project was designed around the most common use cases rather than every historical edge case supported by lodash. ## Growth Through the Open-Source Community - The first release was shared through Toss’s frontend social channels and quickly attracted users and contributors. - Contributors added missing functions, fixed bugs, and optimized implementations. - After promotion on international developer communities, the project received more than 100 recommendations and tens of thousands of repository visitors. - Blogs and newsletters helped extend its reach. - Community members created migration plugins and independently replaced lodash dependencies in other libraries. ## From Contributor to Maintainer - Toss Bank developer Dayong first joined as an external contributor, submitting small pull requests. - Reviewing and designing interfaces for es-toolkit provided valuable experience with JavaScript and API design. - Continued contributions eventually made her the project’s second-largest contributor and helped lead to her joining Toss Bank. - The project also demonstrated how an open-source initiative can connect contributors across companies and countries. ## Lowering the Migration Barrier with `es-toolkit/compat` - Adoption was initially slow because applications often imported many lodash functions throughout their codebases. - Replacing every import manually would make migration expensive and risky. - es-toolkit’s standard implementations also differed from lodash in some edge cases. - `es-toolkit/compat` was introduced as a drop-in replacement: - It preserves lodash-compatible interfaces and behavior as much as possible. - It modernizes the internal implementations. - Projects can gain performance and bundle-size benefits with minimal code changes. - This helped major projects such as Storybook, Mermaid, Yarn Berry, and Recharts adopt es-toolkit. ## Future Direction - es-toolkit plans to help more JavaScript libraries reduce their bundle sizes and improve efficiency. - It aims to add modern utilities, including: - `filter`-style functions for `Map` and `Set`. - Promise-based helpers such as `delay`. - Server-oriented utilities for Node.js, Deno, and Bun. - New functions such as `exec` are intended to provide essential functionality with smaller implementations than competing libraries. - The project plans to maintain its core principle: optimize for more than 80% of common use cases while remaining small, fast, and high quality. es-toolkit’s success shows that a focused, modern implementation can replace widely used legacy utilities when it combines measurable technical benefits with strong migration support and active community participation.

Read original(opens in new tab)
toss3 min readCurated summary

Why Does Our Team’s Documentation Fail? (1)

Documentation often fails not because people lack motivation, but because it depends on individual initiative and lacks clear standards. Interviews with a commerce domain and a server chapter showed that teams struggle to know what to document, how much detail to include, and whether their knowledge is accurate. Both organizations found that consolidating scattered knowledge into a shared system is the essential first step. ## Documentation in Domains and Chapters - **Domains** bring together developers, product owners, and designers around a business area such as commerce or advertising. - Their documentation focuses on product-related knowledge, including policies, terminology, and specifications. - **Chapters** group people with the same profession, such as server or frontend engineers. - Their documentation focuses on shared technical knowledge, conventions, and tools. - Dongjin works on consolidating internal knowledge across commerce and advertising domains, while Hyebin develops the company-wide documentation system “Todoc” and runs a documentation guild in the server chapter. ## Different Starting Points - The commerce domain already had strong awareness of documentation needs. - Members specifically requested terminology guides, policy documentation, experiment records, and API references. - Although writing standards were not clearly defined, people understood which documents would help their daily work. - The server chapter was initially more hesitant. - Members had worked without documentation and had not experienced its benefits directly. - An AI chatbot gave poor answers because its source documents were incomplete or disorganized. - Improving the underlying documents gradually made the chatbot more useful, helping members recognize the value of shared knowledge. ## Interviews Revealed the Real Obstacles - Dongjin interviewed developers to identify knowledge gaps and determine what information should be recorded. - The interviews clarified the organization’s needs, even though solving those needs required additional work. - Hyebin initially reviewed onboarding documents very thoroughly and repeatedly reminded people to complete them. - Interviews showed that contributors generally appreciated external review because it improved document quality. - The main problem was not a lack of motivation, but uncertainty: - What knowledge should be included? - How much detail is appropriate? - Is the information accurate enough to share? - These findings shifted the focus from persuading people to write toward making documentation easier and safer to produce. ## Problems Caused by Missing Documentation - In a domain, scattered policies create collaboration bottlenecks. - A team modifying a feature may first have to search for the policy owned by another team. - Newcomers struggle to understand what they do not know, creating prolonged “unknown unknowns.” - In a technical chapter, engineers often need to reconstruct the history behind unusual code. - They search old chat threads, try multiple keywords, or contact the original author. - More time may be spent assessing context and risk than implementing the change itself. - Useful knowledge often remains private. - Engineers may assume everyone already knows it or worry that it is too trivial to share. - As a result, people repeatedly solve the same problems independently, reducing overall productivity. ## Why Documentation Does Not Continue - Documentation benefits the future, while current work usually feels more urgent. - It is often treated as secondary work that requires a deliberate decision to begin. - Authors may also feel responsible for maintaining documents indefinitely. - Without documentation embedded in normal workflows, every update depends on personal willpower. - AI tools can reduce the effort of drafting and maintaining documents, but unclear standards and fear of being wrong remain significant barriers. Both organizations reached the same starting point: gather scattered knowledge in one accessible place, then integrate writing, review, and updates into everyday work rather than relying on individual motivation.

Read original(opens in new tab)
toss3 min readCurated summary

Creating a Role That Never Existed in the World

Technical Writing at Toss has evolved from producing documents to designing organizational knowledge systems. The core argument is that code captures outcomes but not the context, decisions, and history behind them—information that both employees and AI need. Toss’s Technical Writing Chapter therefore aims to make knowledge discoverable, structured, and increasingly self-sustaining, with the long-term goal of making the chapter unnecessary. ### Why Code Alone Is Not a Sufficient Source of Truth - Code records what a system does, but rarely explains: - Why it was designed that way - Which alternatives were considered - What organizational history shaped the decision - Employees often reconstruct context from colleagues’ memories or years-old messenger threads. - AI faces the same problem: it understands general knowledge but lacks an organization’s internal context. - A true Single Source of Truth requires both the code and the surrounding knowledge that explains it. ### From Writing Documents to Bringing Knowledge to People - Early work focused on creating onboarding documentation for the frontend chapter. - The team recognized that well-written documents are ineffective if people do not actively read or find them. - Toss created “Parkssi,” a chatbot integrated into messaging tools and IDEs: - Users ask questions conversationally. - Answers are based on existing documents. - Sources are provided for verification. - Instead of requiring employees to search for documents, the knowledge reaches them where they work. - Teams that previously ignored documentation began requesting similar systems to reduce repetitive questions and capture implicit knowledge. ### From Documents to Knowledge Systems - A knowledge system collects scattered information from code, conversations, deployments, and other sources. - It structures that information so both humans and AI can understand and use it through questions and automation. - Properly designed systems: - Increase productivity across the organization - Reduce communication costs as the company grows - Help employees adapt quickly and consistently - Toss defines knowledge as verified information that helps people understand situations, make better decisions, and act within a specific context. ### The Four Responsibilities of Toss’s Technical Writing Chapter - **Build products:** The chapter develops and operates “Todok,” an internal knowledge-management platform. - **Lead organizational documentation:** TWs work directly with teams to collect and organize knowledge according to each group’s needs. - **Automate Technical Writing:** AI workflows and automation help employees create and review documentation with consistent quality. - **Shape documentation culture:** The chapter runs company-wide sessions, documentation guilds, and knowledge committees focused on making knowledge easier for AI and people to use. ### A Broader Definition of the Technical Writer - Although the job title remains “Technical Writer,” the role now resembles a knowledge-infrastructure designer. - The role expanded by following organizational problems rather than staying within a fixed professional boundary. - The chapter’s ultimate goal is for teams to create and manage knowledge independently, eliminating the need for a dedicated TW chapter. - The series will explore Toss’s knowledge product, failed documentation approaches, automation of TW work, and the path toward self-sufficient organizations. Technical writers can create greater value by designing systems that make knowledge continuously available—not merely by writing more documents. As AI reshapes every profession, expanding a role around the problems it must solve is presented as an opportunity for any discipline.

Read original(opens in new tab)
toss5 min readCurated summary

Spark Connect on Kubernetes #1: Building a Robust Spark Connect

Toss Securities operates Spark Connect as a production service on Kubernetes so analysts and engineers can use Spark without complex setup. Spark Connect replaces per-application Drivers with long-running servers, making clients lighter and sessions faster, but it also introduces shared-failure and resource-contention problems. The post argues that production reliability requires both reducing server-wide failure triggers and distributing sessions across multiple replicas. ## How Classic Spark Works - Spark consists of: - A **Driver**, which plans jobs, schedules tasks, and collects results. - **Executors**, which perform the distributed computations. - In Classic Spark: - **Client mode** runs the Driver inside the client process. - **Cluster mode** launches the Driver in the cluster for each submitted application. - Both modes assume that one application has one Driver and one workload. - Clients also need Spark libraries, JVM support, and configuration. ## What Spark Connect Changes - Spark Connect turns the Driver into a pre-started, long-running server. - Clients send unresolved logical plans encoded with Protocol Buffers over gRPC. - The server handles analysis, optimization, scheduling, and execution. - Results are streamed back using Arrow. - This resembles a database accessed through JDBC. ### Benefits - **Thin clients:** Clients do not need the full Spark runtime or JVM. - **Language and platform independence:** Notebooks, BI tools, SQL clients, and different programming languages can use the same server. - **Fast session creation:** Sessions connect to an already-running server. - **Better client-failure tolerance:** A disconnected notebook does not necessarily terminate server-side work. ## Problems Created by Shared Long-Running Servers Spark’s internal design often assumes “one application equals one workload.” Sharing one application across many users breaks that assumption. ### A Shared Driver Becomes a Single Point of Failure - Multiple sessions share one `SparkContext` and Driver JVM. - A Driver failure terminates all sessions, jobs, and caches attached to it. - Spark’s global `spark.executor.maxNumFailures` counter can shut down the entire application after enough executor failures. - Because all sessions contribute to the same counter, one user’s unstable or memory-intensive query can terminate unrelated users’ workloads. - The counter is global, persists over time, and is separate from per-query task-level fault tolerance such as `spark.task.maxFailures`. ### Resource Contention and Scheduling Limits - `newSession()` isolates SQL state and namespaces, but not CPU, memory, or executors. - Heavy workloads can occupy all task slots and delay smaller queries. - FIFO scheduling favors earlier jobs, and Spark does not preempt tasks already using slots. - Fair Scheduler pools can influence task-slot ordering, but cannot provide true CPU or memory isolation. - Spark Connect does not automatically propagate `spark.scheduler.pool` to the server-side execution thread, causing queries to fall into the default pool unless the server explicitly assigns pools. - Actual resource isolation must therefore be implemented outside Spark’s task scheduler. ### Fixed Server Capacity - A server’s image, Driver and Executor resources, and Spark configuration are fixed when it starts. - Dynamic Resource Allocation can adjust executor counts, but cannot change the server’s basic specification. - Flexible scaling and team-level isolation require creating or replacing servers, which is addressed in a later part of the series. ## Reducing Server-Wide Failures Before adding replicas, Toss Securities reduces the chance that one bad query can kill the shared server. - Set `spark.executor.maxNumFailures` effectively high enough to disable the global shutdown mechanism. - Use `spark.executor.failuresValidityInterval` to periodically clear accumulated failure records. - Rely on query-scoped controls: - `spark.task.maxFailures` stops tasks that repeatedly fail due to OOMs or exceptions. - `spark.stage.maxConsecutiveAttempts` stops jobs whose stages repeatedly fail, such as from shuffle-fetch errors. - These limits must be tuned carefully: overly aggressive values can cause healthy queries to fail during temporary infrastructure problems. - With this approach, executor failures terminate the problematic query rather than the entire Spark Connect server. ## Protecting Driver Memory from Large Results - Spark Connect streams query results through the Driver, so a large `collect()` can threaten Driver memory. - `spark.driver.maxResultSize` aborts an action when accumulated task results exceed the configured limit. - The limit is checked before large executor-side results are fetched into Driver memory. - The default 1 GB value assumes a single workload; in a multi-session server, it should be reduced or tuned based on the number of concurrent queries. ## Replicating Spark Connect Servers - Configuration alone cannot prevent Driver OOMs, node failures, or other catastrophic events. - The stronger isolation boundary is a separate SparkContext. - Multiple identical Spark Connect replicas are deployed: - Each replica has its own Driver, SparkContext, and Executors. - A failure affects only the sessions assigned to that replica. - Other replicas can continue accepting sessions. - Replica-based deployment reduces the blast radius from the entire Spark Connect service to an individual server instance. ## Practical Recommendation For a multi-user Spark Connect service, disable global executor-failure shutdown, enforce query-level failure limits, protect Driver memory with `spark.driver.maxResultSize`, and use multiple replicas to contain unavoidable Driver or node failures. Scheduler pools can improve ordering, but they should not be treated as true resource isolation.

Read original(opens in new tab)