4 Ana Java Performans Anti Patterni, Spring Boot / Java örnekleri ile

4 Ana Java Performans Anti Patterni

Ana Performans Karşı-Örüntüleri. Bir performans problemi araştırırken, kusurunuzun hangi karşı-örüntüye en çok benzediğini kendinize sorun.



Gereksiz Başlatma: Daha büyük bir süreci başlatırken, sistem, zaten işlenmiş olan küçük bir sonucu tekrar işler. Birikmiş etkiler, ekstra CPU/RAM tüketimi ve/veya yavaşlamayı gerektirir; bunların hepsi önlenebilir. Küçük sonucu önbelleklemek ana panzehirdir.


Strateji/Algoritma Verimsizliği: Yanlış yapılandırılmış veya zayıf seçilmiş bir algoritma veya kodlama stratejisi performans sorunlarına neden olur. Bir strateji, bir kod tabanında kullanılan bir tekniktir ve bir algoritma, tek bir bileşeni uygulamak için kullanılan bir plandır.


Aşırı İşleme: Sistem gereksiz işler yapıyor. Bu işleri kaldırmak ölçülebilir performans faydası sağlar. Fazla veri almak ve çoğunun atılması, yanlış kaynak-yoğun kullanım durumunun yük testine dahil edilmesi gibi örnekler verilebilir.


Büyük İşleme Zorluğu: Büyük miktarda veriyi işlemeye ve fethetmeye çalışma. Böyle bir ihtiyacı olan çok az uygulama vardır, ancak mevcuttur. 4 milyar satır veriyi sorgulama, yavaş bir ağ üzerinden sürekli olarak 10MB veri transferi yapma vb.


Maalesef, bu ana karşı-örüntüler arasında örtüşme vardır, burada bir performans kusuru iki veya daha fazla farklı ana karşı-örüntüye uyabilir. 


"Gereksiz Başlatma" (Unnecessary Initialization) adı verilen bir yazılım anti-patronu detaylı olarak inceleniyor. Bu, genellikle kodun başlangıç aşamasında ortaya çıkan, CPU ve I/O yoğunluğu yüksek, verimsiz bir durumdur. Aynı işlemin gereksiz yere tekrar tekrar yapılması, ekstra yük oluşturur.

Bu anti-patronun tipik örnekleri şunlar olabilir:

XML şema dosyalarının (.xsd ve .xslt) her işlemde tekrar okunup ayrıştırılması, oysa bu tür dosyaların içeriği nadiren değişir.
Yetkilendirme, ürün, organizasyonel veri gibi sabit uygulama düzeyindeki verilerin sürekli olarak yeniden yüklenmesi.
Ağ bağlantılarının (TCP soketi gibi) veya veritabanı bağlantılarının her istekte yeniden oluşturulması.
Bu tür durumlar, performans problemlerine yol açabilir. Bunun yerine, veriler önbelleğe alınabilir veya yeniden kullanılabilir hale getirilebilir, böylece diskten veya ağ üzerinden gereksiz istekler en aza indirilir. Bu, uygulamanın genel performansını artıracaktır. İlgili kod örnekleri, yazarın GitHub reposunda bulunabilir.

Bu anti-patron, sıklıkla küçük I/O işlemlerinin yinelenmesi veya yanlış bir programlama dilinin kullanılmasıyla tanınabilir. "Gereksiz I/O işlemlerinden kaçınmak" klişe bir tavsiye olabilir, ancak bu durum, performans sorunlarının yaygın bir kaynağıdır. Bu nedenle, diske veya ağa yapılan gereksiz isteklerin en aza indirilmesine dikkat etmek önemlidir.

Aşağıda, "Gereksiz Başlatma" (Unnecessary Initialization) anti-paternini örneklemek için yaygın bir Java kod parçacı ve daha sonra bunu düzeltmek için nasıl optimize edilebileceği açıklanmaktadır.

Örnek: Gereksiz Başlatma
Bu örnekte, her seferinde aynı XSD dosyasını ayrıştırmak için XML Schema Factory'nin yeniden oluşturulduğu bir durumu ele alalım:

