30 Aralık 2020 Çarşamba

Yazılım Mimarisi Deployment - Canlıya Geçirme

Giriş
Deployment yazılımımızın yeni sürümü hazır ve canlıya geçirmek istiyoruz anlamına geliyor

Continuous Delivery vs Continuous Deployment 
Açıklaması şöyle. Continuous Deployment koddaki değişikliğin hemen canlıya geçirilmesi demek
When someone says CI/CD, the “CD” they’re referring to is usually continuous delivery, not continuous deployment. What’s the difference? In a CI/CD pipeline that uses continuous delivery, automation pauses when developers push to production. A human—your operations, security, or compliance team—still needs to manually sign off before final release, adding more delays. On the other hand, continuous deployment automates the entire release process. Code changes are deployed to customers as soon as they pass all the required tests.

Continuous deployment is the ultimate example of DevOps automation. That doesn’t mean it’s the only way to do CI/CD, or the “right” way. Since continuous deployment relies on rigorous testing tools and a mature testing culture, most software teams start with continuous delivery and integrate more automated testing over time.
Eğer "Continuous Deployment" yoksa önce "Delivery" yapılıyor. Daha sonra elle deployment yapılıyor. Şeklen şöyle
Bir başka şekil şöyle


Continuous Deployment İçin Yöntemler
Belli başlı yöntemler şöyle. Bu yöntemler Downtime gerektirmiyorlar.

Rolling Deployment
Rolling Deployment yazısına taşıdım

Blue/Green Deployment
Blue/Green Deployment yazısına taşıdım

Canary Deployment
Yükün Belli Bir Yüzdesi Yeni Sisteme Verilir. Canary Deployment yazısına taşıdım

Red Black Deployment - Bir Blue/Green Deployment Türevi
Bu yöntemi Netflix kullanıyor. Aslında Downtime gerektirmeyen yöntem ile aynı sadece basit bir kavramsal fark var. Açıklaması şöyle
With Red Black deployments, your existing “red” microservices are running behind the load balancer as before. In order to deploy your change, you stand up new instances of your microservice as more red instances, adding them into the load balancer. Old versions of your instances are then removed from the load balancer; these are the “black” instances, no longer serving traffic but being kept alive so that if anything goes wrong with the new version, they’re ready and waiting to be re-added to the load balancer. Then, once you’re satisfied that the new red instances are performing correctly, the black instances can be destroyed, leaving only the new set of red services containing your latest change.
...
The key difference between Blue Green and Red Black deployments is conceptual, and is in how they describe the point at which both versions of the microservice are running behind the load balancer
...
With Red Black deployments, the services responding to traffic are always red. Red Black focuses on the continuity of service, not the introduction of change.
...
... from an operational perspective, these instances are all the same. Load is being balanced across all of them, all of them need to respond to the same requests from the clients, and no client-facing features in the new version can be leveraged yet as there is no guarantee that a new version of the service will receive the request. It is only after all of the instances of the old version have been removed from the load balancer can any new feature be leveraged by the outside world.



Confluent Schema Registry

Giriş 
Bazı kısa notlar

Kullanım
1. Kafka Producer ve Consumer'a şu alan eklenir. Böylece Schema Registry sunucusuna erişebilirler
configProps.put("schema.registry.url", "http://127.0.0.1:8081");
2. avsc uzantılı Avro dosyaları tanımlanır. avsc dosyasında sürüm numarası belirtilir.
3. Projemizde Avro Maven Plugin tanımlanır. Bu plugin avro dosyalarını Java koduna çevirir

Schema Registry Veri Akışı
Açıklama şöyle. Schema Registry sadece Confluent Avro serialization kütüphanesi kullanılıyorsa lazım. Schema Registry Kafka'dan farklı bir uygulama ve schema bilgisi ismi "_schemas" olan bir topic'te saklanıyor.
Applications that use Confluent’s Avro serialisation library for Kafka also have to use Confluent’s schema registry. It is a separate process that provides a REST API to store and retrieve schemas and also check for different kinds of compatibility types. The schema registry persists the schemas into a special Kafka topic called ‘_schemas’ which contains one Avro schema file per message-type and version.

