---
title: 'Conway Yasası'
source: 'https://academia.sh/tr/kurslar/surec-ve-ekip/conway-yasasi'
course: 'Süreç, Ekip ve Teslimat'
language: tr
updated: '2026-08-17T18:10:35+00:00'
license: 'CC BY-SA 4.0'
---

# Conway Yasası

İletişim yapısının modül yapısına yansımasının ölçülmesi: aynı modül grafiğine iki ayrı ekip bölünmesinin bindirilmesi, modül başına ekip ve ekip sınırını geçen bağ sayımı, bu bağların iletişim mesafesine göre dağılımı, iletişim yolu olmayan ekipler arasında duran bağların bulunması ve aynı iş kalemi kümesinin iki bölünmedeki el değiştirme, bekleme ve yeniden iş sayıları.

Önceki konu sürecin biçimini seçti, akışı sınırladı ve hata bulma gecikmesini kısalttı. Bütün o
ölçümlerin ortak bir sessiz girdisi vardı: işin **kimden kime geçtiği** veri olarak alındı; o
sınırın nereden geldiği hiç sorulmadı. Bu ders o soruyu sorar.

**Conway yasası**, bir sistemi üreten kuruluşun iletişim yapısı ile ürettiği sistemin yapısı
arasında bir benzerlik olduğunu söyleyen terimdir. Terim tek başına ölçü vermez; ölçü iki
grafik yan yana konarak kurulur — **modül grafiği** (hangi modül hangi modüle bağımlıdır) ve
**iletişim grafiği** (hangi ekibin hangi ekiple düzenli bir kanalı vardır).

Aynı türden bir ithal grafiği daha önce başka amaçlarla okundu: katman kuralı denetlendi, sınır
ihlali sayıldı. **Buradaki sayım o değildir.** Grafiğe bindirilen şey kural değil **ekip
sınırıdır**. Through-line **bölgesel kütüphane ağıdır** ve kurgudur.

## İki Grafik, Tek Kod Tabanı

**ET1 — kod tabanı on yedi modülden ve kırk üç bağımlılık bağından oluşur.** Gerekçe: örtüşme ancak
bağ sayısının ekip sayısından çok büyük olduğu bir grafikte anlam taşır.

**ET2 — bileşen odaklı bölünmede beş ekip vardır, her ekip bir teknik bileşenin sahibidir ve dört
düzenli kanal bulunur.** **ET3 — akış odaklı bölünmede altı ekip vardır, her ekip bir hizmet
akışının sahibidir ve dokuz kanal bulunur.** Gerekçe: iki bölünme aynı on yedi modülü paylaştırır,
yani **modül grafiği iki koşumda da bit bit aynıdır**; değişen tek şey sınırın yeridir.

**ET4 — iş yükü on iki kalemdir; her kalem modülleri işin izlediği sırayla listeler ve ilk modül
isteğin düştüğü yerdir.** **ET5 — bir modülün "değiştiren ekipleri" sahibi ile o modüle dokunan
kalemleri başlatan ekiplerin birleşimidir.** Gerekçe: kurumda kod herkese açıktır; kalemi başlatan
ekip gerektiğinde başka ekibin modülünde değişiklik yazar ve sahibinden gözden geçirme ister.

Aşağıdaki blok bir **modeldir**; gerçek bir kod tabanından okunmuş değildir.

