LINE

107 posts

techblog.lycorp.co.jp/ko

Filter by tag

lineOriginal article

LY's Tech Conference, ' (opens in new tab)

LY Corporation’s Tech-Verse 2025 conference highlighted the company's strategic pivot toward becoming an AI-centric organization through the "Catalyst One Platform" initiative. By integrating the disparate infrastructures of LINE and Yahoo! JAPAN into a unified private cloud, the company aims to achieve massive cost efficiencies while accelerating the deployment of AI agents across its entire service ecosystem. This transformation focuses on empowering engineers with AI-driven development tools to foster rapid innovation and deliver a seamless, "WOW" experience for global users. ### Infrastructure Integration and the Catalyst One Platform To address the redundancies following the merger of LINE and Yahoo! JAPAN, LY Corporation is consolidating its technical foundations into a single internal ecosystem known as the Catalyst One Platform. * **Private Cloud Advantage:** The company maintains its own private cloud to achieve a four-fold cost reduction compared to public cloud alternatives, managed by a lean team of 700 people supporting 500,000 servers. * **Unified Architecture:** The integration spans several layers, including Infrastructure (Project "DC-Hub"), Cloud (Project "Flava"), and specialized Data and AI platforms. * **Next-Generation Cloud "Flava":** This platform integrates existing services to enhance VM specifications, VPC networking, and high-performance object storage (Ceph and Dragon). * **Information Security:** A dedicated "SafeOps" framework is being implemented to provide governance and security across all integrated services, ensuring a safer environment for user data. ### AI Strategy and Service Agentization A core pillar of LY’s strategy is the "AI Agentization" of all its services, moving beyond simple features to proactive, personalized assistance. * **Scaling GenAI:** Generative AI has already been integrated into 44 different services within the group. * **Personalized Agents:** The company is developing the capacity to generate millions of specialized agents that can be linked together to support the unique needs of individual users. * **Agent Ecosystem:** The goal is to move from a standard platform model to one where every user interaction is mediated by an intelligent agent. ### AI-Driven Development Transformation Beyond user-facing services, LY is fundamentally changing how its engineers work by deploying internal AI development solutions to all staff starting in July. * **Code and Test Automation:** Proof of Concept (PoC) results showed a 96% accuracy rate for "Code Assist" and a 97% reduction in time for "Auto Test" procedures. * **RAG Integration:** The system utilizes Retrieval-Augmented Generation (RAG) to leverage internal company knowledge and guidelines, ensuring high-quality, context-aware development support. * **Efficiency Gains:** By automating repetitive tasks, the company intends for engineers to shift their focus from maintenance to creative service improvement and innovation. The successful integration of these platforms and the aggressive adoption of AI-driven development tools suggest that LY Corporation is positioning itself to be a leader in the "AI-agent" era. For technical organizations, LY's model serves as a case study in how large-scale mergers can leverage private cloud infrastructure to fund and accelerate a company-wide AI transition.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

The builder pattern is frequently overused in modern development, often leading to code that is less robust than it appears. While it provides a fluent API, it frequently moves the detection of missing mandatory fields from compile-time to runtime, creating a "house of sand" that can collapse unexpectedly. By prioritizing constructors and factory functions, developers can leverage the compiler to ensure data integrity and build more stable applications. ### Limitations of the Standard Builder Pattern * In a typical builder implementation, mandatory fields are often initialized as nullable types and checked for nullity only when the `.build()` method is called. * This reliance on runtime checks like `checkNotNull` means that a developer might forget to set a required property, leading to an `IllegalStateException` during execution rather than a compiler error. * Unless the platform or a specific library (like an ORM) requires it, the boilerplate of a builder often hides these structural weaknesses without providing significant benefits. ### Strengthening Foundations with Constructors and Defaults * Using a class constructor or a factory function is often the simplest and most effective way to prevent bugs related to missing data. * In languages like Kotlin, the need for builders is further reduced by the availability of default parameters and named arguments, allowing for concise instantiation even with many optional fields. * If a builder must be used, mandatory arguments should be required in the builder's own constructor (e.g., `Builder(userName, emailAddress)`) to ensure the object is never in an invalid state. ### Managing Creation State and Pipelines * Developers sometimes pass a builder as an "out parameter" to other functions to populate data, which can obscure the flow of data and reduce readability. * A better approach is to use functions that return specific values, which are then passed into a final constructor, keeping the logic functional and transparent. * For complex, multi-stage creation logic, defining distinct types for each stage—such as moving from a `UserAccountModel` to a `UserProfileViewComponent`—can ensure that only valid, fully-formed data moves through the pipeline. ### Appropriate Use of Terminal Operations * The builder-like syntax is highly effective when implementing "terminal operations," where various transformations are applied in an arbitrary order before a final execution. * This pattern is particularly useful in image processing or UI styling (e.g., `.crop().fitIn().colorFilter()`), where it serves as a more readable alternative to deeply nested decorator patterns. * In these specific cases, the pattern facilitates a clear sequence of operations while maintaining a "last step" (like `.createBitmap()`) that signals the end of the configuration phase. Prioritize the use of constructors and factory functions to catch as many errors as possible during compilation. Reserve the builder pattern for scenarios involving complex terminal operations or when dealing with restrictive library requirements that demand a specific instantiation style.