java
Copy code
public class UnnecessaryInitialization {
    public boolean validateXML(String xmlContent, String xsdPath) throws SAXException, IOException {
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = factory.newSchema(new File(xsdPath));
        Validator validator = schema.newValidator();
        validator.validate(new StreamSource(new StringReader(xmlContent)));
        return true; // Geçerli ise
    }
}
Bu kod, her çağrıldığında XSD dosyasını yeniden okur ve ayrıştırır, bu da gereksiz I/O maliyetine neden olur.

Doğru Yöntem: Önbelleğe Alma
Bu kodu optimize etmek için, Schema nesnesini önbelleğe alabiliriz. Schema nesnesi değişmediğinde yeniden oluşturulmasına gerek yoktur.

java
Copy code
public class OptimizedInitialization {
    private static Schema schema;

    static {
        try {
            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            schema = factory.newSchema(new File("path/to/your.xsd")); // Yol sabitse
        } catch (SAXException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public boolean validateXML(String xmlContent) throws SAXException, IOException {
        Validator validator = schema.newValidator();
        validator.validate(new StreamSource(new StringReader(xmlContent)));
        return true; // Geçerli ise
    }
}
Bu durumda, Schema nesnesi yalnızca sınıf ilk yüklendiğinde oluşturulur. Bu, XML şemasının değişmediği varsayılarak, bu kodun daha etkili çalışmasına yardımcı olur.

Önbelleğe alma, ayrıştırma gibi pahalı işlemlerin gereksiz yinelenmesini önlemek için kullanılabilir. Bu örnek, gereksiz I/O maliyetini azaltmaya yardımcı olur ve kodun daha hızlı çalışmasını sağlar.


"Strateji/Algoritma Verimsizliği"(Strategy/Algorithm Inefficiency:) olarak adlandırılan ikinci ana anti-patron ele alınmaktadır. Bu anti-patron, iyi performans göstermeyen bir algoritma veya strateji seçimiyle ilgilidir. Ayrıca, yanlış algoritma yapılandırması veya parametreleme ile doğru algoritmanın seçilmesi de dahildir.
Bu durum, algoritmaların karmaşıklığının "Büyük O" notasyonu ile karşılaştırılmasından çok, daha basit ve yaygın işlerle ilgilidir. Çünkü çoğu şirket yazılımı, algoritma karmaşıklığından çok verinin bir noktadan diğerine taşınmasıyla ilgilenir.
Bu anti-patron, sadece algoritmalarla değil, aynı zamanda veri erişim stratejileri gibi stratejilerle de ilgilidir. Algoritmanın uygulanması genellikle tek bir yerde olurken, bir strateji, kodun sistemin dört bir yanına yayılması nedeniyle daha zor ayarlanabilir veya değiştirilebilir olabilir.
Erken geliştirme aşamasında performans testleri kullanmak, değiştirmesi maliyetli olan düşük performanslı bir kod stratejisine yatırım yapmaktan kaçınmaya yardımcı olabilir. Örneğin, 25'ten fazla veritabanı veya diğer arka uç isteği gerçekleştirmenin iyi performans gösterip göstermeyeceğini erken aşamada keşfedebilirsiniz.

Bu ana anti-patern, uygun olmayan bir algoritma veya strateji seçimi ile ilgilidir. Örnek olarak, veritabanına çok sayıda ayrı sorgu göndermek yerine, aynı verileri bir kezde almak için optimize edilmiş bir sorgu kullanma durumunu ele alalım.

Yanlış Strateji: Veritabanına Aşırı Sorgulama
Bu kod parçacığı, veritabanından belirli bir koşula uyan her ürünün ayrı ayrı alındığı bir durumu göstermektedir. Bu, veritabanına gereksiz yere çok sayıda sorgu gönderilmesine neden olabilir.

java
Copy code
public class InefficientStrategy {
    public List<Product> getProducts(Connection connection, List<Integer> productIds) throws SQLException {
        List<Product> products = new ArrayList<>();
        for (int productId : productIds) {
            PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE id = ?");
            statement.setInt(1, productId);
            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                products.add(new Product(rs.getInt("id"), rs.getString("name"), rs.getDouble("price")));
            }
        }
        return products;
    }
}
Doğru Strateji: Tek Sorguda Toplu Alma
Bunu düzeltmek için, aynı verileri tek bir sorguyla alabilecek bir SQL sorgusu kullanabiliriz. Bu, veritabanına yapılan I/O çağrılarını azaltır ve genel performansı artırır.

java
Copy code
public class EfficientStrategy {
    public List<Product> getProducts(Connection connection, List<Integer> productIds) throws SQLException {
        List<Product> products = new ArrayList<>();
        String joinedIds = productIds.stream().map(String::valueOf).collect(Collectors.joining(", "));
        String query = "SELECT * FROM products WHERE id IN (" + joinedIds + ")";
        Statement statement = connection.createStatement();
        ResultSet rs = statement.executeQuery(query);
        while (rs.next()) {
            products.add(new Product(rs.getInt("id"), rs.getString("name"), rs.getDouble("price")));
        }
        return products;
    }
}
Bu kod, bir kezde birden fazla ürün almak için SQL IN anahtar sözcüğünü kullanır, böylece tüm ürünler tek bir sorguyla alınabilir. Bu, I/O maliyetini önemli ölçüde azaltır ve uygulamanın performansını artırır.

Bu stratejinin doğru veya yanlış olduğunu belirtmek önemlidir. Yukarıdaki iki yaklaşımın hangisinin uygun olduğu, spesifik kullanım durumuna ve gereksinimlere bağlıdır. Ancak, genellikle, veritabanına yapılan gereksiz yere aşırı sorguları azaltmak, performansı önemli ölçüde artırabilir.