```js
// kur.mjs — modul grafigi ile iletisim grafigi yan yana konur, ortusme olculur (model)
import { writeFileSync } from "node:fs";

// ET1 — 17 modul; "a: b c" satiri a modulunun b ve c modullerini ithal ettigini soyler
const ITHAL = {
  subeUcu: "oduncAkisi ucretAkisi rezervasyonAkisi ortakBicim",
  personelUcu: "uyelikAkisi oduncAkisi ucretAkisi ortakBicim",
  ceptenErisim: "oduncAkisi rezervasyonAkisi katalogKoprusu ortakBicim",
  oduncAkisi: "oduncKurali katalogKurali depoErisimi bildirimKuyrugu ortakBicim",
  ucretAkisi: "ucretKurali depoErisimi bildirimKuyrugu ortakBicim",
  uyelikAkisi: "uyelikKurali kimlikKoprusu depoErisimi ortakBicim",
  rezervasyonAkisi: "oduncKurali katalogKoprusu depoErisimi bildirimKuyrugu ortakBicim",
  oduncKurali: "ortakBicim", ucretKurali: "oduncKurali ortakBicim",
  katalogKurali: "ortakBicim", uyelikKurali: "ortakBicim",
  depoErisimi: "olayGunlugu ortakBicim", katalogKoprusu: "katalogKurali ortakBicim",
  kimlikKoprusu: "ortakBicim", bildirimKuyrugu: "olayGunlugu ortakBicim",
  olayGunlugu: "ortakBicim", ortakBicim: "",
};
const M = Object.keys(ITHAL);
const KENAR = Object.entries(ITHAL)
  .flatMap(([a, s]) => (s ? s.split(" ").map((b) => [a, b]) : []));

// ET2 — bilesen odakli bolunme: bes ekip, her ekip bir teknik bilesenin sahibi
const A = { ad: "A (bilesen odakli)", bolunme: {
  arayuz: "subeUcu personelUcu ceptenErisim",
  akis: "oduncAkisi ucretAkisi uyelikAkisi rezervasyonAkisi",
  kural: "oduncKurali ucretKurali katalogKurali uyelikKurali",
  altyapi: "depoErisimi katalogKoprusu kimlikKoprusu bildirimKuyrugu olayGunlugu",
  ortak: "ortakBicim" },
  kanal: "arayuz-akis akis-kural akis-altyapi kural-altyapi" };

// ET3 — akis odakli bolunme: alti ekip, her ekip bir hizmet akisinin sahibi
const B = { ad: "B (akis odakli)", bolunme: {
  deneyim: "subeUcu personelUcu ceptenErisim",
  odunc: "oduncAkisi oduncKurali rezervasyonAkisi depoErisimi",
  ucret: "ucretAkisi ucretKurali",
  uyelik: "uyelikAkisi uyelikKurali kimlikKoprusu",
  katalog: "katalogKurali katalogKoprusu",
  platform: "ortakBicim olayGunlugu bildirimKuyrugu" },
  kanal: "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-ucret odunc-katalog " +
    "odunc-platform ucret-platform uyelik-platform katalog-platform" };

// ET4 — on iki is kalemi; moduller isin izledigi sirayla, ilki istegin dustugu yerdir
const KALEM = [
  ["gecikme ucreti orani", "ucretAkisi ucretKurali subeUcu ortakBicim"],
  ["rezervasyon iptali", "ceptenErisim rezervasyonAkisi oduncKurali bildirimKuyrugu"],
  ["uyelik hatirlatmasi", "uyelikAkisi uyelikKurali bildirimKuyrugu personelUcu"],
  ["katalog kaydinda alan", "katalogKoprusu katalogKurali ortakBicim ceptenErisim"],
  ["odunc suresi uzatma", "oduncAkisi oduncKurali subeUcu"],
  ["kimlikte ikinci adim", "kimlikKoprusu uyelikAkisi personelUcu ortakBicim"],
  ["ucret iadesi kaydi", "ucretAkisi depoErisimi olayGunlugu"],
  ["sube gecikme raporu", "personelUcu depoErisimi oduncAkisi"],
  ["bildirim metni bicimi", "bildirimKuyrugu ortakBicim"],
  ["rezervasyon sirasi", "ceptenErisim rezervasyonAkisi subeUcu"],
  ["odunc kurali istisnasi", "oduncKurali ucretKurali oduncAkisi ucretAkisi"],
  ["olay gunlugune alan", "olayGunlugu ortakBicim depoErisimi"],
];

function kur({ ad, bolunme, kanal }) {
  const sahip = {}, E = Object.keys(bolunme), kom = Object.fromEntries(E.map((e) => [e, []]));
  for (const [e, ms] of Object.entries(bolunme)) for (const m of ms.split(" ")) sahip[m] = e;
  for (const k of kanal.split(" ")) {
    const [x, y] = k.split("-");
    kom[x].push(y); kom[y].push(x);
  }
  const d = {};                                  // iletisim grafiginde en kisa yol; yol yoksa -1
  for (const s of E) {
    d[s] = Object.fromEntries(E.map((e) => [e, -1]));
    d[s][s] = 0;
    for (let q = [s]; q.length; ) {
      const u = q.shift();
      for (const v of kom[u]) if (d[s][v] < 0) { d[s][v] = d[s][u] + 1; q.push(v); }
    }
  }
  // ET5 — kod herkese acik: kalemi baslatan ekip gerektiginde baska ekibin modulunu degistirir
  const deg = Object.fromEntries(M.map((m) => [m, new Set([sahip[m]])]));
  for (const [, ms] of KALEM) for (const m of ms.split(" ")) deg[m].add(sahip[ms.split(" ")[0]]);
  return { ad, bolunme, sahip, d, deg: Object.fromEntries(M.map((m) => [m, [...deg[m]]])) };
}

const S = [kur(A), kur(B)];
writeFileSync("ag.json", JSON.stringify({ M, KENAR, KALEM, S }));

const olc = (s) => {
  const dis = KENAR.filter(([a, b]) => s.sahip[a] !== s.sahip[b]);
  const uzak = (f) => dis.filter(([a, b]) => f(s.d[s.sahip[a]][s.sahip[b]])).length;
  const ek = (n) => M.filter((m) => s.deg[m].length >= n).length;
  return {
    "ekip sinirini gecen modul bagi": `${dis.length}/${KENAR.length}`,
    "  iletisim mesafesi 1 olan ekipler arasi": uzak((u) => u === 1),
    "  iletisim mesafesi 2 olan ekipler arasi": uzak((u) => u === 2),
    "  ILETISIM YOLU OLMAYAN ekipler arasi": uzak((u) => u < 0),
    "birden cok ekibin degistirdigi modul": ek(2),
    "  uc ve daha cok ekibin degistirdigi modul": ek(3),
    "modul basina ekip ortalamasi":
      (M.reduce((t, m) => t + s.deg[m].length, 0) / M.length).toFixed(2),
  };
};

const O = S.map(olc);
console.log(`${M.length} modul, ${KENAR.length} bag, ${KALEM.length} is kalemi\n`);
console.log(`${"olcu".padEnd(42)}${S.map((s) => s.ad.padStart(20)).join("")}`);
for (const k of Object.keys(O[0]))
  console.log(`${k.padEnd(42)}${O.map((o) => String(o[k]).padStart(20)).join("")}`);
for (const s of S) {
  const c = {};
  for (const [a, b] of KENAR)
    if (s.d[s.sahip[a]][s.sahip[b]] < 0) {
      const k = `${s.sahip[a]}->${s.sahip[b]}`;
      c[k] = (c[k] ?? 0) + 1;
    }
  console.log(`\n${s.ad} — uc ve daha cok ekibin degistirdigi: ` +
    M.filter((m) => s.deg[m].length >= 3).map((m) => `${m}(${s.deg[m].length})`).join(", "));
  console.log(`  iletisim yolu olmayan ekipler arasinda duran bag: ` +
    (Object.keys(c).length ? Object.entries(c).map(([k, n]) => `${k} ${n}`).join(", ") : "yok"));
}
```