lineOriginal article

Code Quality Improvement Techniques Part 1 (opens in new tab)

The Null Object Pattern is a design technique that replaces null values with objects representing "empty" or "invalid" states to simplify code and provide functional fallbacks. While it effectively streamlines logic for collections and general data flows, using it when error conditions must be explicitly distinguished can lead to hidden bugs and reduced type safety. Developers should generally prefer statically verified types, such as Optionals or language-native nullable types, unless the error case can be seamlessly integrated into the happy-path logic. ### Benefits of the Null Object Pattern * **Code Simplification:** By returning an empty list or a "null object" instead of a literal `null`, callers can avoid repetitive null-check boilerplate. * **Functional Continuity:** It allows for uninterrupted processing in functional chains, such as using `.asSequence().map().forEach()`, because the "empty" object still satisfies the required interface. * **Fallback Provisioning:** The pattern is useful for converting errors into safe fallback values, such as displaying an "Unknown User" profile image rather than crashing or requiring complex conditional UI logic. ### Risks of Silent Failures and Logic Errors * **Bypassing Compiler Safety:** Unlike nullable types in Kotlin or Swift, which force developers to handle the `null` case, a custom null object (e.g., `UserModel.INVALID`) allows code to compile even if the developer forgets to check the object's validity. * **Identity vs. Equivalence:** Implementing the pattern requires caution regarding how the object is compared. If a null object is checked via reference identity (`==`) but the class lacks a proper `equals` implementation, new instances with the same "empty" values may not be recognized as invalid. * **Debugging Difficulty:** When a null object is used inappropriately, the program may continue to run with dummy data. This makes bugs harder to detect compared to a runtime error or a compile-time type mismatch. ### Best Practices for Type Safeness * **Prefer Static Verification:** When boundary conditions or errors must be handled differently than the "happy path," use `Optional`, `Maybe`, or native nullable types to ensure the compiler enforces error handling. * **Criteria for Use:** Reserve the Null Object Pattern for cases where the error logic is identical to the normal logic, or when multiple "empty" candidates exist that cannot be easily resolved through static typing. * **Runtime Errors as a Tool:** In dynamic or non-nullable contexts, a runtime error is often preferable to silent execution with an invalid object, as it provides a clear signal that an unexpected state has been reached. ### Recommendation To maintain high code quality, utilize the Null Object Pattern primarily for collections and UI fallbacks. For core business logic where the presence of data is critical, rely on type-safe mechanisms that force explicit handling of missing values, thereby preventing invalid states from propagating silently through the system.

lineOriginal article

Hosting the Tech Conference Tech- (opens in new tab)

LY Corporation is hosting its global technology conference, Tech-Verse 2025, on June 30 and July 1 to showcase the engineering expertise of its international teams. The event features 127 sessions centered on core themes of AI and security, offering a deep dive into how the group's developers, designers, and product managers solve large-scale technical challenges. Interested participants can register for free on the official website to access the online live-streamed sessions, which include real-time interpretation in English, Korean, and Japanese. ### Conference Overview and Access * The event runs for two days, from 10:00 AM to 6:00 PM (KST), and is primarily delivered via online streaming. * Registration is open to the public at no cost through the Tech-Verse 2025 official website. * The conference brings together technical talent from across the LY Corporation Group, including LINE Plus, LINE Taiwan, and LINE Vietnam. ### Multi-Disciplinary Technical Tracks * The agenda is divided into 12 distinct categories to cover the full spectrum of software development and product lifecycle. * Day 1 focuses on foundational technologies: AI, Security, Server-side development, Private Cloud, Infrastructure, and Data Platforms. * Day 2 explores application and management layers: AI Use Cases, Frontend, Mobile Applications, Design, Product Management, and Engineering Management. ### Key Engineering Case Studies and Sessions * **AI and Data Automation:** Sessions explore the evolution of development processes using AI, the shift from "Vibe Coding" to professional AI-assisted engineering, and the use of Generative AI to automate data pipelines. * **Infrastructure and Scaling:** Presentations include how the "Central Dogma Control Plane" connects thousands of services within LY Corporation and methods for improving video playback quality for LINE Call. * **Framework Migration:** A featured case study details the strategic transition of the "Demae-can" service from React Native to Flutter. * **Product Insights:** Deep dives into user experience design and data-driven insights gathered from LINE Talk's global user base. Tech-Verse 2025 provides a valuable opportunity for developers to learn from real-world deployments of AI and large-scale infrastructure. Given the breadth of the 127 sessions and the availability of real-time translation, tech professionals should review the timetable in advance to prioritize tracks relevant to their specific engineering interests.