 "Aşırı İşleme"(Overprocessing) olarak adlandırılan üçüncü ana anti-patron tanıtılmaktadır. Bu anti-patron, yalnızca marjinal olarak geçerli olan kaynak yoğun kullanım senaryolarına yönelik yanlış girişimlerle ilgilidir.

Bir örnek, bir kullanıcının tek bir ekran dolusu veya web sayfası bilgisiyle yararlanabileceğinden daha fazla verinin işlenmesidir. 100 ms içinde yüklenmesi beklenen tek bir HTML tablosunda 50 sayfa veri beklemek gerçekçi değildir. Ancak, “sonraki sayfa” düğmesiyle 3 sayfa veri oldukça iyi performans gösterebilir.

Bu anti-patronun değerlendirilmesi bazı teknik uzmanlık gerektirse de, daha çok iş uzmanlığına dayalıdır. Hangi iş süreçlerinin üretimde kullanılacağını ve bunların kabaca yüzdeliklerini bilmek yararlı olacaktır.

Aşırı İşleme anti-patronuna sıkça neden olan bir durum, test veritabanlarının, üretimde hiçbir zaman bu kadar büyük veya karmaşık olmayan bazı "süper müşteriler" içermesidir.

Bu senaryonun bir yolu, yük testinizde yanlışlıkla yer alsa bile, kullanıcıların nadiren geçtiği belirli bir kod bölümü üzerinde çok zaman harcamanızdır. Bu zaman kaybıdır.

Başka bir örnek, işlenmesi ekstra zaman alan yanlışlıkla aşırı boyutlandırılmış bir RDBMS sonuç kümesidir. Bunun nedeni, bir SELECT ifadesinde yanlış yerleştirilmiş bir genel arama karakteri veya veritabanındaki beklenmeyen ve geçersiz veri olabilir.

Performans ayarının, kodu daha hızlı hale getirmek kadar akıllıca hangi iş süreçlerini yük testi yapacağınıza dair kararlar almakla da ilgili olduğunu unutmamak önemlidir. Bunun, performans endişelerini karşılamak için web sayfası boyutlarını küçük tutmak gibi performans ve kullanıcı arayüzü tasarımı arasındaki dengelemelerle de ilgili olduğu anlamına gelir.

Bu, sisteminizin kaputunun altına bakarken, büyük bir sonuç kümesinden şüpheli performans gördüğünüzde, düşünmenizi yeniden yönlendirmeniz ve daha soyut şeyleri, performans/kullanılabilirlik değiş tokuşları gibi düşünmeniz gerektiği anlamına gelir. Bu insan bağlam değişimi kolay değildir, ancak düşünün: Bazı ayarlama zorlukları, yük testinde baştan yer almaması gereken gerçeküstü kullanım durumları nedeniyle tamamen önlenebilir.


Bu anti-patern, gereksiz veri işleme ya da kullanıcı için çok fazla veri sunma gibi durumları ele alır. Aşağıda, bu tür bir durumda yanlış yapılan bir şeyi ve nasıl düzeltileceğini gösteren Java kod örnekleri verilmiştir.

Yanlış Strateji: Fazla Veri Yüklemek
Bu kod parçacığı, bir web sayfasında gösterilmek üzere tüm müşteri verilerini yüklemektedir. Bu, kullanıcının bir seferde kullanamayacağı çok fazla veri olabilir, böylece zaman ve kaynak israfına yol açar.

java
Copy code
public class OverprocessingExample {
    public List<Customer> getAllCustomers(Connection connection) throws SQLException {
        List<Customer> customers = new ArrayList<>();
        Statement statement = connection.createStatement();
        ResultSet rs = statement.executeQuery("SELECT * FROM customers");
        while (rs.next()) {
            customers.add(new Customer(rs.getInt("id"), rs.getString("name"), rs.getString("email")));
        }
        return customers;
    }
}
Doğru Strateji: Sayfalama Kullanarak Veriyi Parçalara Bölmek
Bu durumu düzeltmek için, sayfalama kullanarak yalnızca kullanıcının şu anda ihtiyaç duyduğu verileri yükleyebiliriz. Bu, gereksiz yere büyük miktarda veri işlemesini önler.

java
Copy code
public class EfficientProcessingExample {
    public List<Customer> getCustomersWithPagination(Connection connection, int page, int pageSize) throws SQLException {
        List<Customer> customers = new ArrayList<>();
        String query = "SELECT * FROM customers LIMIT ? OFFSET ?";
        PreparedStatement statement = connection.prepareStatement(query);
        statement.setInt(1, pageSize);
        statement.setInt(2, (page - 1) * pageSize);
        ResultSet rs = statement.executeQuery();
        while (rs.next()) {
            customers.add(new Customer(rs.getInt("id"), rs.getString("name"), rs.getString("email")));
        }
        return customers;
    }
}
Bu kod, veritabanından yalnızca belirli bir sayfa boyutuna uygun müşterileri alır, böylece kullanıcı için gerçekten gerekli olan verileri işler. "Önceki" ve "Sonraki" düğmeleri kullanarak kullanıcının diğer verilere erişmesine olanak tanır.

Bu örnek, performansı artırmak ve işlem yükünü azaltmak için veri yüklemesinin nasıl optimize edilebileceğini göstermektedir. İlgili kullanım durumuna bağlı olarak, bu gibi stratejilerle, uygulamanın gereksiz işlemler yapmasını önleyebilir ve kullanıcı deneyimini iyileştirebilirsiniz.


Ana Anti-Patron #4, “Büyük İşleme Sorunu(Large Processing Challenge)nu tanımlar. Bu anti-patron, birkaç milyar satır veri üzerinde arama gibi büyük performans sorunlarına, I/O ve diğer donanım kısıtlamalarına işaret eder. Şirket yazılımı geliştirmede bu tür büyük, zorlu sorunlar nadiren ortaya çıkar. Ancak böyle bir sorunla karşılaştığınızda, ekstra tasarım ve test özeni, saygı ve tedirginlikle yaklaşmanızı öneririm. Geri kalan her şeyi optimize etmek neredeyse önemsizdir.
“Büyük İşleme Sorunu”, dört Ana Anti-Patron'un sonuncusudur. Birinci en çok karşılaşılan iken dördüncü en az karşılaşılandır. Bu büyük sorunlarla düzenli olarak karşılaşıyorsanız, bu durumda bir istisna olarak kabul edebilirsiniz. Ancak, çoğumuz şirket web uygulamaları yazarken, bu tür korku uyandıran büyük işleme sorunları çok azdır.
Büyük sorunlara örnekler şunlar olabilir:
200 milyon kayıtlı bir tabloda sadece birkaç kayıt üzerinde arama yapmak.
Özellikle uzun mesafelerde, yavaş bir ağ üzerinden tekrar tekrar çok miktarda veri (örneğin bir megabayttan fazla) aktarmak.
Çoklu iş parçacığı performansının doğru bir şekilde elde edilmesi zor olsa da, bir başkasının zaten performansı doğru bir şekilde elde ettiği birçok kullanıma hazır API ve çözüm bulunmaktadır.
Bu büyük sorunlara hazırlanmak çok çalışma gerektirdiğinden, hazırlıkların tasarım belgesi oluşturulduğunda başlaması gerektiği gibi görünmektedir. Eğer büyük bir işleme sorunundan gerçekten korkuyorsanız, projenin erken aşamasında bunun uygulanabilirliğini test etmek için zaman ayırın; belki donanım uzmanları burada katkı sağlayabilir.
Büyük işleme sorunları, performans sorunlarını vurgulayan bir performans radarında ortaya çıkar. Büyük işleme sorunlarını ele almanın zor işi nedeniyle, geliştirme ekipleri ekstra çalışmayı öngörmeli ve performans ayarlama çabasının önceliğini artırmalıdır. Ancak, daha küçük performans sorunları performans radarında ortaya çıktığında, büyük performans sorunlarını ayarlama gibi diğer önceliklerin önüne geçerler. Tasarım, geliştirme, QA vb. diğer geliştirme yaşam döngüsü parçalarından da zaman çalarlar.
Küçük performans sorunlarını ayarlamak, temelde bir rahatsızlıktır; tecrübeme göre, küçük performans sorunlarındaki yavaşlamalar, tüm performans kusurlarının beklenmedik büyük bir bölümünü oluşturur.
Özellikle, işleme meydan okumanın büyüklüğü küçük ve kullanılan API kamuya açık olduğunda, başkaları zaten sorunları belgelemiş ve makul çözüm yolları bulmuş olabilir.
Bu anti-patron, ekiplerin bu tür sorunlara nasıl yaklaşması gerektiğine dair somut öneriler ve ipuçları sağlar, böylece daha etkili ve verimli olabilirler.

Bu anti-patern, genellikle geniş bir ölçekte, çok büyük veri setleri üzerinde işlem yapmanın zorluklarını tanımlar. Aşağıda böyle bir durumda yanlış olan bir şeyi ve nasıl düzeltileceğini gösteren Java kod örnekleri verilmiştir.

Yanlış Yaklaşım: Büyük Bir Veri Seti Üzerinde Basit Bir Arama
Bu kod parçacığı, 200 milyon kayıttan oluşan bir tabloda belirli bir kaydı aramaktadır. Bu, büyük bir işlem zorluğunu temsil eder ve ölçeklendirmek zor olabilir.

java
Copy code
public class LargeProcessingChallenge {
    public Customer findCustomerById(Connection connection, int id) throws SQLException {
        Statement statement = connection.createStatement();
        ResultSet rs = statement.executeQuery("SELECT * FROM customers WHERE id=" + id);
        if (rs.next()) {
            return new Customer(rs.getInt("id"), rs.getString("name"), rs.getString("email"));
        }
        return null;
    }
}
Doğru Yaklaşım: Veri Yapılarını ve Algoritmaları Optimize Etme
Büyük veri setlerinde işlem yaparken, özel indeksler, önbellekleme veya daha verimli algoritmalar gibi veri yapılarını ve teknikleri kullanmak önemlidir. Aşağıdaki örnek, veritabanındaki bir indeksi kullanarak arama işlemini optimize etmektedir.

java
Copy code
public class OptimizedLargeProcessingChallenge {
    public Customer findCustomerById(Connection connection, int id) throws SQLException {
        // Bu sorgu, "id" alanı üzerinde bir indeks olduğunu varsayarak optimize edilmiştir.
        PreparedStatement statement = connection.prepareStatement("SELECT * FROM customers WHERE id = ?");
        statement.setInt(1, id);
        ResultSet rs = statement.executeQuery();
        if (rs.next()) {
            return new Customer(rs.getInt("id"), rs.getString("name"), rs.getString("email"));
        }
        return null;
    }
}
Bu örnek, büyük veri setleri üzerinde işlem yapmanın zorluklarını ve bunları aşmak için bazı stratejileri göstermektedir. Ancak, büyük işlem zorluklarını ele almanın doğru yolu genellikle özel ve karmaşıktır, bu nedenle belirli bir duruma uygun en iyi çözümü bulmak için dikkatli analiz ve planlama gerekebilir. Daha özel ve etkili çözümler, paralel işlem, veri parçalama, önbellekleme gibi teknikler ve uygun donanım veya bulut kaynakları kullanmayı içerebilir.

Spring Boot / Java örnekleri

Anti-Pattern #1: Gereksiz Başlatma
Bu anti-pattern, gereksiz veya aşırı nesne başlatma işlemleri nedeniyle kaynakların verimsiz bir şekilde kullanılmasına neden olur.

Yanlış Yaklaşım
Aşağıdaki örnek, her istekte yeni bir servis nesnesi oluşturduğundan, gereksiz başlatma işlemlerinin bir örneğini göstermektedir.

java
Copy code
@RestController
public class UserController {

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        // Her istekte yeni bir servis nesnesi oluşturuluyor
        UserService userService = new UserService();
        return userService.findUserById(id);
    }
}
Bu yaklaşım, özellikle yüksek yük altında, bellek kullanımının ve GC basıncının artmasına neden olabilir.

