r/softwarearchitecture 17h ago

Tool/Product Our team kept running into conflict loops with complex distributed architecture, so we built DevOS as a shared codebase intelligence and engineering context layer.

0 Upvotes

Link: https://devos.zerohive.ai/

Our engineering team at Zerohive works on large codebases, and we use different coding agents (Claude, Codex, Cursor) basis individual preference.

We kept running into problems where one person's agent will end up rewriting or undoing decisions made by someone else. It led to agents re-introducing bugs which we'd fixed last month. We kept reaching out to each other offline to ask "Hey, why did we store xyz in redis instead of persisting on DB" when the agent proposed redoing the architecture.

We spent months collaborating by making ARCHITECTURE.md, DECISIONS.md, LESSONS.md, ADRs etc and shared skill libraries - but they were soon ineffective as the codebase scaled. We also tried code memory platforms but they could only fetch the 'what' but not the 'why', no provenance on architecture or code patterns so reintroducing bugs problem wasn't solved for complex codebases.

So we built DevOS.

DevOS understands the codebase, correlates the decisions made in the chat sessions with final code outcome, and has a deep understanding of the why behind the code and the architecture. It understands architectural choices, alternatives considered, tradeoffs made and final decisions taken w.r.t code or architecture.

Exposed to coding agents as an MCP, DevOS searches files, symbols, decisions and dependencies in parallel so that models make better changes in fewer iterations and exponentially lesser tokens which otherwise would be spent by agents in grepping the codebase.

Agents can now understand the architecture and codebase better, along with the rationale that went behind the architecture, and context can be shared between teammates within their coding agents.

Use lesser tokens, collaborate better. Completely free to try, no paid tier.

Link: https://devos.zerohive.ai/


r/softwarearchitecture 17h ago

Discussion/Advice SCS vs modular monolith for a small ERP team?

3 Upvotes

We are a small team of 3 to 4 developers building a custom ERP for a few customers.

Our current system has basically become a big ball of mud.

Before I joined, there was already a complete rewrite with the goal of making things more modular, but over time it ended up in pretty much the same place:

  • modules, but no real boundaries
  • everything can access everything
  • one database and one schema
  • lots of foreign keys and relations across modules
  • almost no events
  • a huge common module where more and more shared stuff ended up

Now my boss wants to start from scratch again.

He recently came across Self Contained Systems (SCS) and thinks this could solve the problem.

The idea would be completely separated systems with their own:

  • database
  • deployment
  • backend
  • UI

Communication between systems would only happen through defined contracts.

I understand why he likes it. The boundaries are hard to break. A developer working on one SCS cannot simply access the database or internal code of another one.

My concern is that we are only 3 to 4 developers building a fairly traditional ERP. We don't really need independent scaling or independent deployment for organizational reasons.

I'm worried we could end up with a distributed big ball of mud, while also adding things like:

  • network communication everywhere
  • eventual consistency
  • harder transactions
  • retries and failure handling
  • contract versioning
  • more infrastructure
  • harder debugging and local development

I would rather go with a modular monolith with strict boundaries.

One deployment, but properly separated domains/modules. No direct access to another module's internals, no cross module repositories, explicit contracts, events where they make sense, and possibly separate DB schemas to reinforce ownership.

We could also use in process events initially without introducing Kafka or another broker.

My boss's main argument is basically:

And I think he has a valid point. Our previous attempt clearly failed.

At the same time, I don't think the previous system ever had real or enforced module boundaries in the first place.

One problem for me personally is that I don't have a huge amount of architecture experience yet, especially with running microservices or SCS in production. I understand the theoretical downsides, but I lack the real world experience to confidently argue which of those downsides will actually matter for a small team like ours.

My boss has around 30 years of development experience, so I also don't want to argue against his approach just because I personally prefer another architecture.

What would you choose for a team and product like this?

Am I underestimating the advantages of SCS here?

Or are we introducing distributed system complexity mainly to enforce architectural discipline that could also be enforced inside a modular monolith?

I'm especially interested in experiences from people who have worked with both approaches in smaller teams.


r/softwarearchitecture 1h ago

Article/Video OpenAI Details GPT-Live’s Architecture for Continuous Stateful Voice Interaction

Thumbnail infoq.com
Upvotes

OpenAI recently published an engineering account of GPT-Live. It described how they designed the system to maintain continuous voice interaction while separating latency-sensitive media processing from broader application work. The live path contains the media pipeline and inference loop, while delegation, tool use, persistence, and other application logic run behind an asynchronous RPC boundary.


r/softwarearchitecture 23h ago

Article/Video 50 shades of system design

Thumbnail newsletter.systemdesign.one
54 Upvotes

r/softwarearchitecture 14h ago

Article/Video Invariants, boundaries, and when to crash on purpose. Reliability lessons from building a database in Go

Thumbnail tracewayapp.com
3 Upvotes

I've been working on a database and it has forced me to reconsider what reliable means. A service can keep answering requests while its state is already corrupted. Most teams I've seen would consider a service is reliable as long as it's responding to requests, but that is wrong.

I’ve started thinking about reliability in terms of invariants: properties that must remain true. A balance can’t become negative. A cache’s counter must match its actual entries. A secondary index must stay consistent with its source data.

These invariants usually break because an operation has multiple side effects, writes to memory, disk, or another service, and a failure occurs between them.

This is where architecture matters. Every system has recovery boundaries: an operation, a transaction, a request, a job, a worker, or the entire process.

A boundary should recover only if it can guarantee that all its side effects completed, were rolled back, or can be safely discarded. If it can’t make that guarantee, recovering may simply allow the system to continue with invalid state.

