Conditional Formatting

March 4, 2021

Bu yazıda api tasarlarken zaman zaman karşıma çıkan bir problemi açıklamaya çalışacağım. İş uygulaması yazarken kimi özelliklerin serialize edilip edilmeyeceği başka özelliklere bağlı oluyor. Conditional Formatting adresinde bunun newtonsoft serializer için nasıl yapıldığı anlatılmış. Ben ise bunun neden yanlış olduğunu açıklamaya çalışacağım.

Bir arkadaşlık uygulaması yazdığınızı düşünün. Uygulamamızda kullanıcı bir arkadaşını bir ağa dahil edebilir. Kullanıcı arkadaşını yakın arkadaş olarak işaretleyebilir. Biz de kullanıcılara yakın arkadaş diye ön tanımlı bir grup vermiş olalım. idsi de ae057975-a838-45ff-8782-60229dd72eb4 olsun. Yazının geri kalanında bu networkten yakın arkadaş grubu olarak bahsedeceğim. Kullanıcımız bir endpoint üzerinden arkadaşlarını sorgulamak istiyor diyelim.

Server Tarafı Implementasyon 1

Problemi kabaca anladığımıza göre .net uygulaması üzerinde poco olarak nasıl ifade ettiğimize bakalım.

1
2
3
4
5
6
7
public class Friend {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid NetworkId { get; set; }
}

public class Root { public List<Friend> friends { get; set; }  }

Bunu implement etmek için bir miktar kod yazdıktan sonra çıktımızı alalım.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ curl -X GET -H "burak:apikey" host/friends
{
    "friends" : [
        {
            "id" : "67043632-a1c0-4340-8049-c1853e9a9b6f",
            "name" : "suleyman",
            "network_id" : "ae057975-a838-45ff-8782-60229dd72eb4" # yakın arkadaş grubu idsi
        },
        {
            "id" : "5e8f7662-0b8a-48ec-9883-8650448713cc",
            "name" : "faruk",
            "network_id" : "c87f259d-4034-4da5-854e-35c14ec1717d"
        }
    ]
}

Server Tarafı Implementasyon 2

Api ı bu şekilde dışarıya açtıktan sonra bir gün geliyor ürün geliştirmeden biri gelip diyor ki, Kullanıcı arkadaş listesine istek yaptığında yakın arkadaşlarının online olup olmadığını görebilsin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Friend {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid NetworkId { get; set; }
    public bool Online { get; set;}
    
    // Eğer yakın arkadaş grubunda ise online property sini ekle
    public bool ShouldSerializeOnline() => NetworkId == GROUPS.CloseFriends.Id
}

public class Root { public List<Friend> friends { get; set; } }

Tekrar çalıştırıp sonucu görelim

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ curl -X GET -H "burak:apikey" host/friends
{
    "friends" : [
        {
            "id" : "67043632-a1c0-4340-8049-c1853e9a9b6f",
            "name" : "suleyman",
            "network_id" : "ae057975-a838-45ff-8782-60229dd72eb4", # yakın arkadaş grubu idsi
            "online" : true # önceki payloaddan farklı olarak bu geldi
        },
        {
            "id" : "5e8f7662-0b8a-48ec-9883-8650448713cc",
            "name" : "faruk",
            "network_id" : "c87f259d-4034-4da5-854e-35c14ec1717d"
        }
    ]
}

Oldu gibi sanki değil mi ?

Client Side

Şimdi api geliştiren ekipte değilde client geliştiren ekipte olsaydım ne olurdu onu irdeleyelim.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// client application
public class Friend {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid NetworkId { get; set; }
    public bool Online { get; set;}
}

public class Root    {
    public List<Friend> friends { get; set; } 
}

RPC yaptığımızda gelen sonucu deserialize ettiğimize kabaca aşağıdakini bekliyoruz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
ROOT = new Root(){
    friends = new List<Friend>(){
        new Friend(){ 
            Id = Guid.Parse("67043632-a1c0-4340-8049-c1853e9a9b6f"),
            Name = "suleyman",
            Network_Id = Guid.Parse("ae057975-a838-45ff-8782-60229dd72eb4"),
            Online = true // beklendigi gibi true gelecek
            },
            new Friend(){ 
            Id = Guid.Parse("5e8f7662-0b8a-48ec-9883-8650448713cc"),
            Name = "faruk",
            Network_Id = Guid.Parse("ae057975-a838-45ff-8782-60229dd72eb4"),
            Online = <MAGICAL VALUE>
            },
    }
}

Kodda MAGICAL VALUE olan kısma ne gelecek ? Kimi serializerlar exception atıyor kimisi ise default değer ne varsa onu kullanıp geçiyor. Newtonsoft serializer sanırım default değeri kullanıyordu. Default değeri kullandığı durumda nur topu gibi bir bugınız oluyor. Kullanıcı yakın arkadaş listesinde olmadığı için online durumunun false gelmesi onun offline olduğunu göstermez.

Çözüm

Ben böyle bir durumla karşılaştığım zaman yeni bir endpoint açmayı daha uygun buluyorum. Bizim problemimiz için /closefriends olabilir. Serialization cambazlığı yapmaktansa ekstra bir endpoint daha iyidir. Fazlasıyla basitleştirilmiş bir örnek üzerinde bile bu yazıyı yazması benim için yorucu oldu. Gerçek bir uygulamada gerçek karmaşık iş kurallarına rağmen takip edecek geliştirici neler çeker bir düşünün.

Altın kuralı hatırlayalım.

A good API is not just easy to use but also hard to misuse

hidden

The Review Is the Action Item

2024/05/30The Review Is the Action ItemI like to consider running an incident review to be its own action item. Other follow-ups emerging from it are a plus, but the point is to learn from incidents, and the review gives room for that to happen.This is no…

via Ferd.ca

Finding a New Software Developer Job

For the first time ever, I was laid off, and had to find a new software developer job. I managed to find a new one, but it took longer than I thought, and it was a lot of work. I … Continue reading →

via Henrik Warne's blog

HOWTO: Change your behavior

In theory, behavior change should be easy. At first glance, it seems like you control your behavior. So, if you desire different behavior, why doesn’t your behavior change as instantly as your desire to change it? In short, lasting change of habitual behavio…

via Matt Might's blog