Doğru Yaklaşım
Gereksiz başlatma sorununu çözmek için Spring'in Dependency Injection (DI) özelliğinden yararlanabiliriz. Aşağıdaki örnek, UserService'i bir bean olarak enjekte ederek bu sorunu nasıl düzelteceğimizi göstermektedir.

java
Copy code
@RestController
public class OptimizedUserController {

    @Autowired
    private UserService userService; // UserService Spring bean olarak enjekte ediliyor

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findUserById(id); // Aynı servis nesnesi yeniden kullanılıyor
    }
}
Bu düzeltilmiş sürüm, aynı UserService nesnesini yeniden kullanır, böylece gereksiz başlatma işlemlerini önler ve uygulamanın performansını artırır.



Elbette! Şimdi ikinci anti-pattern olan "Strateji/Algoritma Verimsizliği" üzerine odaklanacağım.

Anti-Pattern #2: Strateji/Algoritma Verimsizliği
Bu anti-pattern, verimsiz bir algoritma veya stratejinin seçilmesi durumunda ortaya çıkar. Uygulamanın performansını düşürebilir veya ölçeklenebilirliği zorlaştırabilir.

Yanlış Yaklaşım
Aşağıdaki örnek, her istekte tüm kullanıcıları veritabanından getirip, ardından belirli bir kullanıcıyı bulan verimsiz bir kod örneğini göstermektedir.