lineOriginal article

Replacing a Payment System Database That Processes (opens in new tab)

The LINE Billing Platform team recently migrated its core payment database from Nbase-T to Vitess to address rising licensing costs while maintaining the high availability required for financial transactions. After a rigorous Proof of Concept (PoC) evaluating Apache ShardingSphere, TiDB, and Vitess, the team selected Vitess for its mature sharding capabilities and its ability to provide a stable, scalable environment on bare-metal infrastructure. This migration ensures the platform can handle large-scale traffic efficiently without the financial burden of proprietary license fees. ### Evaluation of Alternative Sharding Solutions Before settling on Vitess, the team analyzed other prominent distributed database technologies to determine their fit for a high-stakes payment system: * **Apache ShardingSphere:** While it offers flexible Proxy and JDBC layers, it was excluded because it requires significant manual effort for data resharding and rebalancing. The management overhead for implementing shard-key logic across various components (API, batch, admin) was deemed too high. * **TiDB:** This MySQL-compatible distributed database uses a decoupled architecture consisting of TiDB (SQL layer), PD (metadata management), and TiKV (row-based storage). Its primary advantage is automatic rebalancing and the lack of a required shard key, which significantly reduces DBA operational costs. * **Nbase-T:** The legacy system provided the highest performance efficiency per resource unit; however, the shift from a free to a paid licensing model necessitated the move to an open-source alternative. ### Vitess Architecture and Core Components Vitess was chosen for its proven track record at companies like YouTube and GitHub, offering a robust abstraction layer that makes a clustered database appear as a single instance to the application. The system relies on several specialized components: * **VTGate:** A proxy server that routes queries to the correct VTTablet, manages distributed transactions, and hides the physical topology of the database from the application. * **VTTablet:** A sidecar process running alongside each MySQL instance that manages query execution, data replication, and connection pooling. * **VTorc and Topology Server:** High availability is managed by VTorc (an automated failover tool), while metadata regarding shard locations and node status is synchronized via a topology server using ZooKeeper or etcd. ### PoC Performance and Environment Setup The team conducted performance testing by simulating real payment API scenarios (a mix of reads and writes) on standardized hardware (8vCPU, 16GB RAM). * **Comparison Metrics:** The tests focused on Transactions Per Second (TPS) and resource utilization as thread counts increased. * **Infrastructure Strategy:** Because payment systems cannot tolerate even brief failover delays, the team opted for a bare-metal deployment rather than a containerized one to ensure maximum stability and performance. * **Resource Efficiency:** While Nbase-T showed the best raw efficiency, Vitess demonstrated the necessary scalability and management features required to replace the legacy system effectively within the new cost constraints. ### Practical Recommendation For organizations managing critical core systems that require horizontal scaling without proprietary lock-in, Vitess is a highly recommended solution. While it requires a deep understanding of its various components (like VTGate and VTTablet) and careful configuration of its topology server, the trade-off is a mature, cloud-native-ready architecture that supports massive scale and automated failover on both bare-metal and cloud environments.

lineOriginal article

AI and Writer's Partnership (opens in new tab)