```
17 modul, 43 bag, 12 is kalemi

olcu                                        A (bilesen odakli)     B (akis odakli)
ekip sinirini gecen modul bagi                           40/43               32/43
  iletisim mesafesi 1 olan ekipler arasi                    23                  27
  iletisim mesafesi 2 olan ekipler arasi                     1                   5
  ILETISIM YOLU OLMAYAN ekipler arasi                       16                   0
birden cok ekibin degistirdigi modul                        15                  12
  uc ve daha cok ekibin degistirdigi modul                   6                   4
modul basina ekip ortalamasi                              2.24                2.06

A (bilesen odakli) — uc ve daha cok ekibin degistirdigi: personelUcu(3), oduncAkisi(3), oduncKurali(3), depoErisimi(3), bildirimKuyrugu(3), ortakBicim(3)
  iletisim yolu olmayan ekipler arasinda duran bag: arayuz->ortak 3, akis->ortak 4, kural->ortak 4, altyapi->ortak 5

B (akis odakli) — uc ve daha cok ekibin degistirdigi: subeUcu(3), depoErisimi(4), bildirimKuyrugu(3), ortakBicim(4)
  iletisim yolu olmayan ekipler arasinda duran bag: yok
```

## Örtüşme Nerede Bozulur

Tablonun en keskin satırı ortadadır. Bileşen odaklı bölünmede **on altı modül bağı, iletişim
grafiğinde birbirine hiç bağlı olmayan iki ekip arasında durur** — kırk üç bağın üçte birinden
fazlası; akış odaklı bölünmede sayı sıfırdır.