How does a Kafka consumer know which schema to retrieve from the registry when receiving a message? Confluent’s documentation specifies a wire format, which includes an ID which can be used to retrieve the Avro schema file from the schema registries REST API.
When using Confluent’s schema registry, the following steps have to be taken in order to write and later read an event form a Kafka topic in Avro binary encoded format:

1. The publisher (event writer) has to call the schema registry’s REST API to upload an Avro schema file (once per schema version)
2. The schema registry checks for compatibility and returns an ID on success or an error if for example the schema is not compatible with earlier versions
3. The publisher encodes the data according to Confluent’s wire format (including schema ID and Avro binary encoding of the data)
4. The consumer reads the raw data from the Kafka topic
5. The consumer calls the schema registry’s REST API to download the Avro schema file with the ID provided in the first few bytes of the data
6. The consumer decodes the message using the downloaded schema

Confluents kafka-avro-serializer library implements this behavior.
Veri akışı şeklen şöyle
Schema ID
Açıklaması şöyle
One of the ways in which the size of the data being sent to Kafka is reduced is when the producer first tries to send an event it sends the schema for it to Schema Registry and the schema registry then returns a four-byte schema id. The producer then sends the data along with the schema ID to Kafka. The consumer then extracts the schema ID and gets the respective schema from the registry and performs validation. In this way, the overall content size of the data is reduced considerably.
Schema ID değeri Kafka mesajının hemen başındaki 4 byte'tır. Şeklen şöyle


Schema'nın sürümleri şeklen şöyle. Ayrıca hem Producer hem de Consumer her seferinde REST çağrısı yapmamak için kendi önbelleğini kullanır



Schema Registry İçin Uyarılar
Açıklaması şöyle
The biggest drawback of this system is in my opinion that both producer and consumer depend on not only Kafka itself but also the schema registry to be available at runtime.

If the consumer tries to read an Avro encoded message from a Kafka topic, but cannot reach the schema registries REST API to download the required version of the schema, an Exception is thrown and, in the worst case, the message gets discarded.

This is true even for the case that consumer or producer application have a local copy of the current schema file available. A common misconception at willhaben was that, if the consumer has a local copy of the current Avro schema, it uses this local schema file to decode the message. This is not supported by Confluents kafka-avro-serializer library at this time. The local Avro schema file is only be used to generate Java classes for a schema (like described before). These classes can be used to handle the consumed data, but are not used for serialisation or deserialisation.

You should also be aware that the schema registry depends on the _schema Kafka topic to persists its data.

If this topic gets lost somehow, there is no way to restore the IDs generated when publishing schema files to the registries REST API and therefore the messages on the Kafka topics referencing these schemas cannot be decoded.
Unit Test
Kolaylaştıran Component Tests isimli bir kütüphane burada

Schema Sorgulama
Şöyle yaparız
curl -X GET -H "Content-Type: application/json" http://localhost:8081/subjects/
Elimizde ismi "customer-topic" olan bir topic varsa çıktı olarak şunu alırız
["customer-topic-key","customer-topic-value"]
Eğer value değerinin şemasını görmek istersek şöyle yaparız
curl -X GET -H "Content-Type: application/json"
http://localhost:8081/subjects/customer-topic-value/versions/1

SerDe
Bazı terminoloji şöyle
With respect to the schema-registry, there are few terminologies.
1. subject — refers to the topic name in Kafka. (default strategy, for more info, look for subject naming strategies)
2. id — unique id is allocated to each schema stored in registry.
3. version — each schema can have multiple versions associated to it per subject.

29 Aralık 2020 Salı

Fault Tolerance ve Resiliency İçin Circuit Breaker Örüntüsü

Giriş
Bu yazı aslında Fault Tolerance ve Resiliency İçin Bazı Yazılım Çözümleri serisinin bir parçası. 