LY Corporation is addressing the chronic shortage of high-quality technical documentation by treating the problem as an engineering challenge rather than a training issue. By utilizing Generative AI to automate the creation of API references, the Document Engineering team has transitioned from a "manual craftsmanship" approach to an "industrialized production" model. While the system significantly improves efficiency and maintains internal context better than generic tools, the team concludes that human verification remains essential due to the high stakes of API accuracy. ### Contextual Challenges with Generic AI Standard coding assistants like GitHub Copilot often fail to meet the specific documentation needs of a large organization. * Generic tools do not adhere to internal company style guides or maintain consistent terminology across projects. * Standard AI lacks awareness of internal technical contexts; for example, generic AI might mistake a company-specific identifier like "MID" for "Member ID," whereas the internal tool understands its specific function within the LY ecosystem. * Fragmented deployment processes across different teams make it difficult for developers to find a single source of truth for API documentation. ### Multi-Stage Prompt Engineering To ensure high-quality output without overwhelming the LLM's "memory," the team refined a complex set of instructions into a streamlined three-stage workflow. * **Language Recognition:** The system first identifies the programming language and specific framework being used. * **Contextual Analysis:** It analyzes the API's logic to generate relevant usage examples and supplemental technical information. * **Detail Generation:** Finally, it writes the core API descriptions, parameter definitions, and response value explanations based on the internal style guide. ### Transitioning to Model Context Protocol (MCP) While the prototype began as a VS Code extension, the team shifted to using the Model Context Protocol (MCP) to ensure the tool was accessible across various development environments. * Moving to MCP allows the tool to support multiple IDEs, including IntelliJ, which was a high-priority request from the developer community. * The MCP architecture decouples the user interface from the core logic, allowing the "host" (like the IDE) to handle UI interactions and parameter inputs. * This transition reduced the maintenance burden on the Document Engineering team by removing the need to build and update custom UI components for every IDE. ### Performance and the Accuracy Gap Evaluation of the AI-generated documentation showed strong results, though it highlighted the unique risks of documenting APIs compared to other forms of writing. * Approximately 88% of the AI-generated comments met the team's internal evaluation criteria. * The specialized generator outperformed GitHub Copilot in 78% of cases regarding style and contextual relevance. * The team noted that while a 99% accuracy rate is excellent for a blog post, a single error in a short API reference can render the entire document useless for a developer. To successfully implement AI-driven documentation, organizations should focus on building tools that understand internal business logic while maintaining a strict "human-in-the-loop" workflow. Developers should use these tools to generate the bulk of the content but must perform a final technical audit to ensure the precision that only a human author can currently guarantee.

lineOriginal article

Code Quality Improvement Techniques Part 1 (opens in new tab)

Effective naming in software development should prioritize the perspective of the code's consumer over the visual consistency of class declarations. By following natural grammatical structures, developers can reduce ambiguity and ensure that the purpose of a class or variable is immediately clear regardless of context. Ultimately, clear communication through grammar is more valuable for long-term maintenance than aesthetic symmetry in the codebase. ### Prefixing vs. Postfixing for Class Names When splitting a large class like `SettingRepository` into specific modules (e.g., Account, Security, or Language), the choice of where to place the modifier significantly impacts readability. * Postfixing modifiers (e.g., `SettingRepositorySecurity`) might look organized in a file directory, but it creates grammatical confusion when the class is used in isolation. * A developer encountering `SettingRepositorySecurity` in a constructor might misinterpret it as a "security module belonging to the SettingRepository" rather than a repository specifically for security settings. * Prefixing the modifier (e.g., `SecuritySettingRepository`) follows standard English grammar, clearly identifying the object as a specific type of repository and reducing the cognitive load for the reader. ### Handling Multiple Modifiers and the "Sandwich" Effect In cases where a single prefix is insufficient, such as defining the "height of a send button in portrait mode," naming becomes more complex. * Using only prefixes (e.g., `portraitSendButtonHeight`) can be ambiguous, potentially being read as the "height of a button used to send a portrait." * To resolve this, developers can use a "modifier sandwich" by moving some details to the end using prepositions like "for," "of," or "in" (e.g., `sendButtonHeightForPortrait`). * While prepositions are helpful for variables, they should generally be avoided in class or struct names to ensure that instance names derived from the type remain concise. * Developers should also defer to platform-specific conventions; for example, Java and Kotlin often omit prepositions in standard APIs, such as using `currentTimeMillis` instead of `currentTimeInMillis`. When naming any component, favor the clarity of the person reading the implementation over the convenience of the person writing the definition. Prioritizing grammatical correctness ensures that the intent of the code remains obvious even when a developer is looking at a single line of code.

lineOriginal article

We tested the video call quality (opens in new tab)