java
Copy code
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User findUserById(Long id) {
        List<User> allUsers = userRepository.findAll(); // Tüm kullanıcıları getir
        return allUsers.stream()
                .filter(user -> user.getId().equals(id))
                .findFirst()
                .orElse(null); // Ardından belirli bir kullanıcıyı filtrele
    }
}
Bu yaklaşım, büyük bir kullanıcı tablosu olduğunda performans problemlerine neden olabilir.

Doğru Yaklaşım
Doğru bir strateji kullanarak, yalnızca gerekli olan kullanıcıyı doğrudan veritabanından getirebiliriz. Bu, performansı artıracak ve ölçeklenebilirliği kolaylaştıracaktır.

java
Copy code
@Service
public class OptimizedUserService {

    @Autowired
    private UserRepository userRepository;

    public User findUserById(Long id) {
        return userRepository.findById(id) // Yalnızca belirli bir kullanıcıyı getir
                .orElse(null);
    }
}
Bu durumda, veritabanı sorgusu yalnızca gerekli olan kullanıcıyı getirir, böylece gereksiz veritabanı erişimi ve veri işleme maliyeti önlenir.

Bu ikinci anti-pattern için açıklamalarım bu kadar. Devam etmek isterseniz, lütfen bana bildirin!

Tabii ki! Şimdi üçüncü anti-pattern olan "Overprocessing" üzerine odaklanalım.