Bu yöntem microservice mimarisinde kullanılıyor. Eğer bir sistem cevap vermiyorsa ona sürekli erişmeye çalışmak yerine sigorta (circuit breaker) devreye girer ve direkt hata mesajı/kodu döndürür. Açıklaması şöyle.
In a nutshell — Do not hammer a service with additional requests which is already down. Please give the service time to recover.
Açıklaması şöyle.
Circuit Breaker monitors API calls. When everything is working as expected, it is in the state closed. When the number of fails, like timeout, reaches a specified threshold, Circuit Breaker will stop processing further requests. We call it the open state. As a result, API clients will receive instant information that something went wrong without waiting for the timeout to come.

The Circuit is opened for a specified period of time. After timeout occurs, the circuit breaker goes into the half-opened state. Next, the API call will hit the external system/API. After that, the circuit will decide whether to close or open itself.
Sigorta 3 durumda olabilir. Şeklen şöyle
CLOSED Durumu - Her şey Yolunda
Açıklaması şöyle. Belli bir sayıda hata aldıktan sonra OPEN durumuna geçer.
The circuit breaker being in a CLOSED state means that everything is working fine and all calls pass through to the remote services. Once the number of failures exceeds a predetermined threshold, the circuit breaker trips and enters into the open state.
OPEN Durumu - Sigorta Atmıştır
Açıklaması şöyle. Direkt hata kodu döndürür. Belli bir süre sonra HALF-OPEN durumuna geçiş yapılır
Once the number of timeouts reaches a predetermined threshold in the circuit breaker, it trips the circuit breaker to the OPEN state. In the OPEN state, the circuit breaker returns an error for all calls to the service without making the calls to the remote service.
HALF-OPEN Durumu
Açıklaması şöyle. Halen hata kodu döndürür, ancak servisleri kontrol etmek için deneme çağrıları yapar.
After a certain duration, the circuit switches to a HALF-OPEN state to test if the underlying problem still exists. The circuit breaker uses a mechanism to make a trial call to the remote service periodically to check if it has recovered. If the call to the Remote service fails, the circuit breaker remains in the OPEN state. If the call returns success, then the circuit switches to the CLOSED state. 
State Geçişi
Açıklaması şöyle
There are 2 types of circuit breaker patterns, Count-based and Time-based.

1. Count-based: the circuit breaker switches from a closed state to an open state when the last N requests have failed or timeout.
2. Time-based: the circuit breaker switches from a closed state to an open state when the last N time unit has failed or timeout.

In both types of circuit breakers, we can determine what the threshold for failure or timeout is. Suppose we specify that the circuit breaker will trip and go to the Open state when 50% of the last 20 requests took more than 2s, or for a time-based, we can specify that 50% of the last 60 seconds of requests took more than 5s.

After we know how the circuit breaker works, then we will try to implement it in the spring boot project.
Circuit Breaker Kütüphaneleri
- Netflix’s Hystrix


28 Aralık 2020 Pazartesi

Fault Tolerance ve Resiliency İçin Retry Örüntüsü

Giriş
Bu yazı aslında Fault Tolerance ve Resiliency İçin Bazı Yazılım Çözümleri serisinin bir parçası. 

Retry-After Parametresi
REST çağrılarında sunucu Http cevabına Retry-After parametresini atayabilirHttp Cevap Parametreleri yazısına bakabilirsiniz.

Retry İşlemini Kim Yapmalı
1. Her servis kendisi Retry işlemini gerçekleştirebilir
2. Ortak bir Retry servisi olabilir. Açıklaması şöyle
... it removes the retry complexity from all microservices, and places it in a single retry microservice. The retry microservice’s job is to track and action all retries. This microservice receives an event, writing it to its own topics with both the event to retry and the timestamp to retry that event. It then pushes out these retry events once their timestamp has been reached.

Retry Verisi Nerede Saklanmalı
1. Kafka, AMQP gibi bir kuyrukta saklanabilir
2. Veri tabanında saklanabilir

Retry Detayları
Sistem içinde hata olsa bile işlem belli bir süre sonra tekrar denenir. Retry yönteminde dikkat edilecek noktalar şöyle
1. Retry sayısı
2. Retry aralığı (back off süresi)
3. Tüm denemeler başarısız olursa ne yapılacağı
4. Retry işleminin stateless veya stateful olacağı
5. Retry 'ın çağırdığı şilemin Idempotent Receiver olması. Idempotency Nedir yazısına bakabilirsiniz.