To optimize the LINE messenger’s communication performance, LY Corporation conducted an on-site call quality assessment in Thailand to analyze local network conditions and compare performance against rising competitors. The study concluded that while LINE offers superior visual clarity and higher bitrates than its rivals, this high-performance strategy requires a careful technical balance to prevent video freezing in unstable network environments. ### High Video Call Adoption in Thailand * Thailand exhibits the highest video call usage among LINE’s major markets, with video calls accounting for 30.43% of all 1:1 sessions—more than double the rate of Japan or Taiwan. * The surge in usage by competitors, specifically "Messenger A," has necessitated frequent benchmarking to maintain LINE’s market leadership and technical edge. * Thailand serves as the primary testing ground for any updates to video modules due to the local user base's preference for high-quality real-time visual communication. ### On-Site Quality Testing Methodology * The assessment was performed over five days by five engineers across high-traffic locations in Bangkok, such as Siam Paragon and Samron Market, using True and AIS 4G/5G networks. * Engineers focused on Quality of Service (QoS) metrics—including packet loss and jitter—to estimate the actual Quality of Experience (QoE) for users. * Baseline performance for LINE in Thailand was recorded at VGA resolution, with frame rates exceeding 20 FPS and an average latency of approximately 150ms. ### Bitrate Strategy and Performance Trade-offs * LINE utilizes a high-bitrate strategy, capping at 1Mbps on 5G and 600kbps on 4G, to deliver sharper, more defined images than Competitor A. * A "start-at-max" approach is used where LINE attempts to find and utilize the highest possible bitrate from the beginning of the call to ensure immediate high quality. * In contrast, competitors adopt a conservative bitrate strategy, starting low and increasing slowly to prioritize connection stability over visual fidelity. * The trade-off for LINE’s higher quality is an increased risk of "freezing"—defined as a single frame persisting for more than 200ms—when the network becomes congested or unstable. ### Technical Implications for Future Development * The relationship between bitrate and network stability remains a zero-sum trade-off; higher bitrates provide better clarity but increase the likelihood of packet delay and loss at the router level. * LINE’s engineering focus is directed toward optimizing the "initial bitrate" detection logic to ensure high quality without triggering network-induced lag in crowded urban environments. * Continuous tuning of the balance between peak visual performance and consistent playback remains the core challenge for maintaining service quality in the Thai market.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

Applying the Single Responsibility Principle is a fundamental practice for maintaining high code quality, but over-fragmenting logic can inadvertently lead to architectural complexity. While splitting classes aims to increase cohesion, it can also scatter business constraints and force callers to manage an overwhelming number of dependencies. This post explores the "responsibility of assigning responsibility," arguing that sometimes maintaining a slightly larger, consolidated class is preferable to creating fragmented "Ravioli code." ### Initial Implementation and the Refactoring Drive The scenario involves a dynamic "Launch Button" that can fire rockets, fireworks, or products depending on its mode. * The initial design used a single `LaunchButtonBinder` that held references to all possible `Launcher` types and an internal enum to select the active one. * To strictly follow the Single Responsibility Principle, developers often attempt to split this into two parts: a binder for the button logic and a selector for choosing the mode. * The refactored approach utilized a `LaunchBinderSelector` to manage multiple `LaunchButtonBinder` instances, using an `isEnabled` flag to toggle which logic was active. ### The Problem of Scattered Constraints and State While the refactored classes are individually simpler, the overall system becomes harder to reason about due to fragmented logic. * **Verification Difficulty:** In the original code, the constraint that "only one thing launches at a time" was obvious in a single file; in the refactored version, a developer must trace multiple classes and loops to verify this behavior. * **State Redundancy:** Adding an `isEnabled` property to binders creates a risk of state synchronization issues between the selector’s current mode and the binders' internal flags. * **Information Hiding Trade-offs:** Attempting to hide implementation details often forces the caller to resolve all dependencies (binders, buttons, and launchers) manually, which can turn the caller into a bloated "God class." ### Avoiding "Ravioli Code" Through Balanced Design The pursuit of granular responsibilities can lead to "Ravioli code," where the system consists of many small, independent components but lacks a clear, cohesive structure. * The original implementation’s advantage was that it encapsulated all logic related to the launch button's constraints in one place. * When deciding to split a class, developers must evaluate if the move improves the overall system or simply shifts the burden of complexity to the caller. * Effective design requires balancing individual class cohesion with the overhead of inter-module coupling and dependency management. When refactoring for code quality, prioritize the clarity of the overall system over the dogmatic pursuit of small classes. If splitting a class makes it harder to verify business constraints or complicates the caller's logic significantly, it may be better to keep those related responsibilities together.

lineOriginal article

Complex user authentication processes are easy (opens in new tab)

