Repository navigation
Identify and name slices by their captures, like ArchUnit - #515
Open
alexanderlinne wants to merge 1 commit into
Open
alexanderlinne wants to merge 1 commit into
alexanderlinne wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## nest-slices-in-packages-option #515 +/- ##
==================================================================
+ Coverage 86.36% 86.48% +0.12%
==================================================================
Files 261 261
Lines 12623 12676 +53
Branches 1226 1232 +6
==================================================================
+ Hits 10902 10963 +61
+ Misses 1374 1366 -8
Partials 347 347 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
alexanderlinne
force-pushed
the
identify-slices-by-captures
branch
from
October 24, 2026 20:10
5b1ca9a to
676c0b6
Compare
alexanderlinne
marked this pull request as draft
October 25, 2026 19:39
A slice was identified by its name, a single string, and named after
what the pattern captured with nothing to mark it as a slice. A custom
SliceAssignment had no way to say what its slice consists of, and a
slice name read like a namespace.
Identify a slice by its parts, as ArchUnit's SliceIdentifier does: for
a slice pattern, the values its capture groups captured, in group order.
SliceIdentifier.Parts holds them, and equality, hash code, CompareTo and
therefore the grouping in SliceAssignment.Apply compare the parts (and
Ignored) alone. The matcher still captures a single value per type, so
every pattern slice has one part and groups exactly as before.
SliceIdentifier.Of(IEnumerable<string>) creates a slice with several
parts; Of(string) is the same slice as Of(new[] { part }).
Name every slice after its parts like ArchUnit's default: "Slice "
followed by the parts joined with " - ":
App.(*) App.Orders Slice Orders
App.(**) App.Orders.Web Slice Orders.Web
Of(new[] { "Orders", "Http" }) Slice Orders - Http
The prefix keeps a name from being mistaken for a namespace. It applies
to every slice, including SlicedBy and custom SliceAssignments, and it
is what failure messages and diagrams show, flat or nested.
SliceIdentifier no longer derives from StringIdentifier: the parts are
all that identifies a slice. Violation stores need a string key, which
SlicesShould takes from the slice's name when it reports a violation, so
a store holds what failure messages show, e.g. "Slice Orders", as
ArchUnit's stores, which keep violation messages, do.
Hand-built parts that contain " - " can share a name, and thus a key,
with another slice: Of(new[] { "A - B" }) and Of(new[] { "A", "B" }) are
different slices, both named "Slice A - B". Parts captured by a pattern
never contain " - ", and ArchUnit has the same limitation. The exporter
rejects two slices that would be drawn under the same name, instead of
drawing them as one node.
The guide's "Cycle Rule" section becomes "Slice Rules", with how slices
are named and frozen, and the NotDependOnEachOther rule.
Breaking changes:
- Slices are named "Slice ..." from their parts, which changes every
slice failure message and slice diagram label.
- Frozen slice violations are stored by the slice's name, so stores
written before no longer match and have to be regenerated.
- New are SliceIdentifier.Parts and SliceIdentifier.Of(IEnumerable).
- SliceIdentifier no longer derives from StringIdentifier, so its
Identifier field is gone, and ToString() returns the slice's name.
Signed-off-by: Alexander Linne <alexander.linne@tngtech.com>
alexanderlinne
force-pushed
the
identify-slices-by-captures
branch
from
October 29, 2026 21:35
676c0b6 to
d4ef3a8
Compare
alexanderlinne
marked this pull request as ready for review
October 29, 2026 21:44
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A slice is identified by its name, a single string, and named after what the pattern captured, with nothing to mark it as a slice:
SliceAssignmenthas no way to say what its slice consists of.This PR settles identity and naming while
main's matcher still captures exactly one value per type, so the PR changes only names, not which types form a slice. PR 4 then only has to produce several values.What changes
Identity. A slice is identified by its parts, as
SliceIdentifieris in ArchUnit ("equal if and only if their parts are equal"). For a slice pattern, the parts are the values its capture groups captured, in group order.SliceIdentifier.Partsholds them, and the following compare the parts (andIgnored) alone:CompareTo,SliceAssignment.Apply.SliceIdentifier.Of(IEnumerable<string>)creates a slice with several parts;Of(string)is the same slice asOf(new[] { part }). Every pattern slice still has one part here, so every rule groups exactly as before.Names. Every slice is named after its parts like ArchUnit's default,
"Slice " + string.Join(" - ", Parts):App.(*)overApp.OrdersOrdersSlice OrdersApp.(**)overApp.Orders.WebOrders.WebSlice Orders.WebOf(new[] { "Orders", "Http" })Slice Orders - HttpThe
Sliceprefix keeps a name from being mistaken for a namespace. It is ArchUnit's default, so messages read the same in both libraries. A laterNamingSlices("$2 of $1")would replace the same thing ArchUnit'snamingSlicesreplaces. The name applies to every slice, includingSlicedByand customSliceAssignments, and it is what failure messages and diagrams show, flat or nested:Every changed snapshot changes only labels and aliases; no slice and no arrow differs. Names with spaces aren't valid PlantUML ids, so these slices get an alias such as
Slice_Slice1. That, and bracketing component names in every arrow, comes from the fixes already merged in #507–#510.Freezing.
SliceIdentifierno longer derives fromStringIdentifier: the parts are all that identifies a slice. Violation stores need a string key, whichSlicesShouldtakes from the slice's name when it reports a violation, e.g.Slice Orders. A store thus holds what failure messages show, as ArchUnit's stores do, which keep violation messages.Until now, a slice was stored by its bare name, e.g.
Orders, so existing stores of slice rules no longer match and have to be regenerated. Since this PR changes every slice failure message anyway, and PR 4 changes which slices some rules produce, the stores are re-frozen once, together with the rest of the stack. The stores inFreezeTestsare updated accordingly.Hand-built parts that contain
-can share a name, and thus a key, with another slice:Of(new[] { "A - B" })andOf(new[] { "A", "B" })are different slices, both namedSlice A - B. Parts captured by a pattern never contain-, and ArchUnit has the same limitation. The exporter rejects two such slices in one diagram with anArgumentExceptionnaming both slices' parts, as they would be drawn under the same name; until this PR, two distinct slices couldn't share a name.Guide. The "Cycle Rule" section becomes "Slice Rules": how slices are named, how they are frozen, and the
NotDependOnEachOtherrule next toBeFreeOfCycles. Like the code, the guide describes slices on their own terms and doesn't refer to ArchUnit.Breaking changes
Slice …after their parts, which changes every slice failure message and slice diagram label.SliceIdentifier.PartsandSliceIdentifier.Of(IEnumerable<string>).SliceIdentifierno longer derives fromStringIdentifier, so itsIdentifierfield is gone, andToString()returns the slice's name.Not in this PR
An ArchUnit-style
NamingSlices("$2 of $1"), so that users can choose slice names themselves. It would be a non-breaking addition: slices are identified by their parts, not their names, and the exporter already rejects two slices that would be drawn under the same name. As in ArchUnit, renaming the slices of a frozen rule would mean re-freezing it.How the images were made
They render the
BuildUmlBySlices_SingleAsteriskandBuildUmlBySlicesNested_SingleAsterisksnapshots at #513 and at this PR, with PlantUML 1.2025.4 and Graphviz, with the remote!includeof C4-PlantUML replaced by PlantUML's bundled copy (!include <C4/C4_Container>).