# Sürekli entegrasyon
Sürekli entegrasyon (CI), kaynak kod değişikliklerini sık sık entegre etme ve entegre kod tabanının çalışır durumda olmasını sağlama uygulamasıdır.
Geliştiriciler genellikle değişiklikleri bir entegrasyon dalına birleştirir, otomatik bir sistem kurulur ve yazılım sistemini test eder. Genellikle, otomatik işlem her bir işlemede çalışır veya günde bir kez olacak gibi bir programa göre çalışır.
Grady Booch, CI terimini ilk kez 1991 yılında önerdi, ancak günde birden fazla kez entegre etmeyi savunmadı, ancak daha sonra CI bu yönü de kapsayacak şekilde geliştirildi.


## Tarihçe.
Sürekli entegrasyon üzerine bilinen en eski çalışma (1989), G. E. Kaiser, D. E. Perry ve W. M. Schell tarafından geliştirilen Infuse ortamıdır. 1994 yılında Grady Booch, Object-Oriented Analysis and Design with Applications (2. baskı) adlı eserinde “continuous integration” (sürekli entegrasyon) ifadesini şu şekilde açıklamak için kullandı: Mikro süreçler kullanılarak geliştirilen sistemlerde, “içsel sürümler bir tür sürekli entegrasyonu temsil eder ve bu sürümler mikro sürecin kapanmasını zorlamak için vardır.”
1997 yılında, Kent Beck ve Ron Jeffries, Chrysler Kapsamlı Ücretlendirme Sistemi projesi üzerinde çalışırken sürekli entegrasyonu da içeren ekstrem programlama (XP) yöntemini geliştirdiler. Beck, sürekli entegrasyon hakkında 1998 yılında yayın yaptığı çalışmasında, teknolojik destekten ziyade yüz yüze iletişimin önemini vurguladı. Beck, 1999'da ektrem programlamaya ilişkin ilk kitabında daha fazla ayrıntıya girdi. İlk açık kaynaklı CI araçlarından biri olan CruiseControl, 2001'de piyasaya sürüldü.
2010 yılında Timothy Fitz, IMVU’nun mühendislik ekibinin ilk pratik sürekli teslimat (Continuous Delivery – CD) sistemini nasıl geliştirdiğini ve kullandığını detaylandıran bir makale yayınladı. Başlangıçta bu yazı şüpheyle karşılansa da, kısa sürede ilgi gördü ve IMVU’ya dayanan yalın yazılım geliştirme metodolojisinin bir parçası olarak geniş çapta benimsendi.


## Uygulamalar.
Sürekli entegrasyonun (CI) temel faaliyetleri, geliştiricilerin kod değişikliklerini sık sık ortak bir entegrasyon alanında birleştirmeleri ve ortaya çıkan entegre kod tabanının doğruluğunun doğrulanmasıdır. Bu sürecin ilk bölümü genellikle, yapılan değişikliklerin ortak bir sürüm kontrol dalına (branch) birleştirilmesini içerir. İkinci bölüm ise genellikle şu gibi otomatikleştirilmiş süreçleri kapsar: derleme, test etme ve diğer otomasyon süreci. Bu iki temel adım, sürekli entegrasyonun yazılım geliştirme sürecinde erken hata tespiti ve hızlı geri bildirim sağlama amacıyla uygulanmasını mümkün kılar.
Genellikle bir sunucu, entegrasyon alanından sık sık derleme yapar; yani her kod gönderiminden (commit) sonra ya da günlük gibi periyodik aralıklarla. Bu sunucu, birim testleri çalıştırmak gibi kalite kontrol gerçekleştirebilir ve statik analiz, performans testleri gibi süreçler aracılığıyla yazılım kalitesiyle ilgili metrikleri toplayabilir.


