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

AI: Where in the Loop Should Humans Go?

This is a re-publishing of a blog post I originally wrote for work, but wanted on my own blog as well.AI is everywhere, and its impressive claims are leading to rapid adoption. At this stage, I’d qualify it as charismatic technology—someth…

via Ferd.ca

More Good Programming Quotes, Part 6

Here are more good programming quotes I have found since my last post. Programming “Configuration is coding in a poorly designed programming language without tests, version control, or documentation.”Gregor Hohpe “It’s the developers misunderstanding, not…

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