Sometimes the safest response is to crash your whole process. Sometimes crashing would turn a bad request into an outage. Neither “always recover” nor “always crash” is a useful rule.

The real question is: what is the narrowest boundary at which you can prove the system is still consistent?

Anyhow I've written a blog post about it. I hope at least some find it interesting or helpful. It's focused on Go specifically but a similar pattern works for other languages with more of a try/catch syntax.

Let me know if you use a similar approach or something totally diff. Thinking in terms of invariants is pretty new to me and I'm looking to learn more from other peoples experiences.

Disclaimers: I wrote the article, it is not AI slop regardless of what it sounds like. Also I am the one building Traceway and the blog is on Traceway's website.


r/softwarearchitecture 13h ago

Article/Video SysML v2 Deep Dive: Lesson 16 - Composite vs. Reference (Mastering Part Ownership)

Enable HLS to view with audio, or disable this notification

5 Upvotes

Hi r/softwarearchitecture,

We are back with Lesson 16 of our technical deep dive into the SysML v2 standard.

In our previous lesson, we made values physically meaningful with types and units. Today, we are modeling who owns the physical hardware those values belong to. In software engineering, the distinction between composition (strong lifecycle binding) and aggregation (loose reference) is foundational. SysML v2 finally brings rigorous semantics to this concept for system models, where one wrong keyword can accidentally double a spacecraft's mass budget.

I’ve uploaded the full video lesson directly to this post so you can watch the workflow right here.

1. The SysML v1 Ambiguity

In SysML v1, whole-part relationships were typically drawn with diamonds. Shared aggregation (the hollow diamond) had no agreed-upon execution semantics in the underlying UML specification, meaning different tools and teams interpreted it differently. Composite aggregation (the filled diamond) made a stronger lifetime claim, but tool support for verifying that claim was inconsistent.

2. The v2 Shift: Ownership and Lifetime Semantics

SysML v2 makes ownership and lifetime a strictly enforceable part of the model's formal semantics. The core rule is: a nested occurrence is composite by default. Add the ref keyword, and it becomes a reference to something owned elsewhere.

Three technical distinctions make this reliable:

  • ref is for Occurrences, Not All Usages: The composition rule applies to occurrences—things with physical or temporal lifetimes like parts, items, actions, connections, and ports. Attributes represent data values (numbers, strings) and are referential by definition, making ref attribute legal but technically redundant.
  • Composition is a Lifetime Claim: A composite part's physical existence is tied to its parent's lifetime. If the whole is destroyed, the composite occurrence is destroyed with it. A satellite does not compose its ground station, its orbit, or its operator.
  • The Architect's Test: When in doubt, ask: "If I deleted the parent system from my model, would this nested element physically cease to exist in the real world?"If yes, use a composite part. If no, use a referential ref part.

3. The Multiplication Trap & Redefinition

Consider a satellite with one shared power bus. If you instantiate standard subsystem templates (like Comms or Thermal) that each contain a default part bus, those internal buses evaluate as composite by default. A script crawling this model will count the main satellite bus plus the internal subsystem buses, quietly multiplying your mass rollup with phantom components.

The fix is to redefine the inherited composite bus as a reference and bind it to the single real sibling bus. (Note: In SysML v2, binding implies symmetrical equality, not an instruction to evaluate and copy a value in one direction).

Code snippet

package SatelliteSystem {
    part def PowerBus;

    part def CommsSubsystem {
        part bus: PowerBus; // A composite bus by default
    }

    part def Satellite {
        // 1. The single real physical bus owned by the satellite (Composite)
        part powerBus: PowerBus;

        // 2. Instantiate the subsystem, redefining its internal bus as a reference bound to 'powerBus'
        part comms: CommsSubsystem {
            ref part :>> bus = powerBus; 
        }
    }
}

Visualizing this: In SysML v2, composite parts appear nested with a solid border (or a filled diamond edge), while reference parts use a dashed border (or a hollow diamond edge).

4. SysML v1 vs. SysML v2

Modeling Concept SysML v1 SysML v2
Composite Relationship Represents coincident, exclusive lifetime using a filled diamond. Represented textually by a nested usage (e.g., part engine). Graphically uses internal nesting with a solid border or a filled diamond edge.
Referential Relationship Represents a shared or non-composite association using a hollow diamond, with execution semantics left undefined by UML. Represented textually using the ref modifier (ref part station;). Graphically uses internal nesting with a dashed border or a hollow diamond edge.
Redefinition & Binding Reference associations drawn as shared aggregation paths on a Block Definition Diagram. Declared inline by redefining the inherited usage and binding it to a sibling feature using :>> and = syntax.
Value Equivalence (Parametrics) Handled by instantiating a Constraint Property and connecting value properties to it via Binding Connectors. Handled directly via declarative inline bindings (e.g., attribute a = b;) or explicit bind connections.

Next lesson, we are moving from architecture to domain-specific meaning with metadata def, which lets you mark a requirement as safety-critical without building an entire SysML v1 Profile first.

For the software architects here: This maps heavily to composition vs. aggregation in OOP design. Have you ever encountered a system bug because a shared component's lifecycle was accidentally treated as an exclusively owned composite? Let's discuss in the comments!


r/softwarearchitecture 3h ago

Article/Video How to secure SSH and Postgres with Warpgate

Thumbnail packagemain.tech
3 Upvotes

r/softwarearchitecture 21h ago

Discussion/Advice Long-term university system in PHP, microservices or modular monolith, given high staff turnover?

Thumbnail
2 Upvotes