<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ahmet Öz</title>
    <description>The latest articles on DEV Community by Ahmet Öz (@ahmetoz).</description>
    <link>https://dev.to/ahmetoz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F377575%2F8a11952f-c502-49ac-9bfc-ff2df64abee6.png</url>
      <title>DEV Community: Ahmet Öz</title>
      <link>https://dev.to/ahmetoz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ahmetoz"/>
    <language>en</language>
    <item>
      <title>Importance of limiting the concurrency.</title>
      <dc:creator>Ahmet Öz</dc:creator>
      <pubDate>Sun, 28 Feb 2021 15:24:43 +0000</pubDate>
      <link>https://dev.to/ahmetoz/importance-of-limiting-the-concurrency-3nih</link>
      <guid>https://dev.to/ahmetoz/importance-of-limiting-the-concurrency-3nih</guid>
      <description>&lt;p&gt;Concurrent programming techniques are the most used approach to structure the applications since the multicore processors are invented, and it's the most effective way to speed your applications when the number of tasks is much greater than the number of CPUs especially when the coordination of these smaller tasks requires network communication. For instance, using concurrent programming a CPU will do other things after triggering an HTTP request instead of blocking the CPU until the response is fulfilled. In this article, I want to explain the importance of putting limits on concurrent requests.&lt;/p&gt;

&lt;p&gt;The behavior of concurrent requests in a server could be analyzed with a well-known queueing theory called Little’s Law &lt;code&gt;L = ℷW&lt;/code&gt;. When we adopt the idea in this theory to a typical client-server architecture based on which requests arrive at a server from the client, processed some time in the server, and then responded to the client. The specifying the formula:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L - the level of concurrency&lt;/strong&gt;;  the number of requests that are currently our server is processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ℷ - throughput&lt;/strong&gt;; the numbers of completed requests (amount) per second in a server, completed because otherwise the request will be piled up in the server and not counted in throughput.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W - average latency&lt;/strong&gt;; the latency (delay) of handling a specific request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you could imagine a change in one characteristic might influence two others. Thus the entire system. So let's jump to playing around with the formula to see the effects, in terms of performance, we care about increasing the throughput which means increase the number of things, a server can do per second. If we want to increase our lambda &lt;strong&gt;ℷ - throughput&lt;/strong&gt;, then we might try to decrease our latency with the same concurrency limit, &lt;em&gt;most of the time&lt;/em&gt; that is beyond our control other than typical algorithm optimization because when we process that request, we might want to access some database or some other service on the network, so basically we might not have control for how long it takes to the response. &lt;/p&gt;

&lt;p&gt;Another thing to do to increase our throughput would be to increase the level of concurrency &lt;strong&gt;L - the level of concurrency&lt;/strong&gt;. How high our throughput can go giving some average latency which is usually more or less constant per system. It's constant because when the concurrency of the system is increased it means an overload of the actual server, and if the server could not handle that amount of requests at the same time, if there is no specific implementation added (by default) to handle the load like rejecting or queuing the request, the connections might drop because the request will time out. Or worse the machine running the server might crash or throttled because of running out of memory or  CPU limits.&lt;/p&gt;

&lt;p&gt;In conclusion, it’s important to note that concurrency limits need to be enforced at the server level, and if you don't have control over the client and the usage of the server/API should be documented considering the best performant concurrency limit. If you have control over your client, the client needs to send requests with considering a good concurrency limit to not overload the servers.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>systems</category>
      <category>performance</category>
    </item>
    <item>
      <title>My code review checklist.</title>
      <dc:creator>Ahmet Öz</dc:creator>
      <pubDate>Sat, 26 Dec 2020 13:34:30 +0000</pubDate>
      <link>https://dev.to/ahmetoz/my-code-review-checklist-1o56</link>
      <guid>https://dev.to/ahmetoz/my-code-review-checklist-1o56</guid>
      <description>&lt;p&gt;Code reviews are a critical and legitimate activity that needs time and focus.&lt;/p&gt;

&lt;p&gt;I was thinking recently about the reviews that I was doing and created a checklist for me to adjust before submitting the comments to the pull requests. &lt;/p&gt;

&lt;h2&gt;
  
  
  Review:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check out the code and run the new tests manually, try to check if the code is handling edge cases.&lt;/li&gt;