## İlgili pratikler.
### Otomasyon oluşturmak.
Yapı otomasyonu, yazılım geliştirme sürecinde en iyi uygulamalardan biridir. Yapı otomasyon araçları, yazılımın derlenme (build) sürecini otomatikleştirir. Sürekli entegrasyon (CI) savunucuları, sistemin yalnızca tek bir komutla derlenebilmesini önermektedir. Otomasyon genellikle entegrasyon sürecini de kapsar ve bu da çoğu zaman yazılımın üretim ortamına benzer bir ortama otomatik olarak dağıtımını (deployment) içerir.
Pek çok durumda, yapı betiği sadece ikili dosyaları (binary) derlemekle kalmaz; aynı zamanda dokümantasyon, web sayfaları, istatistikler ve dağıtım paketleri (örneğin Debian için deb, Red Hat için RPM veya Windows için MSI dosyaları) gibi çıktılar da üretir.


### Atomik gönderimler.
Sürekli entegrasyon (CI), sürüm kontrol sisteminin atomik gönderimleri desteklemesini gerektirir; yani bir geliştiricinin yaptığı tüm değişikliklerin tek bir gönderim (commit) olarak işlenmesi gerekir. Bu sayede, sistemde yarım kalmış veya tutarsız değişikliklerin entegrasyon alanına aktarılması engellenir ve kod tabanının her zaman derlenebilir ve test edilebilir durumda olması sağlanır.


### Kod değişikliklerinin gönderilmesi.
Bir geliştirici kod değişikliği yaparken, mevcut kod tabanının bir kopyasını alarak bir dal (branch) oluşturur. Diğer geliştiriciler de havuza (repository) değişiklikler gönderdikçe, bu kopya zamanla en güncel sürümden uzaklaşır. Bir dal üzerinde geliştirme yapılmaya devam edilirken entegrasyon dalıyla (genellikle ana dal/main branch) birleştirme yapılmazsa, o dal sonunda ana dala geri birleştirilmeye çalışıldığında birden fazla entegrasyon çatışması ve hata riski ortaya çıkar.
Geliştiriciler, kendi kodlarını havuza göndermeden önce, havuzda kendi kopyalarını aldıkları zamandan bu yana yapılmış değişiklikleri sistemlerine entegre etmek zorundadır. Havuza eklenen değişiklikler arttıkça, geliştiricinin kendi değişikliklerini göndermeden önce yapması gereken entegrasyon ve düzeltme işlemleri de artar. Sonuç olarak, havuz geliştiricinin başlangıçtaki sürümünden o kadar farklı hale gelebilir ki, bu durum bazen “birleştirme cehennemi” (merge hell) ya da “entegrasyon cehennemi” (integration hell) olarak adlandırılır. Bu durumda, geliştiricinin yaptığı değişiklikleri entegre etmek için harcadığı zaman, aslında bu değişiklikleri yaparken harcadığı zamandan daha fazla olabilir.


### Yerel testler.
Sürekli entegrasyon savunucuları, geliştiricilerin test güdümlü geliştirme yöntemini kullanmalarını ve entegrasyon dalına kod göndermeden önce tüm birim testlerinin yerel olarak geçmesini sağlamalarını önerirler; böylece bir geliştiricinin yaptığı değişiklik, diğer geliştiricinin kopyasını bozmaz. Tamamlanmamış özellikler, commit öncesinde özellik geçişleri (feature toggles) kullanılarak devre dışı bırakılabilir.


### Sürekli teslimat ve sürekli dağıtım.
Sürekli teslimat (continuous delivery), entegrasyon dalına gönderilen yazılımın her zaman kullanıcıya dağıtılabilir durumda olmasını sağlar; sürekli dağıtım (continuous deployment) ise dağıtım sürecini otomatikleştirir. Sürekli teslimat ve sürekli dağıtım genellikle sürekli entegrasyon (CI) ile birlikte uygulanır ve birlikte CI/CD hattını (pipeline) oluştururlar.


### Sürüm kontrol sistemi.
Sürekli entegrasyon (CI) savunucuları, derleme için gereken tüm dosya ve bilgilerin sürüm kontrolünde (örneğin Git için bir depo/repository) saklanmasını önerir; sistemin temiz bir kopya (fresh checkout) üzerinden derlenebilir olması ve ek bağımlılıklara ihtiyaç duymaması gerekir. Martin Fowler ise tüm geliştiricilerin aynı entegrasyon dalına (integration branch) kod göndermelerini tavsiye eder.