Bazen Retry alt yapısını bizim kodlamamız gerekir, eğer şanslıysak kullandığımız alt yapı bu yeteneği bütünüyle veya kısmen de sağlıyor olabilir.

Not : Bu konuda okunması gereken bir yaz burada

Retry Storms
Elimizde bir servis çağrısı dizisi olsun
A -> B -> C -> D
ve D çalışmıyor olsun. Bu durum Retry Storm sebebidir. Açıklaması şöyle
Now imagine that each service has a retry policy installed which performs up to 3 retries on failed calls (a total of 3+1 requests). Think about what happens if D goes down, and this failure is propagated all the way back up the call chain:
C calls D 4x more
B calls C 4x more
A calls B 4x more

The traffic D receives might be as much as 64 times (!!) that of normal levels. And this is happening when D is already unhealthy — likely impairing it further.

Sounds bad, but the real problem is that these traffic increases grow exponentially. If K is the number of attempts made per call at each node, then the magnitude of the increase in call volume at depth N in the call graph is K^N. This behavior is known as a retry storm, and it can compound minor outages into major cascading failures.

1. Retry Sayısı
Mantıklı bir üst sınıf vermekte fayda var. Yoksa işlem/mesaj sonsuz döngü şeklinde sürekli tekrar tekrar kaynak tüketir.

2. Retry Aralığı
Açıklaması şöyle. Sabit, rastgele veya artan aralıklar kullanılabilir.
You retry few times hoping to get a response, with a fixed, random or exponential wait period in between each attempt and eventually give up to try in the next poll cycle.
Örnek
Java kullanıyorsak elimizde şöyle bir kod olsun .
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
Şöyle yaparız.
service.execute(task);
...
service.schedule(task, 20, TimeUnit.SECONDS);//retry
Örnek
Java kullanıyorsak elimizde şöyle bir kod olsun . java.util.Timer kullanıyoruz
Timer timer = new Timer();
Şöyle yaparız.
timer.schedule(task, 20);
3. Tüm denemeler başarısız olursa ne yapılacağı
Aslında iki tane seçenek var
1. Dead Letter Queue veya benzeri bir yere bir mesaj gönderilebilir.
2. İşlem/mesaj tamamen çöpe atılır

4. Retry işleminin stateless veya stateful olacağı
- Stateless retry işlemlerinden retry mekanizması aynı thread içinde N defa işlemi dener. Thread bu N deneme süresince başka bir işle uğraşmaz.

- Stateful retry işlemlerinden retry mekanizması aynı thread içinde işlemi dener. Eğer başarısız ise, thread başka bir işe geri döner. Yani bloke olmaz. Retry zamanı gelince tekrar dener.

Örnek - Resilience4j
Şöyle yaparız
public List<CompanyDto> searchCompanyByName(String name) {
  RetryConfig retryConfig =
    RetryConfig.custom().maxAttempts(4).waitDuration(Duration.of(2, SECONDS)).build();

  RetryRegistry retryRegistry = RetryRegistry.of(retryConfig);

  Retry retryConfiguration = retryRegistry.retry("companySearchService", retryConfig);

  Supplier<List> companiesSupplier = () -> companyRepository.findAllByName(name);

  Supplier<List> retryingCompaniesSearch =
    Retry.decorateSupplier(retryConfiguration, companiesSupplier);

  List<CompanyDto> companyDtos = new ArrayList<>();
  List companies = retryingCompaniesSearch.get();

  for(Company company : companies) {
    CompanyDto companyDto = new CompanyDto(company.getName(), company.getType(),
      company.getCity(), company.getState(), company.getDescription());
      companyDtos.add(companyDto);
  }

  return companyDtos;
}
Açıklaması şöyle
While using resilience4j-retry library, you can register a custom global RetryConfig with a RetryRegistry builder. Use this registry to build a Retry.