&lt;li&gt;Ensure the code is covering all requirements.&lt;/li&gt;
&lt;li&gt;Checkout code coverage results and ensure the important parts of the code are tested.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comments:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When demanding changes, explain them clearly. Offer suggestions or ask questions, instead of giving a direct todo or even worse just sharing a sample code.&lt;/li&gt;
&lt;li&gt;Don't focus too much on the coding styles or something like making the code one-liner.&lt;/li&gt;
&lt;li&gt;Avoid LGTM comments if possible, if everything is right, write thanks for the work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reply to comments:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always be kind to the developer but serious with the code.&lt;/li&gt;
&lt;li&gt;Avoid confusing statements.&lt;/li&gt;
&lt;li&gt;Do not criticize or explain the architectural decision changes as a long comment, instead request a pair review and do the discussion in a verbal way, after the discussion request or try to write the decisions as a comment to make them visible to the team.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>k8s makes deployment easy</title>
      <dc:creator>Ahmet Öz</dc:creator>
      <pubDate>Fri, 01 May 2020 17:05:32 +0000</pubDate>
      <link>https://dev.to/ahmetoz/k8s-makes-deployment-easy-363d</link>
      <guid>https://dev.to/ahmetoz/k8s-makes-deployment-easy-363d</guid>
      <description>&lt;p&gt;A couple of months ago I was trying to understand and describe the value of Kubernetes, starting to read about it and come off some notes as below, maybe it could be helpful for other developers to understand the value of it. For me, as described in the title I described it to my self as &lt;strong&gt;k8s makes the deployment easy&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Kubernetes does the things that the very best system administrator would do: automation, failover, centralized logging, monitoring. It takes what we've learned in the DevOps community and makes it the default, out of the box." &lt;br&gt;
@kelseyhightower&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Docker makes the development easy&lt;/strong&gt;, lets us build containers locally, push them to or pull them from a container registry, and run container images locally on our machine. &lt;strong&gt;Kubernetes makes deployment easy&lt;/strong&gt;, lets us orchestrate clusters in a pragmatic way. Actually, after the adaption of tools like docker and k8s, there are no big distinctions as before between software engineers and operations engineers. It’s all just software now, and we’re all engineers. So those tools improve the quality of the processes, as said by Amazon CTO Werner Vogels, &lt;strong&gt;"You build it, you run it"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;K8s cluster has a brain called control plane, it maintains all the tasks, scheduling containers, managing services, serving API requests, and so on for us, that part is running on master nodes, and other workloads of the cluster are running on worker nodes. For a typical production use case, k8s would need min 3 master nodes (virtual machines) to avoid the single point of failures, also most of the professionals suggest to not manage clusters manually (I guess here the reason is simple, cluster management is not an easy task which requires a significant investment of time, effort, and expertise and also it could not be cost-effective) instead suggest the usage of a managed services. Run less software philosophy could be a piece of good advice to consider before you decide to run Kubernetes on-premise. For learning/testing purposes we could use &lt;code&gt;Docker Desktop&lt;/code&gt; which lets us run a small (single-node) Kubernetes cluster on our laptops.&lt;/p&gt;

&lt;p&gt;Kubernetes control plane components working together as a state machine. K8s has a process called &lt;code&gt;reconciliation loop&lt;/code&gt; trying to reconcile the actual state with the desired state. The desired state is stored in an internal database (etcd) as a specification/manifest file in k8s like deployment, and controller components of the application continually check the desired state for each K8s resource and make necessary adjustments to keep the state machine in sync with manifests. K8s scheduler on master node watches the unscheduled deployments (desired state) and schedules the node for the pod, after scheduling the &lt;code&gt;kubelet&lt;/code&gt; process running on that node picks it up and takes care of actually starting its containers.&lt;/p&gt;

</description>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Thread safety issues in Java</title>
      <dc:creator>Ahmet Öz</dc:creator>
      <pubDate>Fri, 01 May 2020 16:42:43 +0000</pubDate>
      <link>https://dev.to/ahmetoz/thread-safety-issues-in-java-4dkn</link>
      <guid>https://dev.to/ahmetoz/thread-safety-issues-in-java-4dkn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Note: The post content and ideas aggregated from various resources and mainly Brian Goetz's excellent book &lt;strong&gt;Java Concurrency in Practice&lt;/strong&gt;. If you enjoy these notes below, I strongly suggest purchasing the book!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Writing concurrent programs most of the time is primarily related to managing shared mutable data/state between threads.&lt;br&gt;