Son çıktı satırları bu on altı bağın nereden geldiğini adlandırır: hepsi `ortak` ekibi ile diğer
dört ekip arasındadır. `ortak` tek modülün — `ortakBicim` — sahibidir ve hiçbir iletişim kanalı
yoktur; istekler ona yazılı bir sıradan ulaşır. Modül grafiğinde ise `ortakBicim` on beş modül
tarafından ithal edilir. **Kod tabanının en çok bağımlı olunan modülü, kimsenin konuşmadığı ekibin
elindedir.** İki grafik örtüşmediğinde modül grafiği kazanır: bağımlılık kodda durmaya devam eder ve
eksik kanal kendini o bağdan geçen her kalemin beklemesiyle gösterir.

Akış odaklı bölünme bu sayıyı sıfıra indirir ama başkasını büyütür. Bölünme A'da hiçbir modül üç
ekibi aşmaz; B'de `depoErisimi` ve `ortakBicim` dört ekip tarafından değiştirilir, çünkü akış odaklı
ekipler kalemlerini uçtan uca bitirmek için ortak modüllere doğrudan girer. **B'nin ortalaması daha
iyidir (2.06 karşı 2.24) ama en kötü modülü daha kötüdür.**

## Aynı İşin İki Bölünmedeki Akışı

Bedeli görmek için aynı on iki kalem iki bölünmede koşturulur.

**ET6 — bir kalem dokunduğu her modül için bir tur çalışır; iki ekip arasındaki her geçiş, iletişim
mesafesi 1 ise 1, mesafe 2 ise 3, mesafe 3 ise 5, yol yoksa 8 tur bekler.** Gerekçe: doğrudan kanalı
olan iki ekip aynı turda konuşur; aracıya düşen her adım bir kuyruk daha bekletir.

**ET7 — üç yeniden iş nedeni sayılır: mesafesi 1'den büyük bir geçiş varsa `kisit` (geç öğrenilen
kısıt), kalem üç ve daha çok ekibin değiştirdiği bir modüle dokunuyorsa `sinir` (yanlış sınır),
kalem dört ve daha çok ekibe dağılıyorsa `bilgi` (eksik bilgi); her yeniden iş 2 tur çalışma ekler
ve en uzun beklemeyi bir kez daha ödetir.** Gerekçe: üç neden üç ayrı yapısal kusuru işaret eder —
kanal yokluğu, sahiplik belirsizliği, kapsamın yayılması.