Designing a robust membership authentication system is a critical early-stage requirement that prevents long-term technical debt and protects a platform’s integrity. By analyzing the renewal of the Demaecan delivery service, it is evident that choosing the right authentication mechanism depends heavily on regional infrastructure and a balance between security costs and user friction. Ultimately, a well-structured authentication flow can simultaneously reduce fraud rates and significantly lower user drop-off during registration. ### The Consequences of Weak Authentication Neglecting authentication design during the initial stages of a project often leads to "ghost members" and operational hurdles that are difficult to rectify later. * **Data Integrity Issues:** Without verification, databases fill with unreachable or fake contact information, such as invalid phone numbers. * **Onboarding Blockers:** Legitimate new users may be prevented from signing up if their recycled phone numbers are already linked to unverified legacy accounts. * **Marketing Abuse:** A lack of unique identifiers makes it impossible to prevent bad actors from creating multiple accounts to exploit promotional coupons or events. ### Regional Differences in Verification Authentication strategies must be tailored to the specific digital infrastructure of the target market, as "identity verification" varies globally. * **Domestic (Korea) Standards:** Highly integrated systems allow for "Identity Verification," which combines possession (OTP) and real-name data through telecommunications companies or banking systems. * **Global and Japanese Standards:** Most regions lack a centralized government-linked identity system, relying instead on "Possession Authentication" via email or SMS, or simple two-factor authentication (2FA). * **Verification Expiration:** High-security services must define clear validity periods for authentication data and determine how long to retain data after a user withdraws to prevent immediate re-abuse. ### Strategic Fraud Prevention via IVR When SMS-based possession authentication becomes insufficient to stop determined abusers, shifting the economic cost for the fraudster is an effective solution. * **SMS vs. Voice (IVR):** In Japan, acquiring phone numbers capable of receiving voice calls is more expensive than acquiring SMS-only numbers. * **IVR Implementation:** By switching to call-based (Inbound Voice Response) authentication, Demaecan increased the barrier to entry for abusers. * **Impact:** This strategic shift in authentication type reduced the fraudulent user rate from over 20% to just 1.5%. ### Optimizing Sign-up UX and Retention A complex authentication process does not have to result in high churn if the UI flow is logically organized and user-friendly. * **Logical Grouping:** Grouping similar tasks—such as placing phone and email verification sequentially—helps users understand the progression of the sign-up flow. * **Streamlined Data Entry:** Integrating social login buttons early in the process allows for email auto-fill, reducing the number of manual input fields for the user. * **Safety Nets:** Implementing simple "back" buttons for correcting typos during email verification and adding warning dialogs when a user tries to close the window significantly reduces accidental exits. * **Performance Metrics:** These UX improvements led to a 30% decrease in user attrition, proving that structured flows can mitigate the friction of multi-step verification. To build a successful authentication system, planners should prioritize the most cost-effective verification method for their specific market and focus on grouping steps logically to maintain a smooth user experience. Monitoring conversion logs is essential to identify and fix specific points in the flow where users might struggle.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

The "Clone Family" anti-pattern occurs when two parallel inheritance hierarchies—such as a data model tree and a provider tree—share an implicit relationship that is not enforced by the type system. This structure often leads to type-safety issues and requires risky downcasting to access specific data types, increasing the likelihood of runtime errors during code modifications. To resolve this, developers should replace rigid inheritance with composition or utilize parametric polymorphism to explicitly link related types. ## The Risks of Implicit Correspondence Maintaining two separate inheritance trees where individual subclasses are meant to correspond to one another creates several technical hurdles. * **Downcasting Requirements:** Because a base provider typically returns a base data model type, developers must manually cast the result to a specific subclass (e.g., `as FooDataModel`), which bypasses compiler safety. * **Lack of Type Enforcement:** The constraint that a specific provider always returns a specific model is purely implicit; the compiler cannot prevent a provider from returning the wrong model type. * **Fragile Architecture:** As the system grows, ensuring that "Provider A" always maps to "Model A" becomes difficult to audit, leading to potential bugs when new developers join the project or when the hierarchy is extended. ## Substituting Inheritance with Composition When the primary goal of inheritance is simply to share common logic, such as fetching raw data, using composition or aggregation is often a superior alternative. * **Logic Extraction:** Shared functionality can be moved into a standalone class, such as an `OriginalDataProvider`, which is then held as a private property within specific provider classes. * **Direct Type Returns:** By removing the shared parent class, each provider can explicitly return its specific data model type without needing a common interface. * **Decoupling:** This approach eliminates the "Clone Family" entirely by removing the need for parallel trees, resulting in cleaner and more modular code. ## Leveraging Parametric Polymorphism In scenarios where a common parent class is necessary—for example, to manage a collection of providers within a shared lifecycle—generics can be used to bridge the two hierarchies safely. * **Generic Type Parameters:** By defining the parent as `ParentProvider<T>`, the base class can use a type parameter for its return values rather than a generic base model. * **Subclass Specification:** Each implementation (e.g., `FooProvider : ParentProvider<FooDataModel>`) explicitly defines its return type, allowing the compiler to enforce the relationship. * **Flexible Constraints:** Developers can still utilize type bounds, such as `ParentProvider<T : CommonDataModel>`, to ensure that the generics adhere to a specific interface while maintaining type safety for callers. When designing data providers and models, avoid creating parallel structures that rely on implicit assumptions. Prioritize composition to simplify the architecture, or use generics if inheritance is required, ensuring that the relationships between classes remain explicit and verifiable by the compiler.

lineOriginal article

Implementing a RAG-based (opens in new tab)