In the above method, we first create RetryConfig. We create a RetryRegistry and add RetryConfig in this registry. Then when we create our call to fetch a list of companies. We decorate this call with retryConfiguration.
RetryConfig açıklaması şöyle
Customizations with Resilience4j-Retry
RetryConfig offers different customization:
1. maxAttempts — 3 is the default number of attempts for retries.
2. waitDuration — a fixed wait duration between each retry attempt.
3. intervalFunction — a function to modify the waiting interval after a failure.
4. retryOnResultPredicate — configures a predicate that evaluates if a result should be retried.
5. retryExceptions — Configures a list of throwable classes that are used for retrying
6. ignoreExceptions — Configures a list of throwable classes that are ignored
7. failAfterMaxRetries — A boolean to enable or disable throwing of MaxRetriesExceededException when the Retry has reached the configured maxAttempts

Retry Design Pattern vs Circuit Breaker Pattern
Açıklaması şöyle. Circuit Breaker eğer bir sistemin çalışmadığını anlarsa Retry işlemine girmeden direkt bir cevap döner. Bu yüzden Retry örüntüsüne göre biraz farklıdır.
I would like to mention, a subtle difference with "Circuit Breaker" pattern, which is actually one level up. It has an implicit Retry but also prevents further communication until the remote service is available and responds with a test call. This strategy is recommended when you expect services to be unavailable for a longer duration whereas "Retry" is recommended for transient failures (short duration or temporary failures).
Doğası Gereği Retry Olması Gereken İşlemler
Bazı sistemlerin doğasında Retry vardır. Karşı sistemden bir cevap dönmüyorsa, kullanılan alt yapı, iletişim ağı güvenilir değilse ister istemez Retry benzeri bir çözüm sistemde kullanılmaya başlanıyor.

Örnek
Bir sistemde UDP kullanıldığı için mesajlar kaybolabiliyordu. "Transmission Queue" bileşeninde her mesaj aynı birincil anahtar ile N defa tekrar edilecek şekilde bir çözüm geliştirildi. Böylece Retry örüntüsü aslında bir nevi gerçekleştirilmiş oldu.

24 Aralık 2020 Perşembe

Renk Uzayı - RGB

Giriş
İnsan gözünün görebildiği gamut şöyle
Açıklaması şöyle. Yani çoğu monitor insan gözünün görebildiğinden daha az renk gösteriyor.
Most computer monitors aren't capable of displaying any spectral color. Some of the RGB monitors could display at most three of them: some red wavelength, some green and some blue. This is because the gamut of the human vision is not triangular, instead it's curved and resembles a horseshoe:

In the image above, the black curve represents the spectral colors, with the wavelengths in nm denoted by green numbers. The colored triangle is the sRGB gamut, the standard gamut that most "usual" computer monitors are supposed to have.

As you can see, the black curve doesn't even touch the triangle, which means that sRGB monitors can't display any of the corresponding colors.
İnsan gözünde RGB renkleri için alıcılar (reseptörler) var. Açıklaması şöyle.
Our ability to separate different colors from each others depends crucially on how many different receptors we have for colored light.

Humans have three different receptors for light, which means that we can characterize colors by three numbers, just like the RGB-codes of colors on your screen.

At the end of the day, what determines with colors we perceive is how the wave-form is projected onto these three numbers. Since there is an infinite set of wave forms, there is an infinite mixture of colors that we will perceive as identical (for every perceived color).

Some animals have more than three types of color receptors, and can therefore distinguish more wave-forms of light. You can say that their color perception is higher dimensional (4D,5D,... etc) than our 3 dimensional color perception.
Ancak alıcılar mükemmel çalışmıyorlar. Farklı yoğunluktaki şeyleri aynı renk olarak görebiliriz. Açıklaması şöyle.
The light that hits your eye is a mixture of many different pure wave lengths, all at different intensities.

The red sensor in your eye computes the weighted average of those intensities, the green sensor computes a different weighted average etc.

Each type of sensor computes one number. Your brain interprets those three numbers as a color.