```js
// akis.mjs — ayni on iki is kalemi iki bolunmede kosturulur: el degistirme, bekleme, yeniden is
import { readFileSync } from "node:fs";
const { KALEM, S } = JSON.parse(readFileSync("ag.json", "utf8"));

const BEKLE = [0, 1, 3, 5], YOK = 8;       // ET6: iletisim mesafesine gore bekleme turu
const kosum = (s) => KALEM.map(([ad, dizi]) => {
  const ms = dizi.split(" ");
  const sira = [...new Set(ms.map((m) => s.sahip[m]))];   // ekipler, isin izledigi sirayla
  let bek = 0, enUzun = 0, kopuk = 0;
  for (let j = 1; j < sira.length; j++) {
    const u = s.d[sira[j - 1]][sira[j]], b = u < 0 ? YOK : BEKLE[u];
    bek += b; enUzun = Math.max(enUzun, b);
    if (u < 0 || u >= 2) kopuk += 1;
  }
  const neden = [];                                                 // ET7: uc yeniden is nedeni
  if (kopuk) neden.push("kisit");                                   // gec ogrenilen kisit
  if (ms.some((m) => s.deg[m].length >= 3)) neden.push("sinir");    // yanlis sinir
  if (sira.length >= 4) neden.push("bilgi");                        // eksik bilgi
  const cal = ms.length + neden.length * 2;        // her yeniden is 2 tur calisma ekler
  const bekT = bek + neden.length * enUzun;        // ve en uzun beklemeyi bir kez daha odetir
  return { ad, ekip: sira.length, eld: sira.length - 1, cal, bek: bekT, akis: cal + bekT, neden };
});

const R = S.map((s) => ({ ad: s.ad, k: kosum(s) }));
const BAS = ["ekip", "eld", "bek", "akis"];
const hucre = (r) => [r.ekip, r.eld, r.bek, r.akis].map((x) => String(x).padStart(6)).join("") +
  `  ${(r.neden.join("+") || "-").padEnd(17)}`;
console.log(`${"is kalemi".padEnd(24)}${R.map((r) => r.ad.padEnd(43)).join("")}`.trimEnd());
console.log(`${"".padEnd(24)}${R.map(() =>
  BAS.map((h) => h.padStart(6)).join("") + `  ${"neden".padEnd(17)}`).join("")}`.trimEnd());
for (let i = 0; i < KALEM.length; i++)
  console.log(`${R[0].k[i].ad.padEnd(24)}${R.map((r) => hucre(r.k[i])).join("")}`.trimEnd());

const ozet = (r) => {
  const T = (f) => r.k.reduce((t, x) => t + f(x), 0);
  const n = (c) => r.k.filter((x) => x.neden.includes(c)).length;
  return {
    "el degistirme": T((x) => x.eld), "bekleme turu": T((x) => x.bek),
    "akis suresi (tur)": T((x) => x.akis),
    "akis suresinin bekleme payi": `%${(100 * T((x) => x.bek) / T((x) => x.akis)).toFixed(1)}`,
    "yeniden is (kalem / toplam)":
      `${r.k.filter((x) => x.neden.length).length} / ${T((x) => x.neden.length)}`,
    "  neden: gec ogrenilen kisit": n("kisit"),
    "  neden: yanlis sinir": n("sinir"), "  neden: eksik bilgi": n("bilgi"),
  };
};

const Z = R.map(ozet);
console.log(`\n${"toplam".padEnd(40)}${R.map((r) => r.ad.padStart(20)).join("")}`);
for (const k of Object.keys(Z[0]))
  console.log(`${k.padEnd(40)}${Z.map((z) => String(z[k]).padStart(20)).join("")}`);
```

```
is kalemi               A (bilesen odakli)                         B (akis odakli)
                          ekip   eld   bek  akis  neden              ekip   eld   bek  akis  neden
gecikme ucreti orani         4     3    36    46  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
rezervasyon iptali           4     3     5    13  sinir+bilgi           3     2     3     9  sinir
uyelik hatirlatmasi          4     3    14    24  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
katalog kaydinda alan        4     3    41    51  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
odunc suresi uzatma          3     2    10    17  kisit+sinir           2     1     2     7  sinir
kimlikte ikinci adim         4     3    34    44  kisit+sinir+bilgi     3     2    10    18  kisit+sinir
ucret iadesi kaydi           2     1     2     7  sinir                 3     2     3     8  sinir
sube gecikme raporu          3     2    10    17  kisit+sinir           2     1     2     7  sinir
bildirim metni bicimi        2     1    24    30  kisit+sinir           1     0     0     4  sinir
rezervasyon sirasi           2     1     1     4  -                     2     1     2     7  sinir
odunc kurali istisnasi       2     1     2     8  sinir                 2     1     1     5  -
olay gunlugune alan          2     1    24    31  kisit+sinir           2     1     2     7  sinir

toplam                                    A (bilesen odakli)     B (akis odakli)
el degistirme                                             24                  17
bekleme turu                                             203                  55
akis suresi (tur)                                        292                 126
akis suresinin bekleme payi                            %69.5               %43.7
yeniden is (kalem / toplam)                          11 / 24             11 / 15
  neden: gec ogrenilen kisit                               8                   4
  neden: yanlis sinir                                     11                  11
  neden: eksik bilgi                                       5                   0
```

## Bölünme Değiştiğinde Ne Değişmedi

Toplam tabloda üç sayı belirgin biçimde düşer ve bir sayı hiç kıpırdamaz.