### Sık sık işlemek.
Geliştiriciler, değişikliklerini birbirleriyle sık sık (en az günlük olarak) senkronize ederek çatışma çözme çabalarını azaltabilirler. Bir haftalık çalışmaların bir kerede gönderilmesi, hem çatışma yaşanma olasılığını hem de çözüm karmaşıklığını artırır. Göreceli olarak küçük çatışmalar, büyük olanlara kıyasla çok daha kolay çözülür. Değişikliklerin en az günde bir kez entegre edilmesi (commit yapılması) iyi bir uygulama olarak kabul edilir ve daha sık yapılması daha iyidir.


### Her işlenen derlenmelidir.
Sistem, işlem edilen değişikliklerin mevcut çalışma sürümüyle doğru şekilde entegre olduğunu doğrulamak için commit’leri derlemelidir. Yaygın bir uygulama, bunu otomatik olarak gerçekleştiren sürekli entegrasyon sistemlerinin kullanılmasıdır; ancak bu işlem manuel olarak da yapılabilir.
Otomatik sürekli entegrasyon, sürüm kontrol sistemindeki değişiklikleri izleyen bir sürekli entegrasyon sunucusu veya servis (daemon) kullanır ve değişiklik tespit edildiğinde derleme sürecini otomatik olarak başlatır.


### Her hata düzeltme işlemi bir test senaryosu ile birlikte gelmelidir.
Bir hata düzeltildiğinde, hatayı yeniden üreten (tekrarlayan) bir test senaryosunun da gönderilmesi iyi bir uygulamadır. Bu, yapılan düzeltmenin geri alınmasını ve hatanın yeniden ortaya çıkmasını (regresyon) önlemeye yardımcı olur.


### Üretim ortamının bir kopyasında test yapma.
Bir test ortamına sahip olmak, test edilen sistemlerin üretim ortamına dağıtıldığında hatalarla karşılaşmasına neden olabilir; çünkü üretim ortamı, test ortamından önemli ölçüde farklı olabilir. Ancak, üretim ortamının birebir bir kopyasını oluşturmak maliyet açısından genellikle mümkün değildir. Bunun yerine, test ortamı ya da ayrı bir ön-üretim ortamı ("staging"), üretim ortamının daha ölçeklenebilir bir versiyonu olacak şekilde inşa edilmelidir. Bu yaklaşım, maliyetleri azaltırken kullanılan teknoloji yığını ve sistemin kendine özgü detaylarını korumayı sağlar.
Bu test ortamlarında, ekiplerin kontrolü dışında olan, hâlâ geliştirilmekte olan veya sanal bir test laboratuvarında yapılandırılması çok karmaşık olan bağımlılıklara (örneğin API’ler, üçüncü taraf uygulamalar, servisler, ana bilgisayar sistemleri vb.) isteğe bağlı erişim sağlamak için genellikle servis sanallaştırması kullanılır.


### En son teslim edilebilir çıktılara erişimi kolaylaştırın.
Derlemelerin paydaşlar ve test uzmanları tarafından kolayca erişilebilir olması, gereksinimleri karşılamayan bir özelliğin yeniden inşa edilmesi sırasında ortaya çıkacak yeniden çalışma miktarını azaltabilir. Ayrıca, erken testler sayesinde hataların dağıtıma kadar fark edilmeden kalma olasılığı düşer. Hataların erken bulunması, onları düzeltmek için gereken çabayı da önemli ölçüde azaltır. Tüm yazılımcılar günü, projeyi havuzdan (repository) güncelleyerek başlatmalıdır. Bu sayede herkes en güncel sürüm üzerinde çalışır ve senkronizasyon korunmuş olur.
Derlemenin bozulup bozulmadığını ve bozulduysa ilgili değişikliği kimin yaptığını ve bu değişikliğin ne olduğunu bulmak kolay olmalıdır.