There are many different combinations of intensities that all produce the same three weighted averages and therefore all look identical to your brain.
RGB ve Bellekteki Formatlar
RGB renkleri farklı Integer Formatlarında saklanabilir. Bazıları şöyle.
5/5/5 format: As 15-bit integers (5 bits per component).
5/6/5 format: As 16-bit integers (5 bits each for red and blue, and 6 bits for green).
8/8/8 format: As 24-bit integers (8 bits per component).
8/8/8/8 format: As 32-bit integers (8 bits each for red, green, blue, and alpha).
16/16/16 format: As 48-bit integers (16 bits per component).
32 bit gösterim şöyledir.
struct RGBA
{
  char r;
  char g;
  char b;
  char a;
};
8 Bit Truecolor
Eski RGB renk uzayında her şey 8 bit saklanıyordu. Açıklaması şöyle. Burada blue renk için sadece 2 bit kullanılıyordu. Çünkü insan gözü mavi renge daha az hassas
The other form is where the 8 bits directly describe red, green, and blue values, typically with three bits for red, three bits for green and two bits for blue. This second form is often called 8-bit truecolor
8 bit truecolor ile 3D oyunlar bile yapılmış. Açıklaması şöyle
... the original Quake from id software back in '97 decided to go with 256 color modes due to highcolor (15/16 bit color) and truecolor (16M colors) video cards were still relatively rare. 
Alpha Kanalı
RGBA Renk uzayı 4. eksen olarak Alpha kanalını da içerir. Açıklaması şöyle. Alpha kanalı 1 ise renk mat, 0 ise renk saydamdır yani arkadaki rengi gösterir. RGB rengi RGB + Alpha = 1 olarak düşünülebilir.
Some RGB colors also contain a fourth component, called the alpha component, which is 0 greater and 1 or less (from fully transparent to fully opaque). Such RGB colors are called RGBA colors in this document. RGB colors without an alpha component are generally considered to be fully opaque (and to have an implicit alpha component of 1).
Bir diğer not şöyle.
An RGB color
- is white, black, or a shade of gray (achromatic) if it has equal red, green, and blue components, and
- is a "Web safe" color if its red, green, and blue components are each a multiple of 0.2.
RGB to Greysecale
RGB renk uzayından Greyscale (Gri Tonlamalı) resme geçiş için Renk Uzayı - GreyScale yazısına bakabilirsiniz.

23 Aralık 2020 Çarşamba

ACID - Lost Update Problem

Giriş
Şeklen şöyle

SQL Server için şeklen şöyle
Veri tabanında yapılan değişikliğin bir başka işlem tarafından ezilmesi anlamına gelir. ACID veri tabanlarında Read Committed seviyesinde veya daha düşük transaction level kullanıldığında ortaya çıkar.

Lost Update Problemi Nedir?
Can multiple threads cause duplicate updates on constrained set? sorusunda açıklandığı gibi eğer iki thread aynı anda tek bir satırı güncellemeye çalışırsa kilidi ilk alan işlemi yaparken diğeri kilidin bırakılmasını bekler. Bekleyen thread kilidi alınca aranılan koşulun halen tutup tutmadığını tekrar değerlendirmelidir. Yoksa Lost Update problemi ortaya çıkar. Şeklen şöyle



Lost Update vs Read Skew
Örnek ver

Lost Update vs Write Skew
Örnek
Bir örnek şöyle
Case 3: Consider your team is on production support for a week. The requirement is at least 1 person should always be on support. Is it possible that if you and teammate try to unassign themselves (assuming the other one is still available) then no one is on support ?
Hatalı kod şöyle
## Psuedo code
if(totalMembersOnSupport() > 1) {
  removeFromSupport(user_id);
}
totalMembersOnSupport() -> Select count(user_id) from support where on_support = 't';
removeFromSupport() -> update support set on_support = 'f' where user_id = '234';
Açıklaması şöyle. Yani her iki kullanıcı bir sayaca bakarak kendi satırlarına güncelleme yapıyorlar.
One difference between this case and the previously discussed cases is that in the previous cases concurrent transactions were trying to update the same row. But in this case, they are updating two different rows.
This is known as Write Skew
Çözüm
1. Optimistic Concurrency kullanılabilir.
2. ACID seviyesini artırmak
Repeatable Read yapmak gerekir ya da 
- "Select For Update" yapmak gerekir ya da 
- "Atomic işlem" yapmak gerekir ya da 
- Veri tabanına kısıt koymak gerekir.