Anti-Pattern #3: Overprocessing
Overprocessing, gereğinden fazla işlem yapmak anlamına gelir. İster kullanıcı arayüzü, isterse veritabanı sorguları olsun, gereksiz işlemler sistemin performansını düşürebilir.

Yanlış Yaklaşım
Aşağıdaki örnek, her kullanıcı için detaylı profil bilgilerini de içerecek şekilde tüm kullanıcıları getirmeyi deneyen bir hizmeti gösterir. Bu, gereğinden fazla veri yüklemek anlamına gelebilir, özellikle de kullanıcının yalnızca birkaç kullanıcıyı görmek istediği bir durumda.

java
Copy code
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<UserDetailedInfo> getAllUsersWithDetails() {
        List<User> users = userRepository.findAll();
        return users.stream()
                .map(user -> fetchDetailedInfo(user))
                .collect(Collectors.toList());
    }

    private UserDetailedInfo fetchDetailedInfo(User user) {
        // Kullanıcı için ayrıntılı bilgi getir (Örnek: profili, arkadaş listesi vs.)
        // Bu işlem, çok fazla veri getirmek ve işlemek anlamına gelebilir.
    }
}
Doğru Yaklaşım
Bu durumda, kullanıcının gerçekten neye ihtiyacı olduğunu belirlemek önemlidir. Eğer detaylara gerek yoksa, yalnızca gerekli bilgileri getirerek bu anti-pattern'ı düzeltebiliriz.

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    @Query("SELECT new com.example.UserBasicInfo(u.name, u.email) FROM User u")
    List<UserBasicInfo> findAllBasicInfo();
}