To address the operational burden of handling repetitive user inquiries for the AWX automation platform, LY Corporation developed a support bot utilizing Retrieval-Augmented Generation (RAG). By combining internal documentation with historical Slack thread data, the system provides automated, context-aware answers that significantly reduce manual SRE intervention. This approach enhances service reliability by ensuring users receive immediate assistance while allowing engineers to focus on high-priority development tasks. ### Technical Infrastructure and Stack * **Slack Integration**: The bot is built using the **Bolt for Python** framework to handle real-time interactions within the company’s communication channels. * **LLM Orchestration**: **LangChain** is used to manage the RAG pipeline; the developers suggest transitioning to LangGraph for teams requiring more complex multi-agent workflows. * **Embedding Model**: The **paraphrase-multilingual-mpnet-base-v2** (SBERT) model was selected to support multi-language inquiries from LY Corporation’s global workforce. * **Vector Database**: **OpenSearch** serves as the vector store, chosen for its availability as an internal PaaS and its efficiency in handling high-dimensional data. * **Large Language Model**: The system utilizes **OpenAI (ChatGPT) Enterprise**, which ensures business data privacy by preventing the model from training on internal inputs. ### Enhancing LLM Accuracy through RAG and Vector Search * **Overcoming LLM Limits**: Traditional LLMs suffer from "hallucinations," lack of up-to-date info, and opaque sourcing; RAG fixes this by providing the model with specific, trusted context during the prompt phase. * **Embedding and Vectorization**: Textual data from wikis and chats are converted into high-dimensional vectors, where semantically similar phrases (e.g., "Buy" and "Purchase") are stored in close proximity. * **k-NN Retrieval**: When a user asks a question, the bot uses **k-Nearest Neighbors (k-NN)** algorithms to retrieve the top *k* most relevant snippets of information from the vector database. * **Contextual Generation**: Rather than relying on its internal training data, the LLM generates a response based specifically on the retrieved snippets, leading to higher accuracy and domain-specific relevance. ### AWX Support Bot Workflow and Data Sources * **Multi-Source Indexing**: The bot references two main data streams: the official internal AWX guide wiki and historical Slack inquiry threads where previous solutions were discussed. * **Automated First Response**: The workflow begins when a user submits a query via a Slack workflow; the bot immediately processes the request and provides an initial AI-generated answer. * **Human-in-the-Loop Validation**: After receiving an answer, users can click "Issue Resolved" to close the ticket or "Call AWX Admin" if the AI's response was insufficient. * **Efficiency Gains**: This tiered approach filters out "RTFM" (Read The F***ing Manual) style questions, ensuring that human administrators only spend time on unique or complex technical issues. Implementing a RAG-based support bot is a highly effective strategy for SRE teams looking to scale their internal support without increasing headcount. For the best results, organizations should focus on maintaining clean internal documentation and selecting embedding models that reflect the linguistic diversity of their specific workforce.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

The "Set Discount" technique improves code quality by grouping related mutable properties into a single state object rather than allowing them to be updated individually. By restricting state changes through a controlled interface, developers can prevent inconsistent configurations and simplify the lifecycle management of complex classes. This approach ensures that dependent values are updated atomically, significantly reducing bugs caused by race conditions or stale data. ### The Risks of Fragmented Mutability When a class exposes multiple independent mutable properties, such as `isActive`, `minImportanceToRecord`, and `dataCountPerSampling`, it creates several maintenance challenges: * **Order Dependency:** Developers might accidentally set `isActive` to true before updating the configuration properties, causing the system to briefly run with stale or incorrect settings. * **Inconsistent Logic:** Internal state resets (like clearing a counter) may be tied to one property but forgotten when another related property changes, leading to unpredictable behavior. * **Concurrency Issues:** Even in single-threaded environments, asynchronous updates to individual properties can create race conditions that are difficult to debug. ### Consolidating State with SamplingPolicy To resolve these issues, the post recommends refactoring individual properties into a dedicated configuration class and using a single reference to manage the state: * **Atomic Updates:** By wrapping configuration values into a `SamplingPolicy` class, the system ensures that the minimum importance level and sampling interval are always updated together. * **Representing "Inactive" with Nulls:** Instead of a separate boolean flag, the `policy` property can be made nullable. An `inactive` state is naturally represented by `null`, making it impossible to "activate" the recorder without providing a valid policy. * **Explicit Lifecycle Methods:** Replacing property setters with methods like `startRecording()` and `finishRecording()` forces a clear transition of state and ensures that counters are reset consistently every time a new session begins. ### Advantages of Restricting State Transitions Moving from individual property mutation to a consolidated interface offers several technical benefits: * **Guaranteed Consistency:** It eliminates the possibility of "half-configured" states because the policy is replaced as a whole. * **Simplified Thread Safety:** If the class needs to be thread-safe, developers only need to synchronize a single reference update rather than coordinating multiple volatile variables. * **Improved Readability:** The intent of the code becomes clearer to future maintainers because the valid combinations of state are explicitly defined by the API. When designing components where properties are interdependent or must change simultaneously, you should avoid providing public setters for every field. Instead, provide a focused interface that limits updates to valid combinations, ensuring the object remains in a predictable state throughout its lifecycle.