2.1 Select For Update
Select For Update yazısına taşıdım

3. Multi Version
Tüm veri eski tarihçesi ile saklanıyor. Client bir şekilde çözüm buluyor

21 Aralık 2020 Pazartesi

Cognitive Complexity

Cognitive Complexity Nedir?
Sonar McCabe "Cyclomatic Complexity" dışında Cognitive Complexity diye bir metrik sunuyor. Açıklaması şöyle.
"Cognitive Complexity breaks from the practice of using mathematical models to assess software maintainability. It starts from the precedents set by Cyclomatic Complexity, but uses human judgment to assess how structures should be counted and to decide what should be added to the model as a whole. As a result, it yields method complexity scores which strike programmers as fairer relative assessments of maintainability than have been available with previous models."
Null Check - Increased Complexity
Null check yerine Optional kullanılabilir.

Switch/Case- Increased Complexity
Switch/Case Cognitive Complexity değerini azaltıyor

Sequences of Logical Operator — Reduced Complexity
Eğer bir if içinde sürekli aynı logical operator kullanılıyorsa (örneğin sadece &&) bu Cognitive Complexity değerini artırmaz. Ancak bir tane && bir tane de || kullanılıyorsa bu Cognitive Complexity değerini artırır

Nested Flow Breaks Structures - Increased Complexity
Açıklaması şöyle. İç içe geçmiş if/try gibi bloklar kodun okunurluğunu azaltır
Nested code is much difficult to read than the same code as a liner series. A mix of different code structures like try, for, while, if together increase complexity significantly. This why Cognitive Complexity for nested structures adds a point. 
Örnek
Normalde 15 olması gerekir. Açıklaması şöyle.
SonarQube tells me that the Cognitive Complexity is too high: 21, and the current (default, out of the box) metric limit is 15.
21 olan kod şöyle.
public PdfEncryptedPayloadDocument getEncryptedPayloadDocument2() {
  if (getReader() != null && getReader().isEncrypted()) {
    return null;
  }
  PdfCollection collection = getCatalog().getCollection();
  if (collection != null && collection.isViewHidden()) {
    ...
    if (fileSpecObject != null && fileSpecObject.isDictionary()) {
      try {
        ...
        if (fileSpec != null) {
          ...
          PdfStream stream = embeddedDictionary.getAsStream(PdfName.UF);
          if (stream == null) {
            ...
          }
          if (stream != null) {
            return new ...
          }
        }
      } catch (PdfException e) {
        ...
      }
    }
  }
  return null;
}
Bu kod şu hale gelince metric 7'ye düşüyor.
public PdfEncryptedPayloadDocument getEncryptedPayloadDocument2() {
  if (readerIsEncrypted(getReader())) {
    return null;
  }
  PdfCollection collection = getCatalog().getCollection();
  if (collectionIsNotViewHidden(collection)) {
    return null;
  }
  ...
  PdfObject fileSpecObject = embeddedFiles.getNames().get(documentNameUnicode);
  if (fileSpecObjectIsNoDictionary(fileSpecObject)) {
    return null;
  }
  try {
    PdfFileSpec fileSpec = ...;
    if (fileSpec != null) {
      PdfStream stream = ...
      if (stream != null) {
        return new ...
      }
    }
  } catch (PdfException e) {
    ...
  }
  return null;
}
Örnek
Şu kodun Cognitive Complexity değeri 21.
for (String item1 : itemList1){
  for (String item2 : itemList2){
    for (String item3 : itemList3){
      for (String item4 : itemList4){
        for (String item5 : itemList5){
          for (String item6 : itemList6){
            methodToRun(item1, item2, item3, item4, item5, item6);
          }
        }
      }
    }
  }
}