<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[folksdev - Medium]]></title>
        <description><![CDATA[Kanalımızı ziyaret ettiğin için teşekkür ederiz. Folksdev, yazılımcılardan oluşan bir topluluktur. Her seviyeden yazılımcılar ile eğitimler, meetup’lar, bootcamp’ler düzenliyoruz. Eğer sen de bu ailenin bir parçası olmak istersen: https://linktr.ee/folksdev - Medium]]></description>
        <link>https://medium.com/folksdev?source=rss----1c0fe5b20e42---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>folksdev - Medium</title>
            <link>https://medium.com/folksdev?source=rss----1c0fe5b20e42---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 14 May 2026 23:13:11 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/folksdev" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[[TR] Designing Data-Intensive Applications — Bölüm 2 Özeti]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/folksdev/tr-designing-data-intensive-applications-b%C3%B6l%C3%BCm-2-%C3%B6zeti-191bda081d45?source=rss----1c0fe5b20e42---4"><img src="https://cdn-images-1.medium.com/max/1000/1*DA7v4vLjobHiNFXaUaeHPA.png" width="1000"></a></p><p class="medium-feed-snippet">Veri Modelleri ve Sorgu Dilleri: Do&#x11F;ru Arac&#x131; Se&#xE7;mek</p><p class="medium-feed-link"><a href="https://medium.com/folksdev/tr-designing-data-intensive-applications-b%C3%B6l%C3%BCm-2-%C3%B6zeti-191bda081d45?source=rss----1c0fe5b20e42---4">Continue reading on folksdev »</a></p></div>]]></description>
            <link>https://medium.com/folksdev/tr-designing-data-intensive-applications-b%C3%B6l%C3%BCm-2-%C3%B6zeti-191bda081d45?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/191bda081d45</guid>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[neo4j]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[nosql]]></category>
            <category><![CDATA[sql]]></category>
            <dc:creator><![CDATA[Furkan Özmen]]></dc:creator>
            <pubDate>Sun, 17 Aug 2025 08:04:21 GMT</pubDate>
            <atom:updated>2025-08-17T08:05:44.202Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Understanding Pod Eviction and How to Use the Kubernetes Descheduler]]></title>
            <link>https://medium.com/folksdev/understanding-pod-eviction-and-how-to-use-the-kubernetes-descheduler-a1a7a0975072?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/a1a7a0975072</guid>
            <category><![CDATA[descheduler]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[chaos-engineering]]></category>
            <category><![CDATA[eviction]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Emirhan Doğandemir]]></dc:creator>
            <pubDate>Thu, 19 Jun 2025 19:02:12 GMT</pubDate>
            <atom:updated>2025-06-20T05:46:04.863Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wESSue5pHbElXE_SN_XrHA.png" /><figcaption>Evicted</figcaption></figure><p><strong>In this article, you will learn about:</strong></p><ul><li>Reasons why Pods get evicted: Preemption and Node Pressure</li><li>How Preemption eviction works</li><li>Understanding Pod Priority Classes</li><li>Node Pressure eviction explained</li><li>Exploring Quality of Service (QoS) Classes</li><li>How the Kubernetes Descheduler helps manage evictions</li><li>Common Descheduler strategies for improving cluster balance</li><li>When and why you might want to use the Descheduler in your cluster</li><li>How to install and usage Descheduler</li></ul><h4><strong>What is Evicted Pods in Kubernetes ?</strong></h4><p>In Kubernetes, when a Pod is evicted, it means the Pod is forcibly terminated, often because the cluster is running low on critical resources such as memory or CPU. But what leads to this situation?</p><p>Eviction is a process where a Pod running on a Node is asked to terminate. One of the most common cases in Kubernetes is preemption, where a Pod needs to be evicted to make room for a new Pod when the Node doesn’t have enough available resources.</p><h4><strong>Reasons why Pods get evicted: Preemption and Node Pressure</strong></h4><p>In Kubernetes, Pods are evicted primarily for two reasons: <strong>preemption</strong> and <strong>node pressure</strong>. Preemption happens when a higher-priority Pod needs to be scheduled, but there aren’t enough available resources on any node — forcing the system to evict lower-priority Pods to make room. Node pressure eviction occurs when a node runs critically low on essential resources like memory, CPU, or disk space, and Kubernetes needs to terminate some Pods to maintain node stability and prevent failure.</p><h4><strong>How Preemption eviction works</strong></h4><p>Preemption is the process where the Kubernetes scheduler evicts existing Pods to make room for a higher-priority Pod. When a Node doesn’t have enough available resources and the new Pod has a higher priority than the ones already running, the scheduler terminates lower-priority Pods to free up space. This mechanism ensures that critical applications are not blocked by less important workloads.</p><h4><strong>Understanding Pod Priority Classes</strong></h4><p>Pod Priority Classes are used in Kubernetes to assign priority levels to Pods.<br>These classes help determine which Pods should stay running and which should be evicted when the cluster experiences resource shortages.<br>Pods with higher priority are scheduled before lower-priority ones and are better protected when resources become scarce. This system ensures that critical applications remain operational even under resource constraints.</p><p>Below you can see two examples of Priority Class:</p><pre>apiVersion: scheduling.k8s.io/v1<br>kind: PriorityClass<br>metadata:<br>  name: high-priority-emirhan<br>value: 1000000<br>preemptionPolicy: PreemptLowerPriority<br>globalDefault: false<br>description: &quot;This priority class is for important workloads.&quot;<br>---<br>apiVersion: scheduling.k8s.io/v1<br>kind: PriorityClass<br>metadata:<br>  name: low-priority-emirhan<br>value: 50000<br>preemptionPolicy: PreemptLowerPriority<br>globalDefault: false<br>description: &quot;This priority class is for less critical workloads.&quot;</pre><p>Below you can see the pod sample where two examples of priority classes are used:</p><pre>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: high-priority-pod<br>spec:<br>  priorityClassName: high-priority<br>  containers:<br>  - name: nginx<br>    image: nginx<br>---<br>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: low-priority-pod<br>spec:<br>  priorityClassName: low-priority<br>  containers:<br>  - name: nginx<br>    image: nginx</pre><p>If the node experiences resource pressure, the low-priority Pod will be evicted while the high-priority Pod will continue running, as Kubernetes uses the preemption mechanism to make room for higher-priority Pods.</p><h4>Node Pressure eviction explained</h4><p>Node pressure eviction happens when a Node starts running out of critical resources like memory, CPU, or disk space.<br> To prevent the Node from crashing, Kubernetes selects and evicts certain Pods, usually starting with lower-priority or lower-quality (QoS) Pods.<br> This automatic mechanism helps maintain cluster health and balances resource usage across the Nodes.</p><p><strong>Exploring Quality of Service (QoS) Classes</strong></p><p>In Kubernetes, Quality of Service (QoS) classes categorize Pods based on their resource requests and limits.<br> There are three main QoS classes: <strong>Guaranteed</strong>, <strong>Burstable</strong>, and <strong>BestEffort</strong>.</p><ul><li><strong>Guaranteed</strong> Pods specify both requests and limits for their resources and receive the highest level of protection.</li><li><strong>Burstable</strong> Pods have partial protection, with some resource limits defined but not fully guaranteed.</li><li><strong>BestEffort</strong> Pods do not specify any resource guarantees and have the lowest priority.<br> When a node faces resource pressure, Kubernetes evicts BestEffort Pods first, followed by Burstable Pods, and only as a last resort, Guaranteed Pods.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PGa4sBafG_QnRUjqEUmUkg.png" /><figcaption>QoS Classes</figcaption></figure><h4><strong>How the Kubernetes Descheduler helps manage evictions</strong></h4><p>The Kubernetes scheduler places Pods across the cluster based on available resources and policies. However, over time, the cluster’s conditions change— new Pods are added, old ones are removed, and resource usage can become unbalanced. This is where the <strong>Descheduler</strong> comes into play.<br>The Descheduler evaluates the current state and can recommend or perform the eviction and rescheduling of Pods to more appropriate Nodes. By doing so, it helps reduce <strong>node pressure</strong>, improves <strong>load balancing</strong>, and ensures that <strong>high-priority Pods</strong> have a better environment to run. In short, the Descheduler keeps the cluster healthy by making smarter use of available resources over time.</p><h4><strong>Common Descheduler strategies for improving cluster balance</strong></h4><p>The Descheduler uses several strategies to optimize resource usage and maintain balance across the cluster.<br> Some of the most common strategies include:</p><ul><li><strong>RemovePodsViolatingInterPodAntiAffinity</strong>: Reschedules Pods that violate inter-pod anti-affinity rules.</li><li><strong>RemovePodsViolatingNodeAffinity</strong>: Moves Pods that do not comply with node affinity constraints to appropriate nodes.</li><li><strong>RemovePodsViolatingTopologySpreadConstraint</strong>: Ensures Pods are evenly distributed across nodes according to topology spread constraints.</li><li><strong>LowNodeUtilization</strong>: Evicts Pods from underutilized nodes and redistributes them to achieve better resource utilization. These strategies help reduce node pressure, improve load distribution, and enhance the overall performance and stability of the cluster.</li><li><strong>HighNodeUtilization:</strong> Targets nodes that are heavily overutilized and evicts Pods to relieve resource pressure. By redistributing Pods to less busy nodes, this strategy improves overall cluster balance and prevents performance degradation on overloaded nodes.</li></ul><h4><strong>When and why you might want to use the Descheduler in your cluster</strong></h4><p>While the Kubernetes scheduler does a good job placing Pods initially, over time the balance of the cluster can drift. As new Pods are deployed, resource usage changes, or some Pods behave unpredictably, certain Nodes may become overloaded while others remain underutilized. This imbalance can impact cluster efficiency and application performance. You might want to use the Descheduler to:</p><ul><li>Rebalance resource usage across Nodes,</li><li>Proactively redistribute Pods before node pressure becomes critical,</li><li>Move Pods that violate affinity or taint rules,</li><li>Improve overall cluster health and scalability.<br> The Descheduler is especially valuable in production environments where clusters run for long periods and workloads constantly evolve.</li></ul><h4>How to install and usage Descheduler</h4><pre>$ helm repo add descheduler https://kubernetes-sigs.github.io/descheduler/<br>$ helm repo update</pre><p>Below are our values.yaml :</p><pre>kind: Deployment #1<br><br>schedule: &quot;&quot; #2<br><br>deschedulingInterval: 60s #3<br>replicas: 3 #4<br>leaderElection: #5<br>  enabled: true <br>deschedulerPolicy:<br>  strategies: #6<br>    LowNodeUtilization:<br>      enabled: true<br>      params:<br>        thresholds:<br>          cpu: 20<br>          memory: 20<br>        targetThresholds: #7<br>          cpu: 50<br>          memory: 50</pre><ol><li>Tells Helm to deploy the Descheduler as a <em>long-running</em> Deployment, not as a CronJob that wakes up on a schedule.</li><li>Empty string disables the CronJob template entirely (it only matters when kind is <em>CronJob</em>). Setting it to &quot;&quot; guarantees no CronJob is rendered.</li><li>Inside the Deployment, the Descheduler binary reruns itself every 60 seconds to check cluster state and evict pods if needed.</li><li>Creates <strong>three</strong> Descheduler pods for high availability. Only one will actively evict; the others wait on standby.</li><li>With multiple replicas, this switch makes them elect a leader so that only one pod performs evictions at any moment.</li><li>Enables the <em>LowNodeUtilization</em> strategy, which looks for nodes that are over- or under-used and moves pods away from over-loaded ones.</li><li>These are the “upper” limits. If a node’s CPU or memory usage rises <strong>above 50 %</strong>, it’s considered <em>busy</em> and pods can be evicted from it. The very high pods: 500 effectively says <em>ignore pod count; just use CPU/memory</em>.</li></ol><pre>$ helm install descheduler descheduler/descheduler --version 0.31.0 -n descheduler --create-namespace -f deschedulerdeployment.yaml</pre><p>Below are our helm’s output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/307/1*xJwpfB3hQAK_S8S1eRpQUA.png" /><figcaption>Helm chart release output</figcaption></figure><p>let’s check our descheduler pods:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/594/1*mSzKQH2_4LhP8bT46YCboA.png" /><figcaption>Descheduler pods</figcaption></figure><p>The current pod status is shown below:</p><pre>kubectl get pods -o wide<br>NAME                          READY   STATUS    RESTARTS      AGE     IP            NODE                     NOMINATED NODE   READINESS GATES<br>nginx-deploy-96b9d695-722xd   1/1     Running   3 (12h ago)   27d     10.244.2.4    k8s-playground-worker    &lt;none&gt;           &lt;none&gt;<br>nginx-deploy-96b9d695-8vffd   1/1     Running   3 (12h ago)   27d     10.244.1.14   k8s-playground-worker2   &lt;none&gt;           &lt;none&gt;<br>nginx-deploy-96b9d695-98phx   1/1     Running   0             2m14s   10.244.1.17   k8s-playground-worker2   &lt;none&gt;           &lt;none&gt;<br>nginx-deploy-96b9d695-q2fcp   1/1     Running   0             2m14s   10.244.2.15   k8s-playground-worker    &lt;none&gt;           &lt;none&gt;<br>nginx-deploy-96b9d695-rrkct   1/1     Running   3 (12h ago)   27d     10.244.1.9    k8s-playground-worker2   &lt;none&gt;           &lt;none&gt;</pre><p>Below is the YAML file we use for the CPU stress test:</p><pre><br>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: cpu-stress<br>spec:<br>  nodeName: k8s-playground-worker      <br>  containers:<br>  - name: stress<br>    image: polinux/stress-ng<br>    command: [&quot;/bin/sh&quot;,&quot;-c&quot;]<br>    args: [&quot;stress-ng --cpu 16--timeout 300s&quot;]<br>    resources:<br>      requests:<br>        cpu: &quot;9000m&quot;<br>      limits:<br>        cpu: &quot;9000m&quot;<br>  restartPolicy: Never</pre><pre>$ kubectl apply -f cpustresspod.yaml</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/888/1*WV0CnyySe-Phyv8Ks_EGtw.png" /><figcaption>cpu stress test</figcaption></figure><p>Below is the output from one of the Descheduler pods:</p><pre>I0619 18:18:51.783561       1 lownodeutilization.go:150] &quot;Number of overutilized nodes&quot; totalNumber=1<br>I0619 18:18:51.783605       1 nodeutilization.go:261] &quot;Total capacity to be moved&quot; CPU=10450 Mem=1433800704 Pods=84<br>I0619 18:18:51.783639       1 nodeutilization.go:264] &quot;Evicting pods from node&quot; node=&quot;k8s-playground-worker&quot; usage={&quot;cpu&quot;:&quot;10100m&quot;,&quot;memory&quot;:&quot;562Mi&quot;,&quot;pods&quot;:&quot;14&quot;}<br>I0619 18:18:51.783719       1 nodeutilization.go:267] &quot;Pods on node&quot; node=&quot;k8s-playground-worker&quot; allPods=14 nonRemovablePods=5 removablePods=9<br>I0619 18:18:51.783743       1 nodeutilization.go:274] &quot;Evicting pods based on priority, if they have same priority, they&#39;ll be evicted based on QoS tiers&quot;<br>I0619 18:18:51.902877       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;default/nginx-deploy-96b9d695-972w9&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default<br>&quot;<br>I0619 18:18:51.907219       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;default/nginx-deploy-96b9d695-972w9&quot;<br>I0619 18:18:51.907992       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=13<br>I0619 18:18:52.011975       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-l9kbh&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.018723       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-l9kbh&quot;<br>I0619 18:18:52.020331       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=12<br>I0619 18:18:52.145416       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-w424w&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.145570       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-w424w&quot;<br>I0619 18:18:52.150791       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=11<br>I0619 18:18:52.271926       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-z9fxh&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.271970       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-z9fxh&quot;<br>I0619 18:18:52.271984       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=10<br>I0619 18:18:52.404432       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;default/nginx-deploy-96b9d695-rphhb&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default<br>&quot;<br>I0619 18:18:52.404502       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;default/nginx-deploy-96b9d695-rphhb&quot;<br>I0619 18:18:52.404519       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=9<br>I0619 18:18:52.505450       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-96skg&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.509694       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-96skg&quot;<br>I0619 18:18:52.510311       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=8<br>I0619 18:18:52.625005       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-9k6vc&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.625092       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-9k6vc&quot;<br>I0619 18:18:52.625110       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=7<br>I0619 18:18:52.724450       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-x5qm9&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.724505       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-x5qm9&quot;<br>I0619 18:18:52.724521       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=6<br>I0619 18:18:52.846428       1 evictions.go:186] &quot;Evicted pod&quot; pod=&quot;test/redis-748ffbc5f5-2m5kt&quot; reason=&quot;&quot; strategy=&quot;LowNodeUtilization&quot; node=&quot;k8s-playground-worker&quot; profile=&quot;default&quot;<br>I0619 18:18:52.854322       1 nodeutilization.go:325] &quot;Evicted pods&quot; pod=&quot;test/redis-748ffbc5f5-2m5kt&quot;<br>I0619 18:18:52.854410       1 nodeutilization.go:350] &quot;Updated node usage&quot; node=&quot;k8s-playground-worker&quot; CPU=10100 Mem=589299712 Pods=5<br>I0619 18:18:52.854462       1 profile.go:345] &quot;Total number of pods evicted&quot; extension point=&quot;Balance&quot; evictedPods=9<br>I0619 18:18:52.854494       1 descheduler.go:179] &quot;Number of evicted pods&quot; totalEvicted=11<br></pre><p>The <a href="https://github.com/kubernetes-sigs/descheduler/tree/96c1c299ebde2f4279b3e0f01e6cf9848a827ca2#policy-default-evictor-and-strategy-plugins">official documentation</a> provides various usage examples for different Strategy Plugins, which will not be repeated here.</p><p>Sources I benefited from:</p><p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/#:~:text=Eviction%20is%20the%20process%20of%20terminating%20one%20or%20more%20Pods%20on%20Nodes.">Scheduling, Preemption and Eviction | Kubernetes</a></p><p><a href="https://sysdig.com/blog/kubernetes-pod-evicted/">Understanding Kubernetes Evicted Pods | Sysdig</a></p><p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">Node-pressure Eviction | Kubernetes</a></p><p>Thank you for reading until the end. Before you go:</p><p>Please remember to clap for this article and follow me! 👏 If you want to follow me, <a href="https://www.linkedin.com/in/emirhandogandemir/"><em>LinkedIn</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a1a7a0975072" width="1" height="1" alt=""><hr><p><a href="https://medium.com/folksdev/understanding-pod-eviction-and-how-to-use-the-kubernetes-descheduler-a1a7a0975072">Understanding Pod Eviction and How to Use the Kubernetes Descheduler</a> was originally published in <a href="https://medium.com/folksdev">folksdev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OpenID Connect (OIDC) Nedir ve Neden Gerekli?]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/folksdev/openid-connect-oidc-nedir-ve-neden-gerekli-d9de9aaec1f6?source=rss----1c0fe5b20e42---4"><img src="https://cdn-images-1.medium.com/max/1536/1*eAxy6krnfU_JXZUrl_g5-A.png" width="1536"></a></p><p class="medium-feed-snippet">OIDC Nedir?</p><p class="medium-feed-link"><a href="https://medium.com/folksdev/openid-connect-oidc-nedir-ve-neden-gerekli-d9de9aaec1f6?source=rss----1c0fe5b20e42---4">Continue reading on folksdev »</a></p></div>]]></description>
            <link>https://medium.com/folksdev/openid-connect-oidc-nedir-ve-neden-gerekli-d9de9aaec1f6?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/d9de9aaec1f6</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[auth]]></category>
            <category><![CDATA[oidc]]></category>
            <category><![CDATA[spring]]></category>
            <dc:creator><![CDATA[Furkan Özmen]]></dc:creator>
            <pubDate>Tue, 06 May 2025 13:17:00 GMT</pubDate>
            <atom:updated>2025-05-06T13:19:51.204Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[EC2 Üzerinde GitHub Actions Self-hosted Runner Kurulum Rehberi]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/folksdev/ec2-%C3%BCzerinde-github-actions-self-hosted-runner-kurulum-rehberi-8a07a7e75100?source=rss----1c0fe5b20e42---4"><img src="https://cdn-images-1.medium.com/max/1536/1*Epbr7KFZChdVeIcGTCZ9UA.png" width="1536"></a></p><p class="medium-feed-snippet">Selamlar, GitHub Actions&#x2019;ta self-hosted runner&#x2019;&#x131; kendi EC2 instance&#x2019;&#x131;mda kurup CI-CD s&#xFC;re&#xE7;lerini bunun &#xFC;zerinden &#xE7;al&#x131;&#x15F;t&#x131;rmay&#x131; g&#xF6;sterece&#x11F;im&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/folksdev/ec2-%C3%BCzerinde-github-actions-self-hosted-runner-kurulum-rehberi-8a07a7e75100?source=rss----1c0fe5b20e42---4">Continue reading on folksdev »</a></p></div>]]></description>
            <link>https://medium.com/folksdev/ec2-%C3%BCzerinde-github-actions-self-hosted-runner-kurulum-rehberi-8a07a7e75100?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/8a07a7e75100</guid>
            <category><![CDATA[ec2]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Furkan Özmen]]></dc:creator>
            <pubDate>Mon, 05 May 2025 16:01:39 GMT</pubDate>
            <atom:updated>2025-05-05T16:01:29.467Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[AWS CloudFront, S3 ve Lambda@Edge ile Real Time Görsel Optimizasyonu]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/folksdev/aws-cloudfront-s3-ve-lambda-edge-ile-real-time-g%C3%B6rsel-optimizasyonu-b44c0805da8a?source=rss----1c0fe5b20e42---4"><img src="https://cdn-images-1.medium.com/max/1024/1*iFVLFGxJIqMLEaEpHQpCqQ.png" width="1024"></a></p><p class="medium-feed-snippet">Giri&#x15F;: Neden G&#xF6;rseller Bu Kadar &#xD6;nemli?</p><p class="medium-feed-link"><a href="https://medium.com/folksdev/aws-cloudfront-s3-ve-lambda-edge-ile-real-time-g%C3%B6rsel-optimizasyonu-b44c0805da8a?source=rss----1c0fe5b20e42---4">Continue reading on folksdev »</a></p></div>]]></description>
            <link>https://medium.com/folksdev/aws-cloudfront-s3-ve-lambda-edge-ile-real-time-g%C3%B6rsel-optimizasyonu-b44c0805da8a?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/b44c0805da8a</guid>
            <category><![CDATA[lambda]]></category>
            <category><![CDATA[cloudfront]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[cdn-service]]></category>
            <dc:creator><![CDATA[Furkan Özmen]]></dc:creator>
            <pubDate>Sun, 04 May 2025 17:15:47 GMT</pubDate>
            <atom:updated>2025-05-04T17:07:50.755Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Designing Data-Intensive Applications — Bölüm 1 Özeti]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/folksdev/designing-data-intensive-applications-b%C3%B6l%C3%BCm-1-%C3%B6zeti-039f62a827d6?source=rss----1c0fe5b20e42---4"><img src="https://cdn-images-1.medium.com/max/1024/1*YXrmzezQm4BnLkakraqO4Q.png" width="1024"></a></p><p class="medium-feed-snippet">Data Intensive (Veri Yo&#x11F;un) Uygulamalara Yeni Bir Bak&#x131;&#x15F;</p><p class="medium-feed-link"><a href="https://medium.com/folksdev/designing-data-intensive-applications-b%C3%B6l%C3%BCm-1-%C3%B6zeti-039f62a827d6?source=rss----1c0fe5b20e42---4">Continue reading on folksdev »</a></p></div>]]></description>
            <link>https://medium.com/folksdev/designing-data-intensive-applications-b%C3%B6l%C3%BCm-1-%C3%B6zeti-039f62a827d6?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/039f62a827d6</guid>
            <category><![CDATA[data-integration]]></category>
            <category><![CDATA[designing-data]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[development]]></category>
            <dc:creator><![CDATA[Furkan Özmen]]></dc:creator>
            <pubDate>Fri, 02 May 2025 16:50:49 GMT</pubDate>
            <atom:updated>2025-08-17T07:46:44.166Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[gRPC: Yüksek Performanslı İletişim Kütüphanesi]]></title>
            <link>https://medium.com/folksdev/grpc-y%C3%BCksek-performansl%C4%B1-i%CC%87leti%C5%9Fim-k%C3%BCt%C3%BCphanesi-fe4031508e5f?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/fe4031508e5f</guid>
            <dc:creator><![CDATA[Ümit Sayın]]></dc:creator>
            <pubDate>Mon, 13 Jan 2025 06:27:19 GMT</pubDate>
            <atom:updated>2025-01-13T20:45:43.536Z</atom:updated>
            <content:encoded><![CDATA[<p>Bu yazımda, günümüz için önemli bir teknoloji olan gRPC’yi kapsamlı bir şekilde ele alarak sizlere aktarmak istiyorum, keyifli okumalar dilerim.</p><p>Turkcell WEB/APP uygulamasındaki monolitik backend yapılarımızı mikroservis mimarisine dönüştürürken, servisler arasındaki iletişimi iyileştirmek ve süreci daha verimli hale getirmek için farklı araçlar üzerinde çalışmalar yaptık. Bu süreç bizi gRPC’ye yönlendirdi ve özellikle yapısı gereği sunduğu ayrıcalıklar süreçlerimiz için bir çok avantaj sağladığını fark ettik. Bu süreçte edindiğim deneyimler ve bilgilere birlikte göz atalım.</p><h4>Neden İhtiyaç Duyuldu?</h4><p>Öncelikle gRPC’ye tam bir giriş yapmadan önce, neden böyle bir ihtiyaç doğduğunu ele alalım.</p><figure><img alt="why we should use gRPC" src="https://cdn-images-1.medium.com/max/742/1*v_PXvlex46__h0vZxTjYBw.png" /><figcaption>Monolithic and Microservice Architecture</figcaption></figure><p>gRPC’ye olan ihtiyacı anlamak için yukarıdaki gibi bir uygulamanın mikroservis dönüşüm sürecindeki iletişim problemini inceleyelim.</p><p>Monolitik mimaride geliştirilen uygulamalar, ihtiyaç doğrultusunda mikroservis mimarisine geçiş yapılmaktadır. Bu geçiş sürecinde, uygulamada bir bütün olarak çalışan servisler, birbirinden bağımsız olarak ihtiyaca göre parçalanır. Ancak, bu parçalanma sonrasında servislerin ihtiyaç halinde birbiriyle iletişim kurması gerekir ve bu noktada ek bir maliyet oluşur.</p><p>Monolitik mimaride servisler arası iletişim doğrudan gerçekleşirken, mikroservislerde servislerin birbiriyle iletişim kurması için genellikle HTTP tabanlı Restful API’ler kullanılır. Ancak, Restful API’ler metin tabanlı mesajlar (JSON/XML) ağır veri formatları kullandığından, her istek için header bilgilerinin taşınması performans açısından önemli bir yük oluşturabilir.</p><p>gRPC ise bu tür maliyetleri ortadan kaldırarak, monolitik mimariye en yakın şekilde hızlı ve verimli bir iletişim sunar. Restful gibi yöntemlerden farklı olarak, binary veri formatları kullanması ve HTTP/2 protokolü üzerinden çalışması sayesinde performans avantajı sağlar.</p><p>Bu nedenlerden dolayı gRPC, mikroservisler arası iletişimde hız, düşük gecikme ve daha az ağ yükü gibi önemli farklar yaratmaktadır. Şimdi, gRPC’nin bu avantajlarını daha yakından inceleyelim.</p><h3><strong>gRPC Nedir?</strong></h3><p>Google tarafından geliştirilmiş, açık kaynaklı Remote Procedure Call(RPC) kütüphanesidir. RPC, uzak sunucudaki methodları sanki kendi ortamının birer parçasıymış gibi çalıştırabilen sistemlerdir.</p><figure><img alt="grpc" src="https://cdn-images-1.medium.com/max/585/1*aKGHEExgZoi1hw6bUs1LPw.png" /><figcaption><a href="https://grpc.io/img/landing-2.svg">https://grpc.io/img/landing-2.svg</a></figcaption></figure><p>Ana amacı client ve server arasında yüksek, güvenilir ve verimli bir iletişim sağlamaktır. Özellikle mikroservis mimarisinde servisler arasında yüksek hızda iletişim sağlar. RESTful sistemlere göre metin tabanlı veri formatları yerine, binary tabanlı veri formatı kullanır.</p><p>gRPC, veriyi serilize ve deserilize etmek için Protocal Buffers adlı bir veri tanımlama dili (Interface Defination Language) kullanır.</p><p>Protobuf, verileri küçük ve hızlı bir şekilde kodlamak için tasarlanmıştır. gRPC’nin performansının büyük kısmı, Protobuf’un sağladığı bu hızlı ve az yer kaplayan serileştirme yeteneklerinden gelir. Bu da ağ üzerindeki yükü azaltır ve işlem sürelerini hızlandırır.</p><h4><strong>gRPC Avantajları</strong>:</h4><ul><li><strong>Yüksek performans ve verimlilik</strong>: gRPC, HTTP/2 protokolü üzerinden binary tabanlı bir iletişim sağlayarak, yüksek performanslı ve düşük geçikmeli bir iletişim sağlar.</li><li><strong>Streaming yeteneği</strong>: gRPC, tek seferlik request/response dışında çift yönlü bir iletişim yeteneğine sahiptir.</li><li><strong>Güçlü tip güvenliği ve sözleşmeler</strong>: Protobuf ile tanımlanan arayüzler sayesinde sıkı bir tip güvenliği sağlar ve client ile server arasındaki servisler net olarak belirlenir.</li><li><strong>Çapraz platform ve dil desteği</strong>: Birçok platform ve dil desteğine sahiptir. Örneğin client tarafı Java iken server tarafı C++ veya Python olabilir.</li></ul><h3><strong>Protocoll Buffers</strong></h3><p>Protobuf, mesajların ve servislerin tanımlarının yapıldığı bir IDL (Interface Definition Language)’dir. Yazılan proto dosyası, servis ve mesajların oluşturulması için kod üretiminde yardımcı olur. Böylece verileri serialize ve deserialize ederek, binary veri formatını rahatlıkla kullanmamızı sağlar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/651/1*iOJz1MDFmpH13TLH7mTKQQ.png" /><figcaption>gRPC Proto File</figcaption></figure><p>Yukarıda bir proto dosyasını inceleyelim.</p><p>Öncelikle, Protobuf’un farklı sürümleri kullanılmakta ve sürekli gelişmektedir. Proto3, en son sürüm olduğu için bu örnekte onu kullanıyoruz.</p><p>Kod üretiminde, sınıfların hangi paket altında üretileceğini belirtmek için ise package bilgisi doldurulmalıdır.</p><p>Örneğimize baktığımızda, servis ve mesaj tanımlarının yapıldığını görüyoruz. Mesajlarda kullanılan numaralar, serileştirme sırasında hangi alanın hangi veriye karşılık geldiğini belirtmek için oldukça önemlidir.</p><p>Bu örnekte ise, bir kullanıcının fatura detaylarını alabilmesi için gerekli servis ve mesaj tanımlarını proto dosyasıyla nasıl yazdığımızı görebiliriz. Gelin bu proto için gRPC client ve gRPC server nasıl oluşturabileceğimizi inceleyelim.</p><h3><strong>gRPC Server</strong></h3><p>Proto dosyası derlendiğinde, BillingServiceGrpc.BillingServiceImplBase sınıfı oluşturulur. Bu sınıf, proto dosyasında tanımlanan servis için bir isteğin sonucunu döndürebileceğimiz metot sunar.</p><p>Proto dosyası ise bizim arayüzümüz olarak işlev görür. Orada tanımlanan her metodu override ederek, servis yanıtını istediğimiz gibi oluşturabiliriz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8vp8x9XTcegQbj4qOeO6dw.png" /><figcaption>gRPC Server</figcaption></figure><h3><strong>gRPC Client</strong></h3><p>Öncelikle, bir gRPC client istek göndermek istediği gRPC server bağlantı kurması gerekir. gRPC server’in çalıştığı adres bilgisi yml dosyasında aşağıdaki gibi tanımlanır.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/777/1*bMkq1jZUZz9pZyjEYv3a0A.png" /></figure><p>Bu şekilde, gRPC client’ın ihtiyaç duyduğu bağlantı adresi tanımlanmış olur. Ardından proto dosyası derlendiğinde üretilen BillingServiceGrpc sınıfına, bu adres bilgisi sağlanarak client ile server<strong> </strong>arasında bağlantı kurulmuş olur.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/795/1*4M4kDHieI2zjPwELiPNvyQ.png" /></figure><p>Burada önemli olan diğer bir bilgi ise, buradaki isteğimiz unary olduğu için BillingServiceGrpc.BillingServiceBlockingStub client’ını kullanıyoruz. Örneğin, isteğimiz server-side streaming iletişim modelinde olsaydı, BillingServiceGrpc.BillingServiceStub client’ını kullanabilirdik.</p><p>gRPC farklı iletişim yöntemlerini destekler, gelin birlikte bunlara göz atalım.</p><h3><strong>gRPC İletişim Türleri</strong></h3><p>gRPC client ve server arasında farklı iletişim modellerini destekler. gRPC’yi verimli şekilde kullanmak istiyorsak, ihtiyacımıza uygun iletişim modelini seçmek oldukça önemlidir.</p><h4>Unary RPC</h4><p>Geleneksel request/response isteklerine benzer. Client, tek bir istek için server’dan tek bir yanıt alır. Örnek verecek olursak, REST API’lerimiz unary RPC modeline benzer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/628/1*yRfkEjR_egZnB9UQZkHEGg.png" /><figcaption><a href="https://i0.wp.com/blog.nashtechglobal.com/wp-content/uploads/2024/07/1.png?resize=1024%2C576&amp;ssl=1">https://i0.wp.com/blog.nashtechglobal.com/wp-content/uploads/2024/07/1.png?resize=1024%2C576&amp;ssl=1</a></figcaption></figure><h4>Server Streaming RPC</h4><p>Bu iletişim modelinde client server’a bir istek gönderir ve server birden fazla mesajını akış gönderir. Örneğin, bir video veya müzik dosyası client tarafından talep edildiğinde, server medya içeriğini parça parça client’a iletir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*pbzVxAJmHpfGnU7dYcfcSQ.png" /><figcaption><a href="https://i0.wp.com/blog.nashtechglobal.com/wp-content/uploads/2024/07/2-4.png?resize=1024%2C576&amp;ssl=1">https://i0.wp.com/blog.nashtechglobal.com/wp-content/uploads/2024/07/2-4.png?resize=1024%2C576&amp;ssl=1</a></figcaption></figure><h4>Client Streaming RPC</h4><p>Buradaki modelde ise client tarafından bir streaming isteği başlatılır, tüm istekler iletildiğinde server tüm isteklere karşı bir response döner. Örneğin, bir dosyayı parçalar halinde client tarafından gönderebiliriz ve tüm parçalar gönderildiğinde server, yüklemenin sonucu hakkında bir response döner.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/757/1*Zh04R8exHRq_EC6f96WLdg.png" /><figcaption><a href="https://i0.wp.com/blog.nashtechglobal.com/wp-content/uploads/2024/07/3.png?fit=1920%2C1080&amp;ssl=1">https://i0.wp.com/blog.nashtechglobal.com/wp-content/uploads/2024/07/3.png?fit=1920%2C1080&amp;ssl=1</a></figcaption></figure><h4>Bidirectional Streaming RPC</h4><p>Son olarak bu iletişim modelinde client ve server arasında birbirlerinden bağımsız olarak bir streaming söz konusudur. İletişim her iki yönde de eş zamanlı olarak gerçekleşir. Örnek verecek olursak, yolda giden bir aracın server’a durumu hakkında veriler yolladığı ve server’ın ilettiği trafik bilgileri hakkında sürekli ve eş zamanlı bir akış olarak gerçekleşmesi olabilir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/627/1*XYNPGhLMMsfgr0clVb879w.png" /></figure><h3><strong>gRPC vs Rest</strong></h3><p>gRPC ve RESTfull arasında bir çok farklılıklar vardır, bunlardan bazılarını aşağıdaki görselden inceleyebilirsiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ICLZ8lxO1g8d6v9CF8w5pQ.png" /><figcaption>gRPC vs REST</figcaption></figure><p>Bu yazımda genel olarak gRPC kapsamlı bir şekilde anlatmaya çalıştım. Bir sonraki gRPC yazımda, exception handling, rate limiting, monitor and logging gibi konuları gRPC sürecinde nasıl uygulayabiliriz konularını ele almaya çalışacağım. Bir sonraki yazıda görüşmek dileğiyle, sağlıcakla kalın :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fe4031508e5f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/folksdev/grpc-y%C3%BCksek-performansl%C4%B1-i%CC%87leti%C5%9Fim-k%C3%BCt%C3%BCphanesi-fe4031508e5f">gRPC: Yüksek Performanslı İletişim Kütüphanesi</a> was originally published in <a href="https://medium.com/folksdev">folksdev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Plotly ile Oluşturulan Grafiklerin Statik ve Paylaşılabilir Hale Getirilmesi]]></title>
            <link>https://medium.com/folksdev/plotly-ile-olu%C5%9Fturulan-grafiklerin-statik-ve-payla%C5%9F%C4%B1labilir-hale-getirilmesi-b7eb89df5a95?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/b7eb89df5a95</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[plotly-chart-studio]]></category>
            <category><![CDATA[data-visualization]]></category>
            <category><![CDATA[plotly]]></category>
            <dc:creator><![CDATA[Melisa Çevik]]></dc:creator>
            <pubDate>Wed, 26 Jun 2024 12:59:22 GMT</pubDate>
            <atom:updated>2024-06-26T13:00:36.778Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KbvKVsVKFrS-qt6ckLw1UQ.png" /></figure><p>Merhaba! Bugün sizlere, <strong>Plotly</strong> kullanarak oluşturduğunuz grafiklerin nasıl statik hale getirilebileceğini ve bu grafiklerin nasıl online olarak paylaşılabileceğini anlatacağım. Bu sayede projelerinizi ve analizlerinizi daha geniş kitlelerle kolayca paylaşabilirsiniz.</p><p>Rapor oluştururken daha statik grafiklere ihtiyaç duyabiliriz ve bu grafiklerin sadece yerel bilgisayarımızda kalmasını tercih etmeyebiliriz. Bu durumda, grafiklerinizi herkesin erişimine açmak için kullanabileceğiniz pratik bir çözüm var:<strong><em> Plotly Chart Studio</em></strong>.</p><h3>Adımlar</h3><p>1️⃣ Plotly Chart Studio Hesabı Oluşturma</p><ul><li><a href="https://chart-studio.plotly.com/">Plotly Chart Studio</a> web sitesine gidin.</li><li>Bir hesap oluşturun veya mevcut Plotly hesabınızla giriş yapın.</li></ul><p>2️⃣ Plotly Kütüphanelerini Yükleme</p><p>Plotly ve Chart Studio kütüphanelerini yüklemek için aşağıdaki komutu kullanın:</p><pre>pip install plotly chart-studio</pre><p>3️⃣ Plotly Credentials Ayarlama</p><ul><li>API key ve kullanıcı adınızı ayarlamanız gerekiyor. Bu bilgileri Plotly hesap ayarlarınızdan bulabilirsiniz.</li><li>chart-studio modülünü kullanarak ayarları yapın</li></ul><pre>import chart_studio<br>import chart_studio.plotly as py<br>import chart_studio.tools as tls<br><br>username = &#39;YOUR_USERNAME&#39;  # Plotly kullanıcı adınız<br>api_key = &#39;YOUR_API_KEY&#39;    # Plotly API anahtarınız<br>chart_studio.tools.set_credentials_file(username=username, api_key=api_key)</pre><p>4️⃣ Grafiği Plotly Chart Studio’ya Yükleme</p><pre>import pandas as pd<br>import plotly.express as px<br><br># Basit bir veri kümesi oluşturma<br>data = {<br>    &#39;Gün&#39;: [&#39;Pazartesi&#39;, &#39;Salı&#39;, &#39;Çarşamba&#39;, &#39;Perşembe&#39;, &#39;Cuma&#39;],<br>    &#39;Değer&#39;: [10, 15, 13, 17, 14]<br>}<br>df = pd.DataFrame(data)<br><br># Çizgi Grafik oluşturma<br>fig = px.line(df, x=&#39;Gün&#39;, y=&#39;Değer&#39;, title=&#39;Haftalık Değerler&#39;,<br>              labels={&#39;Gün&#39;: &#39;Günler&#39;, &#39;Değer&#39;: &#39;Değerler&#39;},<br>              color_discrete_sequence=[&#39;#1f77b4&#39;])<br><br># Grafik tasarımını düzenleme<br>fig.update_layout(<br>    plot_bgcolor=&#39;white&#39;,<br>    title_font=dict(family=&quot;Roboto Mono&quot;, size=24, color=&#39;#000000&#39;),<br>    font=dict(family=&quot;Roboto Mono&quot;, size=16, color=&#39;#000000&#39;),<br>    xaxis_tickfont=dict(family=&quot;Roboto Mono&quot;, size=14, color=&#39;#000000&#39;),<br>    yaxis_tickfont=dict(family=&quot;Roboto Mono&quot;, size=14, color=&#39;#000000&#39;),<br>    showlegend=False<br>)<br><br># Grafiği Plotly Chart Studio&#39;ya yükleme<br>py.plot(fig, filename=&#39;haftalik_degerler_linechart&#39;, auto_open=True)</pre><h3>Avantajlar</h3><ul><li><strong>Kullanım Kolaylığı:</strong> Plotly Chart Studio, grafiklerinizi hızlı ve kolay bir şekilde paylaşmanızı sağlar.</li><li><strong>Profesyonellik:</strong> Grafiğiniz Plotly’nin kendi sunucularında barındırılır, bu da profesyonel ve güvenilir bir çözüm sunar.</li><li><strong>Interaktivite:</strong> Grafikler interaktif olarak paylaşılabilir, böylece kullanıcılar grafiklerle etkileşime girebilir.</li></ul><p>Bu adımları takip ederek, Plotly ile oluşturduğunuz grafiklerinizi kolayca online hale getirebilir ve paylaşabilirsiniz. Bu sayede projeleriniz ve analizleriniz daha geniş kitlelere ulaşacak ve daha etkili olacak.</p><p>Okuduğunuz için teşekkür ederim. ✍️(◔◡◔)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b7eb89df5a95" width="1" height="1" alt=""><hr><p><a href="https://medium.com/folksdev/plotly-ile-olu%C5%9Fturulan-grafiklerin-statik-ve-payla%C5%9F%C4%B1labilir-hale-getirilmesi-b7eb89df5a95">Plotly ile Oluşturulan Grafiklerin Statik ve Paylaşılabilir Hale Getirilmesi</a> was originally published in <a href="https://medium.com/folksdev">folksdev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Spring Retry ve Recover Kullanarak Hata Yönetimi ]]></title>
            <link>https://medium.com/folksdev/spring-retry-ve-recover-kullanarak-hata-y%C3%B6netimi-29656118cea8?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/29656118cea8</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[recover]]></category>
            <category><![CDATA[retry]]></category>
            <category><![CDATA[spring-boot]]></category>
            <dc:creator><![CDATA[Metehan Gültekin]]></dc:creator>
            <pubDate>Fri, 07 Jun 2024 09:19:18 GMT</pubDate>
            <atom:updated>2024-06-07T09:19:18.240Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*eLqpd90fzj4yPtM6x7bl6Q.png" /></figure><p>Modern yazılım sistemlerinde, özellikle mikroservis mimarilerinde, geçici hatalar (örneğin, ağ bağlantı sorunları veya geçici hizmet kesintileri) sıklıkla karşılaşılan durumlardır. Bu tür geçici hataları yönetmek ve uygulamanızın güvenilirliğini artırmak için yeniden deneme (retry) mekanizmaları kullanılır. <em>Spring Retry</em>, bu tür mekanizmaları Spring uygulamalarında kolayca uygulamak için tasarlanmış güçlü bir kütüphanedir. Ayrıca, Spring Retry’nin `<em>Recover</em>` işlevi, tüm denemeler başarısız olduğunda uygulamanızın nasıl tepki vereceğini belirlemenize olanak tanır.</p><h3><strong>Spring Retry ve Recover Nedir?</strong></h3><p><strong>Spring Retry<br></strong>Spring Retry, belirli bir işlem başarısız olduğunda, bu işlemi otomatik olarak belirli sayıda tekrar denemenize olanak tanır. Örneğin, bir veritabanı bağlantısı kurmaya çalıştığınızda bir hata alırsanız, Spring Retry bu bağlantı denemesini otomatik olarak tekrar eder. Böylece, geçici hatalarla başa çıkabilir ve işlemlerin başarılı olma olasılığını artırabilirsiniz.</p><p><strong>Spring Recover<br></strong>Spring Recover ise tüm yeniden deneme girişimleri başarısız olduğunda devreye giren bir mekanizmadır. Recover işlevi, hata durumlarında alternatif bir işlem veya hata yönetimi stratejisi sunar. Bu, uygulamanızın beklenmeyen durumlarla daha zarif bir şekilde başa çıkmasını sağlar.</p><h3>Spring Retry kullanarak bir proje geliştirelim</h3><p>Projemizi oluşturmak için ilk adım olarak projemizin ihtiyaç duyduğu bağımlılıkları ekleyerek başlayalım. Bu kapsamda Spring Web, Spring Retry , Spring Aop ve Lombok bağımlılıklarını projemize eklememiz gerekiyor.</p><pre>&lt;dependency&gt;<br>   &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>   &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;<br>  &lt;/dependency&gt;<br><br>  &lt;dependency&gt;<br>   &lt;groupId&gt;org.springframework.retry&lt;/groupId&gt;<br>   &lt;artifactId&gt;spring-retry&lt;/artifactId&gt;<br>  &lt;/dependency&gt;<br><br>  &lt;dependency&gt;<br>   &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>   &lt;artifactId&gt;spring-boot-starter-aop&lt;/artifactId&gt;<br>  &lt;/dependency&gt;<br><br>  &lt;dependency&gt;<br>   &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;<br>   &lt;artifactId&gt;lombok&lt;/artifactId&gt;<br>   &lt;optional&gt;true&lt;/optional&gt;<br>  &lt;/dependency&gt;</pre><p>Config için fazla şeye ihtiyacımız yok, sadece Application class’ına @EnableRetry eklememiz yeterli.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1eb6bb8c9717504f52ab2b02baaea522/href">https://medium.com/media/1eb6bb8c9717504f52ab2b02baaea522/href</a></iframe><p><strong>@EnableRetry</strong>: Bu işaretleme Spring’in metotları yeniden deneme desteğini etkinleştirmek için kullanılır.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0311f5902df74a27e84afb11fdc5de7c/href">https://medium.com/media/0311f5902df74a27e84afb11fdc5de7c/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b699586b70359c85713c0b93631d8557/href">https://medium.com/media/b699586b70359c85713c0b93631d8557/href</a></iframe><p><strong>Metot Açıklamaları</strong></p><p>`<em>retryOrderProcess</em>` -&gt; Bu metot, sipariş detayları boş ise `<em>SQLException</em>` fırlatır. Eğer `<em>SQLException</em>` meydana gelirse, metot üç kez yeniden denenir. Üç başarısız denemeden sonra, `<em>recoverOrderProcess</em>` metodu devreye girer ve bir kurtarma işlemi yapar.</p><p>`<em>retryOrderProcessWithBackoff</em>` -&gt; Bu metot da, sipariş detayları boş ise `<em>SQLException</em>` fırlatır. `<em>SQLException</em>` durumunda, metot maksimum beş kez yeniden denenir. Her yeniden denemede bekleme süresi başlangıçta 2 saniye olup, her seferinde iki katına çıkarılacak şekilde artar. Maksimum bekleme süresi 30 saniyedir. Beş başarısız denemeden sonra, `<em>recoverOrderProcessWithBackoff</em>` metodu devreye girer ve bir kurtarma işlemi yapar.</p><h3><strong>Request ve Log Çıktıları</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-JDFRYC4cPEjPDJ7tnFq6Q.png" /><figcaption>request-log</figcaption></figure><h3>@Retryable Anotasyonu: Parametrelerin Detaylı Açıklaması</h3><p><strong>1. `<em>value</em>` veya `<em>retryFor</em>`<br></strong>Bu parametre, hangi istisnalar karşısında yeniden deneme yapılacağını belirtir. Bir exception sınıfı veya exception sınıfı dizisi kabul eder.</p><pre>@Retryable(value = { SQLException.class, IOException.class })</pre><p><strong>2. `<em>exclude</em>` veya `<em>noRetryFor</em>`<br></strong>Bu parametre, yeniden deneme yapılmayacak exception’ı belirtir. Bu exception karşısında yeniden deneme yapılmaz.</p><pre>@Retryable(exclude = { IllegalArgumentException.class, NullPointerException.class })</pre><p><strong>3. `<em>maxAttempts</em>`<br></strong>Yeniden deneme girişimlerinin maksimum sayısını belirtir. Varsayılan değer 3&#39;tür.</p><pre>@Retryable(maxAttempts = 5)</pre><p><strong>4. `<em>backoff</em>`<br></strong>Yeniden denemeler arasındaki bekleme süresini yapılandırmak için kullanılır. `<em>@Backoff</em>` anotasyonu ile birlikte kullanılır.</p><pre>@Retryable(backoff = @Backoff(delay = 2000, multiplier = 2))</pre><p><strong>`<em>@Backoff</em>` Anotasyonunun Parametreleri:<br></strong>- `<em>delay</em>`: İlk yeniden deneme öncesinde bekleme süresini (milisaniye cinsinden) belirtir.<br>- `<em>multiplier</em>`: Her başarısız denemeden sonra bekleme süresinin çarpanını belirtir.</p><pre>1. deneme: delay = 2000 ms<br>2. deneme: delay = 2000 * 2 = 4000 ms<br>3. deneme: delay = 4000 * 2 = 8000 ms<br>...</pre><p>- `<em>maxDelay</em>`: Bekleme süresinin maksimum değerini belirtir.<br>- `<em>random</em>`: Yeniden denemeler arasında rastgele bir gecikme ekler.</p><p><strong>5. `<em>recover</em>`<br></strong>Yeniden deneme girişimlerinin hepsi başarısız olursa çağrılacak metodun adını belirtir. Bu metod, hataları ele almak için bir geri kazanım mekanizması sağlar.</p><pre>@Retryable(recover = &quot;recoverOrderProcess&quot;)</pre><p><strong>6. `<em>label</em>`<br></strong>Bu parametre, yeniden deneme işlemine bir etiket ekler. Bu etiket, özellikle loglama ve izleme gibi durumlar için yararlıdır.</p><pre>@Retryable(label = &quot;orderRetry&quot;)</pre><p><strong>Öne Çıkan Özellikler ve Faydalar</strong></p><ul><li><strong>Dayanıklılık ve Güvenilirlik:</strong> Geçici hatalar karşısında işlemlerinizi tekrar deneyerek başarı şansını artırır ve sisteminizin güvenilirliğini sağlar.</li><li><strong>Esneklik:</strong> Yeniden deneme stratejilerini kolayca özelleştirebilir, farklı gecikme süreleri ve deneme sayıları belirleyebilirsiniz.</li><li><strong>Hata Yönetimi:</strong> Recover işlevi ile, tüm yeniden denemeler başarısız olsa bile uygulamanızın belirli bir şekilde tepki vermesini sağlayarak, hata yönetimini optimize edebilirsiniz.</li><li><strong>Kod Temizliği:</strong> Karmaşık hata yönetim kodlarını azaltır ve kodunuzu daha temiz ve yönetilebilir hale getirir.</li></ul><p>Projenin kaynak kodlarına buradan ulaşabilirsiniz.</p><p><a href="https://github.com/mgmetehan/spring-retry-recover">GitHub - mgmetehan/spring-retry-recover</a></p><p>Sonuna kadar okuduğunuz için teşekkür ederiz. Gitmeden önce:</p><ul><li>Lütfen yazıyı alkışlamayı ve beni takip etmeyi unutmayın! 👏</li><li>Beni takip etmek isterseniz <a href="https://twitter.com/metehan_gltkn">X</a><strong>| </strong><a href="https://www.linkedin.com/in/mgmetehan/"><strong>Linkedin</strong></a><strong>| </strong><a href="https://github.com/mgmetehan"><strong>Github</strong></a></li></ul><p>İyi günler,<br>Bol kodlamalar :)</p><h3>Kaynaklar</h3><ul><li><a href="https://github.com/spring-projects/spring-retry">https://github.com/spring-projects/spring-retry</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=29656118cea8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/folksdev/spring-retry-ve-recover-kullanarak-hata-y%C3%B6netimi-29656118cea8">Spring Retry ve Recover Kullanarak Hata Yönetimi 🔁🛠</a> was originally published in <a href="https://medium.com/folksdev">folksdev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dikkat! Kimlik kontrolü: Mernis & SpringBoot]]></title>
            <link>https://medium.com/folksdev/dikkat-kimlik-kontrol%C3%BC-mernis-springboot-1ac49a9fb7f7?source=rss----1c0fe5b20e42---4</link>
            <guid isPermaLink="false">https://medium.com/p/1ac49a9fb7f7</guid>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[mernis]]></category>
            <category><![CDATA[kimlik-doğrulama]]></category>
            <dc:creator><![CDATA[Duygu Orhan]]></dc:creator>
            <pubDate>Fri, 24 May 2024 07:18:50 GMT</pubDate>
            <atom:updated>2024-05-24T07:18:49.984Z</atom:updated>
            <content:encoded><![CDATA[<p>Herkese merhabaa, uygulama geliştirirken Türkiye Cumhuriyeti’nin kimlik kontrolünü sağlayan bir servisini kullanabildiğimizi biliyor muydunuz? Peki bu servis nedir ve nasıl kullanılır? Hadi gelin birlikte bakalım 👩🏻‍💻💚</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XkOeatiHrwAmDHpwMvMjaQ.jpeg" /></figure><h4>Mernis &amp; KPS nedir?</h4><p>Merkezi Nüfus İdaresi Sistemi (MERNİS), Türkiye Cumhuriyeti vatandaşlarının nüfus kayıtlarının merkezi bir veri tabanında tutulduğu bir projedir. Kimlik Paylaşım Sistemi (KPS) ise, MERNİS veri tabanındaki kimlik bilgilerinin kamu kurumları ve yetkilendirilmiş tüzel kişiler tarafından kontrol edilebileceği ve paylaşılabileceği bir hizmettir. Bu hizmetin prosedürleri kabul eden herkese açık olması sayesinde biz de KPS API’sini kullanarak kimlik kontrolünü gerçekleştirebiliyoruz.</p><p>KPS servisini kullanabilmek için TC kimlik numarası ile kullanıcı kaydı doğrulayıp oluşturabileceğimiz basit bir proje oluşturalım 👇🏻</p><p>Projeyi <a href="https://start.spring.io/">spring initializer</a> sayfasına giderek oluşturuyoruz. Bu bir maven projesi ve ilgili dependencys: Lombok, JPA, Spring Web, SpringBoot DevTools, PostgreSQL Driver.</p><p>Öncelikle PostgreSql’de UserRegister adında bir veri tabanı oluşturalım ve sonrasında projeye gelip resources kısmında properties uzantılı dosyayı yaml uzantılı dosyaya çevirelim. Bize gerekli olan veri tabanı ve jpa tanımlamalarını yazalım.</p><pre>spring:<br>  application:<br>    name: mernisConfig<br>  jpa:<br>    properties:<br>      hibernate:<br>        dialect: org.hibernate.dialect.PostgreSQLDialect<br>    hibernate:<br>      ddl-auto: update<br>      show-sql: true<br>  datasource:<br>    url: jdbc:postgresql://localhost:5432/UserRegister<br>    username: postgres<br>    password: test</pre><p>Model package oluşturup içerisine User sınıfımızı tanımlayalım. Burada bizim için gerekli olan ad, soyad, doğum tarihi ve TC kimlik numarasını tanımlayarak business katmanında kontrol işlemlerini gerçekleştirerek kayıt oluşturacağız.</p><pre>package com.example.mernisConfig.model;<br><br><br>import jakarta.persistence.*;<br>import lombok.AllArgsConstructor;<br>import lombok.Getter;<br>import lombok.NoArgsConstructor;<br>import lombok.Setter;<br><br>import java.time.LocalDate;<br><br>@AllArgsConstructor<br>@NoArgsConstructor<br>@Getter<br>@Setter<br>@Entity<br>@Table(name = &quot;users&quot;)<br>public class User {<br>    @Id<br>    @GeneratedValue(strategy = GenerationType.IDENTITY)<br>    private int id;<br>    private String firstName;<br>    private String lastName;<br>    private LocalDate birthOfDateYear;<br>    private String identityNumber;<br>    private String email;<br>}</pre><p>Oluşturduğumuz User sınıfının UserRepository interface’ini oluşturarak veri tabanı işlemlerini kolaylaştırıyoruz. Servis sınıfını oluşturmadan önce burada kullanacağımız mernis sistemini kurma vakti geldi. Yeni bir package oluşturarak adına ‘mernis’ diyelim. Eğer ilk defa bir web servisi ekleyecekseniz projenize muhtemelen ilgili plugin bulunmayacaktır. Bu yüzden öncelikle easyWSDL plugin ekliyoruz ki dışarıdan servisi ekleyip kullanabilelim.</p><p>File üzerine gelerek proje ayarlarına gidelim:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/469/1*n6TaWYAXNYG9JozdxjFTqg.png" /></figure><p>Buradan da plugin kısmına gelerek easyWSDL generator’ı aratalım ve install yapalım:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EG-2p8ORAdz5_2_-VshSpQ.png" /></figure><p>Oluşturduğumuz package üstüne gelerek sağ click yaparak en alttaki easyWSDL - add web service seçeneğine tıklayarak hesap oluşturuyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*3PrW319-Ea25gbn2j6_4bQ.png" /></figure><p>Hesap oluşturduktan sonra, tekrardan add web service diyerek çıkan yeni pencerede URL kısmına kullanacağımız mernis KPS servisini veriyoruz. Language ‘Java’ olarak seçip, işlemi tamamlıyoruz. (<a href="https://tckimlik.nvi.gov.tr/Service/KPSPublic.asmx">https://tckimlik.nvi.gov.tr/Service/KPSPublic.asmx</a>)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/764/1*cZduFJxjC958aAuKhPbs1Q.png" /></figure><p>Ve artık ilgili sınıflar package içerisinde. Proje dosyasında oluşan jar dosyalarını da module olarak eklememiz gerekli.</p><p>File →Project Structure → Modules e gelerek easyWsdl klasöründeki jar dosyalarını seçiyoruz ve bunları projeye yüklüyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8NsmeyNfa7F63lLb-upbiw.png" /></figure><p>Artık mernis servisini projemize bağladık ve ilgili sınıfları kullanarak kimlik kontrolümüzü gerçekleştiren kodu yazabiliriz. UserService sınıfını oluşturabiliriz. Aşağıdaki servis kodunda mernis package’ında bulunan CQRKPSPublicSoap sınıfından bir obje oluşturuyoruz. (<em>Muhtemelen eğer siz projeyi kendiniz oluşturursanız sınıfların önündeki 3 harf değişecektir.</em>) Bu oluşturduğumuz objede TCKimlikNoDoğrulama metodunu çağırarak ve içerisine obje değerlerini göndererek kontrol ediyoruz. Eğer sonucumuz true dönerse bu bilgilere sahip bir TC vatandaşı bulunmakta, false ise bu bilgilerle kayıtlı bir TC vatandaşı bulunmamaktadır.</p><pre>package com.example.mernisConfig.service;<br><br>import com.example.mernisConfig.mernis.CQRKPSPublicSoap;<br>import com.example.mernisConfig.model.User;<br>import com.example.mernisConfig.repository.UserRepository;<br>import lombok.RequiredArgsConstructor;<br>import org.apache.coyote.BadRequestException;<br>import org.springframework.stereotype.Service;<br><br>@Service<br>@RequiredArgsConstructor<br>public class UserService {<br>    private final UserRepository userRepository;<br>    public String registerUser(User user) throws Exception {<br>        CQRKPSPublicSoap client= new CQRKPSPublicSoap();<br>        boolean isRealPerson = client.TCKimlikNoDogrula(<br>                Long.valueOf(user.getIdentityNumber()),<br>                user.getFirstName(),<br>                user.getLastName(),<br>                Integer.valueOf(user.getBirthOfDateYear().getYear()));<br><br>        if(isRealPerson){<br>            userRepository.save(user);<br>            return &quot;kullanıcı başarıyla kayıt edildi&quot;;<br><br>        }<br>        else {<br>            throw new IllegalArgumentException(&quot;Kullanıcı bulunamadı!&quot;);<br>        }<br><br>    }<br><br>}</pre><p>En son da controller sınıfımızı oluşturarak kullanıcı oluşturmak için bir post metodu tanımlıyoruz.</p><pre>package com.example.mernisConfig.controller;<br><br>import com.example.mernisConfig.model.User;<br>import com.example.mernisConfig.service.UserService;<br>import lombok.RequiredArgsConstructor;<br>import org.springframework.http.ResponseEntity;<br>import org.springframework.web.bind.annotation.PostMapping;<br>import org.springframework.web.bind.annotation.RequestBody;<br>import org.springframework.web.bind.annotation.RequestMapping;<br>import org.springframework.web.bind.annotation.RestController;<br><br>@RestController<br>@RequestMapping(&quot;/api/v1/users&quot;)<br>@RequiredArgsConstructor<br>public class UserController {<br><br>    private final UserService userService;<br><br>    @PostMapping<br>    public ResponseEntity&lt;String&gt; register(@RequestBody User user) throws Exception {<br>        return ResponseEntity.ok(userService.registerUser(user));<br> }<br>}</pre><p>Kodumuzun son halini doğru kullanıcı bilgileri girerek Postman’den istek atıp doğrulayalım:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/893/1*0RALEwzmdl70f-GU_nLHFA.png" /></figure><p>Bu kodlara ulaşmak isterseniz <a href="https://github.com/duygu2/mernis-springboot">Github Repository</a> burada.</p><p><em>Okuduğunuz için teşekkür ederim. Umarım sizler için faydalı bir yazı olmuştur 🫶🏻</em></p><p><em>Eğer yazılarım ilginizi çekiyorsa beni takip etmeyi unutmayın ✨💐<br></em><a href="https://twitter.com/duguorhan"><em>X</em></a><em> | </em><a href="https://www.linkedin.com/in/duygu-orhan-9a7a711ba/"><em>LinkedIn</em></a><em> | </em><a href="https://github.com/duygu2"><em>GitHub</em></a></p><p><em>Bir sonraki yazıda görüşmek üzere, sağlıcakla kalın🙌🏻</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1ac49a9fb7f7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/folksdev/dikkat-kimlik-kontrol%C3%BC-mernis-springboot-1ac49a9fb7f7">Dikkat! Kimlik kontrolü: Mernis &amp; SpringBoot</a> was originally published in <a href="https://medium.com/folksdev">folksdev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>