Repository navigation
Design for one product with two native apps #46
Replies: 5 comments 1 reply
|
@pbienkowski : I think I need a bit more context here. Whenever we follow the design first model [/design-blueprint], it goes through design stages Level 1 to 4, and it also accounts for the existing codebase, meaning it defines the interactions, capabilities, components and eventually the contract. If you are saying the design blueprint document needs to be the same for two different codebases, are you saying that both codebases, Swift and Kotlin, should have the same structure, the same files and the same folder structure? That would only make sense if that is the case, since the design blueprint is meant to be the glue between the requirement and the codebase. In Lattice, the flow is that you first create the requirement using [ /requirement-forge], then the [/design-blueprint], and then [/code-forge]. The design blueprint accounts for the requirement and the current state of the codebase at the time it is created. If you create a design blueprint today, but the implementation happens a month or two later, the codebase will likely have moved on from what it was when the design was created. That is worth factoring in as well. Let me know if that gives you the context you were looking for. |
|
Thanks a lot for the detailed answer, @techygarg - and sorry, my question was not precise enough :( The case I described is a specific example of a broader problem: implementing the same feature (or a whole system) on different architectures. Of course the Kotlin and Swift codebases will not be identical - they are different technologies with different structures. The same thing happens, for example, when one feature needs both a frontend and a backend. If I understand the levels correctly, this is how I see it:
Your point about the codebase moving on also fits this split: the L3-L4 for the second platform should be created when that platform actually picks up the feature, against its current codebase - not a month earlier. So having one full blueprint per technology is not ideal, because L1-L2 would be duplicated and could drift apart. And since the technologies move at different speeds, we also need to know at any time which of them has already implemented a given blueprint. So my question is: what is the recommended way to describe multiple technologies in Lattice blueprints - and to track which technology has already implemented a given blueprint? For example:
I recently tried to get around this challenge by including separate statuses for iOS and Android in the “Features” section, and by using anonymized language (without technical details) in the blueprint. Thanks again! |
|
@pbienkowski Got it, that makes more sense now. Frontend + backend is the same problem, so it's a good one to sort out. One correction first, since it changes the answer. The levels are L1 Capabilities, L2 Components, L3 Interactions, L4 Contracts. Only L1 is tech-agnostic. L2 already maps components to existing modules in the codebase, and L3/L4 build on that. And L1 is just a handful of capabilities with no technical detail, so it's pretty much a restatement of the requirement. So my take is that the requirement is your single source of truth, not the blueprint. Keep one requirement for both platforms, and create a separate blueprint in each codebase when that platform picks up the feature. Your idea of per-platform status in the feature file is fine. Lattice never writes status to the requirement on purpose, so that part is yours to manage. Each blueprint also has its own draft/approved status, so each repo shows where it stands. I wouldn't do one blueprint with per-platform sections. A blueprint has a single status and code-forge only runs on an approved one, so mixing two platforms in it gets messy. A shared L1-L2 doc would mostly duplicate the requirement. I'd also drop the anonymized wording. Code-forge needs concrete components and contracts, and a blueprint generic enough to share is too vague to build from. The real drift risk is behaviour decisions made while building the first platform (edge cases, error handling, UX tweaks) that never go back into the requirement. Then the second platform designs from an outdated spec. Simple rule: if it changes what the product does, update the requirement. If it only changes how one platform builds it, it stays in that blueprint. When the second platform starts, it's worth skimming the first platform's blueprint and decision log too. For frontend + backend in the same repo, give the blueprints different names (e.g. checkout-web and checkout-api) so they don't clash. This also showed me a gap. The blueprint adds a link back to itself in the requirement's Links section, and making that one link per platform would give you the tracking for free. I'll look into it. |
|
@techygarg Thank you! Here is my summary, to make sure I understood it right: A few follow-up questions:
|
|
@pbienkowski Your summary is spot on. 1. Timing: create the blueprint right before code-forge, on every platform including the first. One made early just goes stale and you end up designing twice. 2. One feature across several codebases: there's no fixed rule. It depends a lot on how your code is organised. Some options:
3. "Diverged" status: I'd keep it simple. Version hashes or a divergence status add tracking that someone has to maintain. If the requirement changes, update the blueprint against the new requirement and approve it again. That flow already exists. 4. Naming: use a suffix, More generally, it's hard to set fixed rules for this. Models keep getting better and what works changes with them. The guardrails (levels, approval gates, contracts) stay at the core, but around them there's room to experiment. We haven't tried every one of these setups, so please share what works for you. This thread has also given me an idea: a config option where you can add a few lines of your own instructions per molecule. The molecule would read them alongside its standard rules, so setup-specific habits like your naming can be set once instead of repeated every session. Roughly like this in additional_instructions:
requirement_forge:
- One requirement per feature, shared by iOS and Android. Never platform-specific.
design_blueprint:
- Suffix the blueprint with the platform: {feature}-ios or {feature}-android.
- Before designing, read the other platform's blueprint and decision log if it exists.
code_forge:
- If a change affects what the product does, flag it so the requirement gets updated.These would add to the standard rules, never override gates or approvals. Still an idea, I'll explore it. Would this cover your case? One question from my side: how are you using Lattice? Personal projects or at work, on your own or with a team? From folks I've talked to directly, it's being used everywhere from solo devs and startups to large teams at multinationals, so knowing your setup helps me shape answers like these. |
Uh oh!
There was an error while loading. Please reload this page.
Context
I'm using Lattice (the design-first skill, Levels 1-4) on one product that ships as two native apps: one in Swift (iOS) and one in Kotlin (Android). Both apps are meant to stay functionally identical.
The catch: the two apps move at different speeds. A feature is designed and built on one platform first, and the other platform picks it up later - often a month or more. So at any point in time, a design can be implemented on one app and still pending on the other.
What I'd like
One product, one source of truth for design - without the two platforms drifting apart, and without redoing the design work when the second platform catches up.
Question
What's the recommended way to use Lattice for one product with two native implementations that don't move in sync - so the design stays one source of truth, and the second platform can implement it later without redoing the design work?
All reactions