@Service
public class OptimizedUserService {

    @Autowired
    private UserRepository userRepository;

    public List<UserBasicInfo> getAllUsers() {
        // Yalnızca kullanıcının temel bilgilerini veritabanından çeker
        return userRepository.findAllBasicInfo();
    }
}
Bu durumda, gereksiz ayrıntıları getirmek yerine, yalnızca kullanıcıların temel bilgilerini getiriyoruz. Bu, veritabanı sorgularını, ağ trafiğini ve istemci tarafı işlemesini önemli ölçüde azaltabilir.

Bu, Overprocessing anti-pattern'ı için uygun bir çözüm olabilir. Devam etmek isterseniz, lütfen bana bildirin!

Elbette, son anti-pattern olan "Large Processing Challenge" üzerinde konuşalım.

Anti-Pattern #4: Large Processing Challenge
Bu anti-pattern, I/O veya diğer donanım kısıtlamalarının neden olduğu büyük performans zorluklarıyla ilgilidir. Bu gibi durumlar oldukça nadirdir ancak karşılaşıldığında ekstra dikkat gerektirir.

Yanlış Yaklaşım
Bu örnek, bir tabloda birkaç milyar satıra sahip olabilecek büyük bir veritabanı sorgusu oluşturur. Bu, performansı ciddi şekilde etkileyebilir.

java
Copy code
@Service
public class ProductSearchService {

    @Autowired
    private ProductRepository productRepository;

    public List<Product> searchProducts(String keyword) {
        // Bu sorgu, milyarlarca kayıt içeren bir tabloyu tarayabilir.
        return productRepository.findProductsByKeyword(keyword);
    }
}
Doğru Yaklaşım
Bu tür büyük işlem zorlukları, özel bir dikkat ve optimizasyon gerektirir. İlk adım, gerekli olmayan verilerin işlenmesini önlemektir. İkinci adım, uygun indeksleme, önbellekleme ve veritabanı optimizasyonlarını kullanmaktır.

java
Copy code
@Service
public class OptimizedProductSearchService {

    @Autowired
    private ProductRepository productRepository;

    public Page<Product> searchProducts(String keyword, Pageable pageable) {
        // Sonuçları sayfalamak, verilerin yalnızca bir kısmını yüklememize izin verir.
        return productRepository.findProductsByKeyword(keyword, pageable);
    }
}
Bu durumda, yalnızca gerekli olan sonuçları yüklemek için sayfalama kullanıyoruz. Ayrıca, uygun veritabanı indeksleri kullanmak ve sorgunun etkin bir şekilde çalıştığından emin olmak için ekstra çalışma yapabilirsiniz.

Bu yaklaşım, "Large Processing Challenge" anti-pattern'ını çözmek için uygun bir yoldur. Sorgunun yalnızca gerçekten ihtiyaç duyulan kısmını işlemek, sistem kaynaklarını önemli ölçüde azaltabilir.

Hiç yorum yok

Rastgele İçerik

DonanımHaber

© tüm hakları saklıdır
made with by templateszoo