Showcases 2: Multi-Market Orders on Faker Pools
Requires Pro (FlatFile, string Constant) — a Free-tier version of the same idea is Showcases 3
Problem statement
You’re testing an EU order pipeline. Customers come from Germany, France, and Spain, roughly 50/30/20 by volume, and the names and addresses need to look right for each market — a French name sitting in a German postcode is the kind of thing that makes a demo fall flat and lets encoding bugs hide until production.
Here’s the honest problem: SpiceGrinder’s bundled business-object data is US-centric. Given names come from SSA records, surnames from the 2010 US Census, and city_state_zip.csv is GeoNames’ US postal file. There is no de_DE name data in the box, and building forty more locale files would be a poor use of anyone’s afternoon.
Faker has dozens of locales. What Faker doesn’t have is any notion that a market mix should come out at 50/30/20, that a postcode belongs to the customer who has it, or that an order value should attach to that same customer. Each fake.name() and fake.city() call is independent, so holding them together is glue code you write, and then write again for the next schema.
Use each tool for the half it’s good at: Faker for the vocabulary, SpiceGrinder for the structure.
The model
Build one pool per market with Faker — a couple of hundred rows each is plenty — and commit them. A pool is a vocabulary, not a dataset; the volume comes from the model later, so it never needs to be large.
The model is the same Mix → branch shape as the bundled person model from Claims 2, where gender and given name are chosen together so they always agree. Here it’s market and customer: Mix picks a market by weight, and everything inside the chosen branch comes from that one draw. The market label and the customer are selected together, inside the same branch, so they can never disagree.
<?xml version="1.0" encoding="UTF-8"?>
<dataset seed="42">
<root node="Order"/>
<nodes>
<Append name="Order">
<input name="Customer"/>
<input name="ItemCount"/>
<input name="OrderValue"/>
</Append>
<Mix name="Customer">
<input name="GermanBranch" weight="0.50"/>
<input name="FrenchBranch" weight="0.30"/>
<input name="SpanishBranch" weight="0.20"/>
</Mix>
<Append name="GermanBranch">
<input name="DeLabel"/>
<input name="GermanPool"/>
</Append>
<Constant name="DeLabel" value="DE" type="string"/>
<FlatFile name="GermanPool" file="customers-de.csv" mode="unweighted" skipHeader="true"/>
<!-- FrenchBranch and SpanishBranch follow the same shape.
Abridged here for reading; the model won't load until all three
branches named by the Mix above actually exist. -->
<Poisson name="ItemCount" lambda="2.2"/>
<Lognormal name="OrderValue" mu="4.1" sigma="0.8"/>
</nodes>
</dataset>
Run it (samples/pro/software/orders-multi-locale.xml) and market, customer, and postcode always agree:
FR,Hortense Diallo,Bertrandboeuf,FR-95584,3,29.534151471601852
ES,Nicodemo Cabello Barrera,Toledo,ES-23236,3,15.782629571402822
ES,Ruperta Castillo Barreda,Sevilla,ES-09010,4,109.64989566069686
FR,Pierre Teixeira,Saint Frédéric-les-Bains,FR-80263,2,88.14631181927025
DE,Edelgard Wulf-Langern,Hersbruck,DE-66270,1,140.59989142221843
Why this shape works
The label goes inside the branch, not beside it. It would be simpler to emit a market code and a customer as two independent draws — and then nothing stops market DE pairing with a Spanish customer. Putting the Constant and the FlatFile in the same Append, under the same Mix input, makes the agreement structural rather than something the model just happens to get right.
Check that the weights actually hold. Declaring 0.50/0.30/0.20 is a claim, and claims are worth testing. Over 100,000 rows the model produced 50.16% / 29.81% / 20.03%. Generate a hundred thousand rows and count them yourself rather than trusting the attribute.
Watch the leading zeros. Faker produces 05130 in France and 09010 in Spain, and FlatFile parses numeric-looking cells as numbers — so a bare postcode loses its leading zero no matter how you quote it. The pools above prefix the country code (ES-09010), which makes the cell genuinely non-numeric and happens to be a real European postal convention. Verified: with the prefix the same seed produces the identical customers and order values, so only the representation changed.
Seed Faker too. Faker.seed(42) matters less than you’d think, since you commit the pool and the artifact is fixed either way — but it means a teammate regenerating it gets the same file instead of a confusing diff.
For US data you probably don’t want Faker here. SpiceGrinder’s bundled pools are real weighted Census and SSA distributions, which beat Faker’s uniform sampling for that market. This pattern earns its keep on the locales we don’t ship.