lineOriginal article

How to evaluate AI-generated images? (opens in new tab)

To optimize the Background Person Removal (BPR) feature in image editing services, the LY Corporation AMD team evaluated various generative AI inpainting models to determine which automated metrics best align with human judgment. While traditional research benchmarks often fail to reflect performance in high-resolution, real-world scenarios, this study identifies a framework for selecting models that produce the most natural results. The research highlights that as the complexity and size of the masked area increase, the gap between model performance becomes more pronounced, requiring more sophisticated evaluation strategies. ### Background Person Removal Workflow * **Instance Segmentation:** The process begins by identifying individual pixels to classify objects such as people, buildings, or trees within the input image. * **Salient Object Detection:** This step distinguishes the main subjects of the photo from background elements to ensure only unwanted figures are targeted for removal. * **Inpainting Execution:** Once the background figures are removed, inpainting technology is used to reconstruct the empty space so it blends seamlessly with the surrounding environment. ### Comparison of Inpainting Technologies * **Diffusion-based Models:** These models, such as FLUX.1-Fill-dev, restore damaged areas by gradually removing noise. While they excel at restoring complex details, they are generally slower than GANs and can occasionally generate artifacts. * **GAN-based Models:** Using a generator-discriminator architecture, models like LaMa and HINT offer faster generation speeds and competitive performance for lower-resolution or smaller inpainting tasks. * **Performance Discrepancy:** Experiments showed that while most models perform well on small areas, high-resolution images with large missing sections reveal significant quality differences that are not always captured in standard academic benchmarks. ### Evaluation Methodology and Metrics * **BPR Evaluation Dataset:** The team curated a specific dataset of 10 images with high quality-variance to test 11 different inpainting models released between 2022 and 2024. * **Single Image Quality Metrics:** Evaluated models using LAION Aesthetics score-v2, CLIP-IQA, and Q-Align to measure the aesthetic quality of individual generated frames. * **Preference and Reward Models:** Utilized PickScore, ImageReward, and HPS v2 to determine which generated images would be most preferred by human users. * **Objective:** The goal of these tests was to find an automated evaluation method that minimizes the need for expensive and time-consuming human reviews while maintaining high reliability. Selecting an inpainting model based solely on paper-presented metrics is insufficient for production-level services. For features like BPR, it is critical to implement an evaluation pipeline that combines both aesthetic scoring and human preference models to ensure consistent quality across diverse, high-resolution user photos.

lineOriginal article

Code Quality Improvement Techniques Part (opens in new tab)

Effective code design often involves shifting the responsibility of state verification from the caller to the receiving object. By internalizing "if-checks" within the function that performs the action, developers can reduce boilerplate, prevent bugs caused by missing preconditions, and simplify state transitions. This encapsulation ensures that objects maintain their own integrity while providing a cleaner, more intuitive API for the rest of the system. ### Internalizing State Verification * Instead of the caller using a pattern like `if (!receiver.isState()) { receiver.doAction() }`, the check should be moved inside the `doAction` method. * Moving the check inside the function prevents bugs that occur when a caller forgets to verify the state, which could otherwise lead to crashes or invalid data transitions. * This approach hides internal state details from the caller, simplifying the object's interface and focusing on the desired outcome rather than the prerequisite checks. * If "doing nothing" when a condition isn't met is non-obvious, developers should use descriptive naming (e.g., `markAsFriendIfNotYet`) or clear documentation to signal this behavior. ### Leveraging Return Values for Conditional Logic * When a caller needs to trigger a secondary effect—such as showing a UI popup—only if an action was successful, it is better to return a status value (like a `Boolean`) rather than using higher-order functions. * Passing callbacks like `onSucceeded` into a use case can create unnecessary dependency cycles and makes it difficult for the caller to discern if the execution is synchronous or asynchronous. * Returning a `Boolean` to indicate if a state change actually occurred allows the caller to handle side effects cleanly and sequentially. * To ensure the caller doesn't ignore these results, developers can use documentation or specific compiler annotations to force the verification of the returned value. To improve overall code quality, prioritize "telling" an object what to do rather than "asking" about its state and then acting. Centralizing state logic within the receiver not only makes the code more robust against future changes but also makes the intent of the calling code much easier to follow.