Düşenler: el değiştirme 24'ten 17'ye, bekleme 203 turdan 55 tura, akış süresi 292'den 126'ya iner;
bekleme payı %69.5'ten %43.7'ye düşer. Önemli olan orantısızlıktır: **el değiştirme yalnız %29
azalırken bekleme %73 azalır.** Bedelin çoğu el değiştirmenin sayısında değil, el değiştirilen
ekibin uzaklığındadır. Bölünme A'da "bildirim metni biçimi" yalnız iki ekibe dokunur ve tek el
değiştirme içerir, ama o el değiştirme `ortak` ekibine yapıldığı için kalem otuz tura ulaşır —
dört ekibe dağılan "rezervasyon iptali" kaleminin iki katından fazla.

Kıpırdamayan sayı `sinir` nedenidir: iki bölünmede de on bir kalem bu nedenle yeniden işe girer.
A'da altı modül üç ekip tarafından değiştirilir; B'de bu sayı dörde iner ama iki modül dört ekibe
çıkar ve o ikisi (`depoErisimi`, `ortakBicim`) kalemlerin çoğunda görünür. **Ekip
sınırını taşımak paylaşılan modülü ortadan kaldırmaz; yalnız kimin beklediğini değiştirir.** Buna
karşılık `bilgi` nedeni 5'ten 0'a iner ve `kisit` 8'den 4'e düşer ama sıfırlanmaz; kalan dördü
`platform` ile `deneyim` arasındaki iki adımlık mesafeden gelir.

İki gözlem birlikte dersin sonucudur. İletişim yapısını değiştirmek modül grafiğine hiç dokunmadan
akış süresini iki kattan fazla kısaltabilir; ama ortak bağımlılığı yalnız iletişim yapısıyla çözmek
mümkün değildir. **Örtüşmeyi kurmanın iki yönü vardır ve bir bölünme kararı yalnız birini
kullanır.**

## Özet

- Aynı 17 modüllü ve 43 bağlı grafiğe iki bölünme bindirildi: bileşen odaklı 5 ekip (4 kanal) ve
  akış odaklı 6 ekip (9 kanal); modül grafiği iki koşumda da değişmedi.
- Bileşen odaklı bölünmede 40/43 bağ ekip sınırını geçer ve bunların **16'sı iletişim grafiğinde
  hiç yolu olmayan ekipler arasında** durur; akış odaklıda sınırı geçen bağ 32'ye iner ve yolu
  olmayan ekip çifti kalmaz.
- On altı kopuk bağın hepsi tek modülün etrafındadır: 15 modülün ithal ettiği `ortakBicim`, hiçbir
  kanalı olmayan tek modüllük bir ekibin elindedir.
- Aynı 12 iş kalemi iki bölünmede koşturulduğunda el değiştirme 24'ten 17'ye, bekleme 203 turdan
  55 tura, akış süresi 292'den 126'ya iner; bekleme payı %69.5'ten %43.7'ye düşer.
- Bekleme %73, el değiştirme yalnız %29 azalır: bedel el değiştirmenin sayısında değil, karşı
  ekibin iletişim grafiğindeki uzaklığındadır.
- `sinir` yeniden iş nedeni iki bölünmede de 11 kalemde görülür; akış odaklı bölünme en çok
  paylaşılan modülü 3 ekipten 4 ekibe çıkarır. Paylaşılan modüldeki çekişme ekip sınırı taşınarak
  yok edilemez.

## Sonraki Adım

Bu dersin ikinci bölünmesi "akış odaklı" adıyla anıldı ama yalnız tek bir özelliğiyle kullanıldı:
her ekip bir hizmet akışının sahibidir. Sayılar bu özelliğin akış süresini iki kattan fazla
kısalttığını gösterdi — ve bir şeyi hiç ölçmedi: **o ekiplerin ne kadar yük taşıdığını**. Sonraki
ders bu yükü sayar: aynı iş kalemi kümesi üç ayrı ekip düzeninde koşturulur ve el değiştirme,
bekleme, yeniden iş sayılarının yanına ekip başına **bilişsel yük** eklenir — sahip olunan modül ve
bağımlı olunan dış arayüz sayısı. Akış odaklı düzenin kazandığı yer bu dersin tablosunda görüldü;
kaybettiği yer orada görülecek.