### Dağıtımı otomatikleştirin.
Çoğu sürekli entegrasyon (CI) sistemi, bir derleme (build) tamamlandıktan sonra betiklerin (scripts) çalıştırılmasına izin verir. Çoğu durumda, uygulamayı herkesin inceleyebileceği canlı bir test sunucusuna dağıtacak bir betik yazmak mümkündür.
Bu yaklaşımın daha ileri bir aşaması ise sürekli dağıtım (continuous deployment) yöntemidir. Sürekli dağıtım, yazılımın doğrudan üretim ortamına dağıtılmasını öngörür ve genellikle hataları veya regresyonları önlemek amacıyla ek otomasyon süreçleriyle desteklenir.


## Faydaları.
CI’nin (Sürekli Entegrasyonun) faydaları şunlardır:
  - Hataların erken tespit edilmesini kolaylaştırır.
  - Hataların nedenini bulmak için harcanan çabayı azaltır  bir CI testi başarısız olursa, son başarılı derlemeden bu yana yapılan değişiklikler hata kaynağını içerir  her değişiklik sonrası derleme yapılırsa, yalnızca tek bir değişiklik sorumludur.
  - Birçok değişikliğin aynı anda entegre edilmesinden doğan kaosu önler.
  - Bir test başarısız olduğunda veya bir hata bulunduğunda, kod tabanı çalışır bir sürüme geri döndürülebilir  bu sayede daha az değişiklik kaybedilir.
  - Test, demo ve sürümleme için sık sık bilinen, çalışır bir sürümün hazır olmasını sağlar.
  - Sık kod gönderimi, daha modüler ve daha az karmaşık kod yazımını teşvik eder.
  - Kod değişikliklerinin sistem genelindeki etkisi hakkında hızlı geri bildirim sağlar.
  - Kod kapsama oranı (code coverage), kod karmaşıklığı (code complexity) gibi yazılım metriklerinin toplanmasına olanak tanır.


## Riskleri.
Sürekli Entegrasyonun (CI) riskleri şunlardır:
  - Derleme sistemini kurmak zaman ve çaba gerektirir.
  - Otomatik test paketi yazmak ve bunu sürdürülebilir şekilde güncel tutmak emek ister.
  - CI'nin sağladığı fayda, testlerin kalitesine doğrudan bağlıdır  zayıf testler, hataları gözden kaçırabilir.
  - Yüksek derleme gecikmesi (build’lerin sırada beklemesi), sistemin değerini azaltır.
  - CI, tamamlanmamış kodların entegre edilmemesini öngörür  bu, bazı geliştiricilerin tercih ettiği esnek çalışma yöntemlerine ters düşebilir.
  - Güvenlik veya görev açısından kritik sistemlerde (örneğin DO-178C, ISO 26262 gibi standartlara tabi projelerde), CI süreçleriyle birlikte gerekli dokümantasyon ve inceleme süreçlerini sağlamak zor olabilir.


## Bulut sistemleri için en iyi uygulamalar.
Aşağıdaki uygulamalar, özellikle bulut ortamında barındırılan sistemlerde CI/CD hatlarının (pipeline'ların) verimliliğini artırabilir:
  - Pipeline Sayısı: Küçük ekipler, tek bir depo (repository) ve tek bir pipeline kullanarak daha verimli çalışabilir. Buna karşılık, daha büyük organizasyonlar her ekip için ayrı depolar ve pipeline’lar, hatta bir ekibin içerisindeki her servis için bile ayrı yapılandırmalar kullanabilir.
  - İzinler: Pipeline’larla ilgili izinlerde, “asgari ayrıcalık” ilkesine uymak, mimarinin dinamik doğası nedeniyle zorlayıcı olabilir. Bu nedenle, yöneticiler daha geniş (izin verici) haklar tanıyabilir  ancak olası güvenlik açıklarını sınırlamak amacıyla telafi edici güvenlik kontrolleri uygulayarak risk alanını (blast radius) en aza indirmeye çalışabilirler.