{
    "archive_path": "archive/1765538996.362868",
    "base_url": "olano.dev/blog/balancing-coupling",
    "basename": "",
    "bookmarked_date": "2025-12-12 11:29",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/olano.dev/blog/balancing-coupling",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=olano.dev",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": null
    },
    "domain": "olano.dev",
    "downloaded_at": "2025-12-12T11:29:58.543614+00:00",
    "downloaded_datestr": "2025-12-12 11:29",
    "extension": "",
    "hash": "105P8AWR6N3Z2W1TB2JB",
    "history": {
        "archive_org": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://web.archive.org/save/https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-12T11:30:43.267831+00:00",
                "index_texts": null,
                "output": "https://web.archive.org/web/20251212113027/https://olano.dev/blog/balancing-coupling/",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:22.908986+00:00",
                "status": "succeeded"
            }
        ],
        "dom": [
            {
                "cmd": [
                    "/usr/bin/chromium-browser",
                    "--proxy-server=socks5://tor-socks-proxy:9150",
                    "--disable-features=DarkMode",
                    "--run-all-compositor-stages-before-draw",
                    "--hide-scrollbars",
                    "--autoplay-policy=no-user-gesture-required",
                    "--no-first-run",
                    "--use-fake-ui-for-media-stream",
                    "--use-fake-device-for-media-stream",
                    "--simulate-outdated-no-au='Tue, 31 Dec 2099 23:59:59 GMT'",
                    "--headless=new",
                    "--no-sandbox",
                    "--no-zygote",
                    "--disable-dev-shm-usage",
                    "--disable-software-rasterizer",
                    "--disable-sync",
                    "--window-size=1440,2000",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "--user-data-dir=/data/personas/Default/chrome_profile",
                    "--profile-directory=Default",
                    "--dump-dom",
                    "https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "131.0.6778",
                "end_ts": "2025-12-12T11:30:11.706453+00:00",
                "index_texts": null,
                "output": "output.html",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:02.990394+00:00",
                "status": "succeeded"
            }
        ],
        "favicon": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://www.google.com/s2/favicons?domain=olano.dev"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-12T11:30:01.659388+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:29:58.704965+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-12T11:30:02.568653+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:01.705197+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [
            {
                "cmd": [
                    "(internal) archivebox.extractors.htmltotext",
                    "./{singlefile,dom}.html"
                ],
                "cmd_version": "0.8.5rc51",
                "end_ts": "2025-12-12T11:30:18.017667+00:00",
                "index_texts": [
                    "[tl;dr] Balancing Coupling in Software Design | olano.dev (/assets/css/main.css) (/feed.xml) (olano.dev) (https://olano.dev/blog/balancing-coupling)  (/) olano.dev (/blog) blog  [tl;dr] Balancing Coupling in Software Design 2025-10-19 (/blog/tags#software) #software (/blog/tags#books) #books (/blog/tags#tldr) #tldr    (https://coupling.dev/)   Commentary  I got interested in this after reading the (../domain-driven-design-revisited) Domain-Driven Design book by the same author, because of the historical perspective he applied to his treatment of modular design. This new book sounded like it would expand on that, and it didn\u2019t disappoint: it\u2019s well researched, building on the ideas of Parnas, Myers, Brooks, Conway, and Ousterhout, to produce something new and useful. Vlad Khononov does something that (../unit-testing-principles) I find is fundamental to the software design discussion: he provides principled definitions to reduce our reliance on gut feeling when making decisions. That being said, while insightful, it\u2019s also a rather specialized book, one that I recommend to software design nerds but not necessarily to every programmer (as, say, I do recommend A Philosophy of Software Design ). I may change this assessment if I find myself frequently using its heuristics to success. The thesis of the book: despite its reputation, coupling is not something fundamentally bad that we need to remove but an attribute that we should manage strategically. Similar to essential complexity, a useful software system can\u2019t exist without some form of coupling of its components. An easy way to internalize this idea is remembering that cohesion is sometimes defined as good coupling . Software has a fractal nature, one can reason about modularity at the system, service, namespace, class, and function levels. At each level there are interfaces and implementation, module depth and complexity. Complexity is twofold: local and global. And since software is fractal, this level\u2019s global complexity becomes a higher level\u2019s local one. Naively splitting modules into smaller ones just pushes local complexity up, making the overall system more complicated. Our job then is not chasing local minima but striking a balance: a good enough trade-off that reduces total maintenance cost. Two thirds of the book is spent on definitions: there are the usual suspects (complexity, modularity, coupling), some historically relevant concepts (structured design\u2019s module coupling, connasence), and a few new ones introduced by the author (integration strength, distance, volatility). These are used to compose heuristics (represented as formulas) to assess the modularity and balance of components in a system, to detect problems and hint at possible solutions. This activity is what the author calls balancing (and re-balancing) coupling. The final chapters show concrete applications of these heuristics on a series of case studies. To a large extent, the process can be summarized as: if modules are strongly integrated (they share much knowledge), reduce their distance; if modules are weakly integrated (they don\u2019t share much knowledge), increase their distance. Notice how this differs from the notion that smaller, more spread out components necessarily yield simpler systems (a notion that leads to microservice hell and left-pad). But the balancing is not limited to \u201cmoving things around\u201d. Given that software systems are fractal networks, one can introduce new levels of abstraction to allow them to grow beyond their structural limits\u2014and the cognitive load its maintainers can support. This is one of the strengths of the theory presented by the book: the same principles apply at all levels of a system; there\u2019s no hard distinction between software design and architecture\u2014not even between software systems and (../a-note-on-essential-complexity) the human systems they integrate \u2014just different scales, different semantic levels: different perspectives. Summary  A system has components and purpose. The interaction between the components (coupling) is necessary for the components to achieve the system\u2019s purpose. On a smaller scale, a component is almost always a subsystem in its own right. Coupling results from the components having to share knowledge, or lifecycles, or both. Coupling defines not only what knowledge is allowed to flow between the components but also what knowledge should never leave their boundaries. This makes coupling a core tool for designing modular software systems. The higher the magnitude of coupling, the higher the likelihood of the coupled components having to change together.   Complexity reflects the cognitive load a person experiences when interacting with a system. The greater the cognitive load, the more difficult it is to understand, control, predict, and change the behavior of the system. Local complexity is the complexity of a single component\u2014the complexity of interactions happening inside it. Global complexity is the complexity of interactions between the system\u2019s components. This distinction is subjective and depends on perspective. Global complexity turns into local when the system is observed from a higher level of abstraction.   A module is a type of component designed to improve the flexibility of a system, allowing it to evolve to support future goals. A software module bounds a well-defined functionality, exposing it to other components through a public interface. Any logical or physical boundary within a software system can be designed as a module: a service, a namespace, an object, a function, etc. An effective module hides decisions. If a decision has to be revisited, the change should only affect one module, the one that \u201chides\u201d it. An effective module maximizes the knowledge it encapsulates, while sharing only the minimum that is required for other components to work with it.   A system\u2019s design should not be evaluated by examining individual modules in isolation, but the relationships between them: how they are coupled. Different ways of coupling components share different types and amounts of knowledge. Some will increase complexity, while others will contribute to modularity. Coupling manifests across three dimensions: integration strength, distance, and volatility. The higher the integration strength (the more knowledge shared across their boundaries), the higher the likelihood that modules will need to change in unison. When such cascading changes occur, distance signifies the effort required to implement them. Volatility represents how frequently these changes are anticipated to happen. When designing cross-component interactions, our goal is not to minimize the strength of coupling. The goal is a modular system: one that is simple to implement, evolve, and maintain. This can only be achieved by considering all three dimensions of coupling.   Integration strength models the type and extent of knowledge shared by coupled components. There are four levels of coupling strength: Intrusive coupling: integration through the upstream component\u2019s private interfaces or other implementation details. This makes the downstream component sensitive to all future changes in the upstream component. Functional coupling: components implement closely related business functionalities. A change in the business requirements is highly likely to affect all coupled components. Model coupling: components using a shared model of the business domain. The evolution of the model requires changes in all coupled modules. Contract coupling: components using an integration-specific shared model: a contract. The integration contract abstracts the details of the model used internally in the upstream component.   Distance refers to the space knowledge \u201ctravels\u201d across coupled components. It affects the coordination and communication efforts needed to implement a change affecting the coupled components. Distance is influenced by several factors: The physical location of the code: for example, it\u2019s easier to change coupled methods in a class than coupled methods across distributed systems. On the other hand, collocating otherwise unrelated functionalities couples their lifecycles, introducing collateral changes that wouldn\u2019t be necessary if they were separated. Organizational structure: the greater the ownership distance (whether components are maintained by the same person, team, department, or organization), the higher the coordination effort.   Volatility is a component\u2019s expected rate of change. One way to model volatility is through Domain-Drive Design\u2019s subdomain types: core subdomains are expected to change more frequently than supporting and generic subdomains. Investing in modularization isn\u2019t as beneficial for components that are not expected to change frequently.   Balance refers to the optimal state of the three dimensions of coupling, in which the design increases the modularity of the system\u2019s volatile components. An unbalanced combination of these dimensions results in increased cognitive load and, consequently, increased complexity.  -- there's global complexity when significant knowledge   -- travels long distances   global_complexity := strength() AND distance()     -- there's local complexity when unrelated components   -- are collocated   local_complexity := NOT strength() AND NOT distance()     -- modularity is the absence of local and global complexity   complexity := local_complexity OR global_complexity   = NOT ( strength() XOR distance())   modularity := NOT complexity   = strength() XOR distance()     -- there's balance when the volatile components are modular   -- and the complex components don't change   balance := modularity OR NOT volatility()   = ( strength() XOR distance()) OR NOT volatility()       \u2190 (/blog/verified-in-production) \u201cNeeds to be verified in production\u201d   (/blog/whats-different-about-my-rss-reader) What\u2019s different about my RSS reader  \u2192    (https://olano.dev/blog/balancing-coupling)  (/) Facundo Olano Vlad Khononov builds on the ideas of Parnas, Myers, Brooks, Conway, and Ousterhout, to produce something new and useful.    powered by (https://jorge.olano.dev) jorge | (https://github.com/facundoolano/olano.dev/tree/main/src/blog/balancing-coupling.org) source | (mailto:facundo.olano@gmail.com) contact     "
                ],
                "output": "htmltotext.txt",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:17.996780+00:00",
                "status": "succeeded"
            }
        ],
        "media": [
            {
                "cmd": [
                    "/usr/local/bin/yt-dlp",
                    "--restrict-filenames",
                    "--trim-filenames",
                    "128",
                    "--write-description",
                    "--write-info-json",
                    "--write-annotations",
                    "--write-thumbnail",
                    "--no-call-home",
                    "--write-sub",
                    "--write-auto-subs",
                    "--convert-subs=srt",
                    "--yes-playlist",
                    "--continue",
                    "--no-abort-on-error",
                    "--ignore-errors",
                    "--geo-bypass",
                    "--add-metadata",
                    "--format=(bv*+ba/b)[filesize<=750m][filesize_approx<=?750m]/(bv*+ba/b)",
                    "--skip-download",
                    "--cache-dir=/data/yt-dlp-cache/",
                    "--cookies=/data/yt-dlp-cache/cookies.txt",
                    "--proxy=socks5://tor-socks-proxy:9150",
                    "--no-playlist",
                    "https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "2024.10.7",
                "end_ts": "2025-12-12T11:30:22.860853+00:00",
                "index_texts": [],
                "output": "media/",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:18.277378+00:00",
                "status": "succeeded"
            }
        ],
        "mercury": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/postlight-parser",
                    "https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "2.2.3",
                "end_ts": "2025-12-12T11:30:17.963238+00:00",
                "index_texts": null,
                "output": "mercury/",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:14.463028+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/readability-extractor",
                    "/tmp/tmpii4d8vfo",
                    "https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2025-12-12T11:30:14.274046+00:00",
                "index_texts": [
                    "I got interested in this after reading the Domain-Driven Design book by the same author, because of the historical perspective he applied to his treatment of modular design. This new book sounded like it would expand on that, and it didn\u2019t disappoint: it\u2019s well researched, building on the ideas of Parnas, Myers, Brooks, Conway, and Ousterhout, to produce something new and useful. Vlad Khononov does something that I find is fundamental to the software design discussion: he provides principled definitions to reduce our reliance on gut feeling when making decisions. That being said, while insightful, it\u2019s also a rather specialized book, one that I recommend to software design nerds but not necessarily to every programmer (as, say, I do recommend A Philosophy of Software Design). I may change this assessment if I find myself frequently using its heuristics to success.\n\nThe thesis of the book: despite its reputation, coupling is not something fundamentally bad that we need to remove but an attribute that we should manage strategically. Similar to essential complexity, a useful software system can\u2019t exist without some form of coupling of its components. An easy way to internalize this idea is remembering that cohesion is sometimes defined as good coupling.\n\nSoftware has a fractal nature, one can reason about modularity at the system, service, namespace, class, and function levels. At each level there are interfaces and implementation, module depth and complexity. Complexity is twofold: local and global. And since software is fractal, this level\u2019s global complexity becomes a higher level\u2019s local one. Naively splitting modules into smaller ones just pushes local complexity up, making the overall system more complicated. Our job then is not chasing local minima but striking a balance: a good enough trade-off that reduces total maintenance cost.\n\nTwo thirds of the book is spent on definitions: there are the usual suspects (complexity, modularity, coupling), some historically relevant concepts (structured design\u2019s module coupling, connasence), and a few new ones introduced by the author (integration strength, distance, volatility). These are used to compose heuristics (represented as formulas) to assess the modularity and balance of components in a system, to detect problems and hint at possible solutions. This activity is what the author calls balancing (and re-balancing) coupling. The final chapters show concrete applications of these heuristics on a series of case studies.\n\nTo a large extent, the process can be summarized as: if modules are strongly integrated (they share much knowledge), reduce their distance; if modules are weakly integrated (they don\u2019t share much knowledge), increase their distance. Notice how this differs from the notion that smaller, more spread out components necessarily yield simpler systems (a notion that leads to microservice hell and left-pad).\n\nBut the balancing is not limited to \u201cmoving things around\u201d. Given that software systems are fractal networks, one can introduce new levels of abstraction to allow them to grow beyond their structural limits\u2014and the cognitive load its maintainers can support. This is one of the strengths of the theory presented by the book: the same principles apply at all levels of a system; there\u2019s no hard distinction between software design and architecture\u2014not even between software systems and the human systems they integrate\u2014just different scales, different semantic levels: different perspectives.\n\nSummary\n\n\nA system has components and purpose. The interaction between the components (coupling) is necessary for the components to achieve the system\u2019s purpose. On a smaller scale, a component is almost always a subsystem in its own right.\n\nCoupling results from the components having to share knowledge, or lifecycles, or both.\n\nCoupling defines not only what knowledge is allowed to flow between the components but also what knowledge should never leave their boundaries. This makes coupling a core tool for designing modular software systems.\nThe higher the magnitude of coupling, the higher the likelihood of the coupled components having to change together.\n\n\n\nComplexity reflects the cognitive load a person experiences when interacting with a system. The greater the cognitive load, the more difficult it is to understand, control, predict, and change the behavior of the system.\n\nLocal complexity is the complexity of a single component\u2014the complexity of interactions happening inside it.\nGlobal complexity is the complexity of interactions between the system\u2019s components.\nThis distinction is subjective and depends on perspective. Global complexity turns into local when the system is observed from a higher level of abstraction.\n\n\n\nA module is a type of component designed to improve the flexibility of a system, allowing it to evolve to support future goals.\n\nA software module bounds a well-defined functionality, exposing it to other components through a public interface. Any logical or physical boundary within a software system can be designed as a module: a service, a namespace, an object, a function, etc.\nAn effective module hides decisions. If a decision has to be revisited, the change should only affect one module, the one that \u201chides\u201d it.\nAn effective module maximizes the knowledge it encapsulates, while sharing only the minimum that is required for other components to work with it.\n\n\n\nA system\u2019s design should not be evaluated by examining individual modules in isolation, but the relationships between them: how they are coupled. Different ways of coupling components share different types and amounts of knowledge. Some will increase complexity, while others will contribute to modularity.\n\nCoupling manifests across three dimensions: integration strength, distance, and volatility.\nThe higher the integration strength (the more knowledge shared across their boundaries), the higher the likelihood that modules will need to change in unison. When such cascading changes occur, distance signifies the effort required to implement them. Volatility represents how frequently these changes are anticipated to happen.\nWhen designing cross-component interactions, our goal is not to minimize the strength of coupling. The goal is a modular system: one that is simple to implement, evolve, and maintain. This can only be achieved by considering all three dimensions of coupling.\n\n\n\nIntegration strength models the type and extent of knowledge shared by coupled components. There are four levels of coupling strength:\n\nIntrusive coupling: integration through the upstream component\u2019s private interfaces or other implementation details. This makes the downstream component sensitive to all future changes in the upstream component.\nFunctional coupling: components implement closely related business functionalities. A change in the business requirements is highly likely to affect all coupled components.\nModel coupling: components using a shared model of the business domain. The evolution of the model requires changes in all coupled modules.\nContract coupling: components using an integration-specific shared model: a contract. The integration contract abstracts the details of the model used internally in the upstream component.\n\n\n\nDistance refers to the space knowledge \u201ctravels\u201d across coupled components. It affects the coordination and communication efforts needed to implement a change affecting the coupled components. Distance is influenced by several factors:\n\nThe physical location of the code: for example, it\u2019s easier to change coupled methods in a class than coupled methods across distributed systems. On the other hand, collocating otherwise unrelated functionalities couples their lifecycles, introducing collateral changes that wouldn\u2019t be necessary if they were separated.\nOrganizational structure: the greater the ownership distance (whether components are maintained by the same person, team, department, or organization), the higher the coordination effort.\n\n\n\nVolatility is a component\u2019s expected rate of change.\n\nOne way to model volatility is through Domain-Drive Design\u2019s subdomain types: core subdomains are expected to change more frequently than supporting and generic subdomains.\nInvesting in modularization isn\u2019t as beneficial for components that are not expected to change frequently.\n\n\nBalance refers to the optimal state of the three dimensions of coupling, in which the design increases the modularity of the system\u2019s volatile components. An unbalanced combination of these dimensions results in increased cognitive load and, consequently, increased complexity.\n\n\n\n-- there's global complexity when significant knowledge\n-- travels long distances\nglobal_complexity := strength() AND distance()\n\n-- there's local complexity when unrelated components\n-- are collocated\nlocal_complexity := NOT strength() AND NOT distance()\n\n-- modularity is the absence of local and global complexity\ncomplexity := local_complexity OR global_complexity\n            = NOT (strength() XOR distance())\nmodularity := NOT complexity\n            = strength() XOR distance()\n\n-- there's balance when the volatile components are modular\n-- and the complex components don't change\nbalance := modularity OR NOT volatility()\n         = (strength() XOR distance()) OR NOT volatility()"
                ],
                "output": "readability/",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:12.202327+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://olano.dev/blog/balancing-coupling/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-12T11:30:12.117650+00:00",
                "index_texts": null,
                "output": "[tl;dr] Balancing Coupling in Software Design | olano.dev",
                "pwd": "/data/archive/1765538996.362868",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-12T11:30:12.086977+00:00",
                "status": "succeeded"
            }
        ],
        "wget": []
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": "https://web.archive.org/web/20251212113027/https://olano.dev/blog/balancing-coupling/",
        "dom": "output.html",
        "favicon": "favicon.ico",
        "git": null,
        "media": "media/",
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "[tl;dr] Balancing Coupling in Software Design | olano.dev",
        "warc": null,
        "wget": null
    },
    "link_dir": "/data/archive/1765538996.362868",
    "newest_archive_date": "2025-12-12T11:30:22.908986+00:00",
    "num_failures": 0,
    "num_outputs": 9,
    "oldest_archive_date": "2025-12-12T11:29:58.704965+00:00",
    "path": "/blog/balancing-coupling/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_abid": "snp_01KC95685HA0DC406C01ZPS4DQ",
    "snapshot_id": "1528392d-2f1a-46a2-b61c-0d20ff6c91b7",
    "sources": [
        "/data/sources/1765538994-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1765538996.362868",
    "title": "[tl;dr] Balancing Coupling in Software Design | olano.dev",
    "url": "https://olano.dev/blog/balancing-coupling/"
}