As threads in the same process sharing the same memory address space (heap) with threads, managing the shared data/state is important to get predictable results from the running application. Basically this makes it hard to create a multithreaded application than a single-threaded application. The penalties for failing to synchronize shared mutable data are liveness and safety failures, so as a developer we need to write a code that synchronizes access of the shared data and which explains the synchronization policy for both clients and maintainers of the code/library. &lt;/p&gt;

&lt;h2&gt;
  
  
  Atomicity
&lt;/h2&gt;

&lt;p&gt;Operation of a shared state in a concurrent application should be &lt;strong&gt;atomic&lt;/strong&gt;, and if we don't use synchronization mechanisms, concurrent access of operation might cause &lt;strong&gt;race conditions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Race Conditions&lt;/strong&gt;: A semantic error condition, mostly related to the timing of instruction because thread scheduling algorithms can swap between threads (like context switching) in runtime or other kernel related problems might occur like waiting for some threads on kernel level, so it could cause that instructions on a multithreaded application will not be executed in a sequential manner means that multiple threads can race to access and change the data in the same time, so correctness is based on a &lt;strong&gt;timing luck&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Most of the time atomicity problems not easy to predict, and happens mostly on compound actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read-modify-write 

&lt;ul&gt;
&lt;li&gt;for example incrementing a counter, actions: read the value, increment it and write back to memory.&lt;/li&gt;
&lt;li&gt;to avoid such cases we could use &lt;strong&gt;AtomicInteger&lt;/strong&gt; class in &lt;code&gt;java.util.concurrent.atomic&lt;/code&gt; package.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;check-then-act 

&lt;ul&gt;
&lt;li&gt;for example lazy initialization of an expensive object like creating a database connection object.&lt;/li&gt;
&lt;li&gt;actions: first do a null check if the object is assigned, then create the object.&lt;/li&gt;
&lt;li&gt;to avoid such cases we could use

&lt;ul&gt;
&lt;li&gt;double-check lock mechanism&lt;/li&gt;
&lt;li&gt;an enum as enums using lazy initialization by default and all synchronization is handled by JVM.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Visibility
&lt;/h2&gt;

&lt;p&gt;Including the atomicity, we need to make sure that a change in the shared state needs to be visible by other threads because threads using the same memory. In order to ensure the visibility of memory writes across threads, we must use synchronization.&lt;/p&gt;

&lt;p&gt;Solutions to adjust visibility between threads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A weaker form of memory visibility using the java &lt;code&gt;volatile&lt;/code&gt; keyword. Basically, when an update occurs to a volatile variable the JVM ensures that the change is propagated to memory so threads could see the value change without needing an explicit synchronization. It's weak because does not guarantee atomicity issues. Most of the use cases using volatile is not practical, it's only useful for storing state value of an object in a boolean variable like initialized, stopped ext.&lt;/li&gt;
&lt;li&gt;A better solution is using the same common locking mechanism for both reading and writing threads because synchronization has no effect unless both read and write operations are synchronized.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thread safety issues could be solved
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;By using immutable data structures. &lt;/li&gt;
&lt;li&gt;By not sharing any states between threads. &lt;em&gt;Stateless&lt;/em&gt; objects or using pure functions without side effects.&lt;/li&gt;
&lt;li&gt;By using the java features like implicit locks, explicit locks synchronized keyword, and volatile keyword.&lt;/li&gt;
&lt;li&gt;By delegating thread safety to well-implemented higher level concurrency utilities in &lt;code&gt;java.util.concurrent&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;By not sharing the object reference.&lt;/li&gt;
&lt;li&gt;By returning defensive copies of a collection instead of returning the mutable collection itself.&lt;/li&gt;
&lt;li&gt;By using a thread-confinement object that can only be accessed by a current thread-like &lt;code&gt;ThreadLocal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;By using encapsulation and locks for securing not thread-safe objects.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
    </item>
  </channel>
</rss>
