{"id":2900,"date":"2018-11-08T05:20:06","date_gmt":"2018-11-08T05:20:06","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw92\/?p=2900"},"modified":"2018-11-12T00:24:50","modified_gmt":"2018-11-12T00:24:50","slug":"revisiting-the-unix-philosophy-in-2018","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw92\/index.php\/2018\/11\/08\/revisiting-the-unix-philosophy-in-2018\/","title":{"rendered":"Revisiting the Unix philosophy in 2018"},"content":{"rendered":"<p>In 1984, Rob Pike and Brian W. Kernighan published an article called &#8220;<a href=\"http:\/\/harmful.cat-v.org\/cat-v\/\" target=\"_blank\" rel=\"noopener\">Program Design in the Unix Environment<\/a>&#8221; in the AT&amp;T Bell Laboratories Technical Journal, in which they argued the Unix philosophy, using the example of BSD&#8217;s cat -v implementation. In a nutshell that philosophy is: Build small, focused programs\u2014in whatever language\u2014that do only one thing but do this thing well, communicate via stdin\/stdout, and are connected through pipes.<\/p>\n<p>Sound familiar?<\/p>\n<p>Yeah, I thought so. That&#8217;s pretty much the <a href=\"https:\/\/martinfowler.com\/articles\/microservices.html\" target=\"_blank\" rel=\"noopener\">definition of microservices<\/a> offered by James Lewis and Martin Fowler:<\/p>\n<blockquote><p>In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API.<\/p><\/blockquote>\n<p>While one *nix program or one microservice may be very limited or not even very interesting on its own, it&#8217;s the combination of such independently working units that reveals their true benefit and, therefore, their power.<\/p>\n<h2>*nix vs. microservices<\/h2>\n<p>The following table compares programs (such as cat or lsof) in a *nix environment against programs in a microservices environment.<\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>*nix<\/th>\n<th>Microservices<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Unit of execution<\/td>\n<td>program using stdin\/stdout<\/td>\n<td>service with HTTP or gRPC API<\/td>\n<\/tr>\n<tr>\n<td>Data flow<\/td>\n<td>Pipes<\/td>\n<td>?<\/td>\n<\/tr>\n<tr>\n<td>Configuration &amp; parameterization<\/td>\n<td>Command-line arguments,<br \/>\nenvironment variables, config files<\/td>\n<td>JSON\/YAML docs<\/td>\n<\/tr>\n<tr>\n<td>Discovery<\/td>\n<td>Package manager, man, make<\/td>\n<td>DNS, environment variables, OpenAPI<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Let&#8217;s explore each line in slightly greater detail.<\/p>\n<h3>Unit of execution<\/h3>\n<p>The unit of execution in *nix (such as Linux) is an executable file (binary or interpreted script) that, ideally, reads input from<\/p>\n<p>stdin<\/p>\n<p>and writes output to<\/p>\n<p>stdout<\/p>\n<p>. A microservices setup deals with a service that exposes one or more communication interfaces, such as HTTP or gRPC APIs. In both cases, you&#8217;ll find stateless examples (essentially a purely functional behavior) and stateful examples, where, in addition to the input, some internal (persisted) state decides what happens.<\/p>\n<h3>Data flow<\/h3>\n<p>Traditionally, *nix programs could communicate via pipes. In other words, thanks to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Douglas_McIlroy\" target=\"_blank\" rel=\"noopener\">Doug McIlroy<\/a>, you don&#8217;t need to create temporary files to pass around and each can process virtually endless streams of data between processes. To my knowledge, there is nothing comparable to a pipe standardized in microservices, besides my little <a href=\"https:\/\/speakerdeck.com\/mhausenblas\/distributed-named-pipes-and-other-inter-services-communication\" target=\"_blank\" rel=\"noopener\">Apache Kafka-based experiment from 2017<\/a>.<\/p>\n<h3>Configuration and parameterization<\/h3>\n<p>How do you configure a program or service\u2014either on a permanent or a by-call basis? Well, with *nix programs you essentially have three options: command-line arguments, environment variables, or full-blown config files. In microservices, you typically deal with YAML (or even worse, JSON) documents, defining the layout and configuration of a single microservice as well as dependencies and communication, storage, and runtime settings. Examples include <a href=\"http:\/\/kubernetesbyexample.com\/\" target=\"_blank\" rel=\"noopener\">Kubernetes resource definitions<\/a>, <a href=\"https:\/\/www.nomadproject.io\/docs\/job-specification\/index.html\" target=\"_blank\" rel=\"noopener\">Nomad job specifications<\/a>, or <a href=\"https:\/\/docs.docker.com\/compose\/overview\/\" target=\"_blank\" rel=\"noopener\">Docker Compose<\/a> files. These may or may not be parameterized; that is, either you have some templating language, such as <a href=\"https:\/\/helm.sh\/\" target=\"_blank\" rel=\"noopener\">Helm<\/a> in Kubernetes, or you find yourself doing an awful lot of sed -i commands.<\/p>\n<h3>Discovery<\/h3>\n<p>How do you know what programs or services are available and how they are supposed to be used? Well, in *nix, you typically have a package manager as well as good old man; between them, they should be able to answer all the questions you might have. In a microservices setup, there&#8217;s a bit more automation in finding a service. In addition to bespoke approaches like <a href=\"https:\/\/github.com\/airbnb\/smartstack-cookbook\" target=\"_blank\" rel=\"noopener\">Airbnb&#8217;s SmartStack<\/a> or <a href=\"https:\/\/github.com\/Netflix\/eureka\" target=\"_blank\" rel=\"noopener\">Netflix&#8217;s Eureka<\/a>, there usually are environment variable-based or DNS-based <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/service\/#discovering-services\" target=\"_blank\" rel=\"noopener\">approaches<\/a> that allow you to discover services dynamically. Equally important, <a href=\"https:\/\/www.openapis.org\/\" target=\"_blank\" rel=\"noopener\">OpenAPI<\/a> provides a de-facto standard for HTTP API documentation and design, and <a href=\"https:\/\/grpc.io\/\" target=\"_blank\" rel=\"noopener\">gRPC<\/a> does the same for more tightly coupled high-performance cases. Last but not least, take developer experience (DX) into account, starting with writing good <a href=\"https:\/\/suva.sh\/posts\/well-documented-makefiles\/\" target=\"_blank\" rel=\"noopener\">Makefiles<\/a> and ending with writing your docs with (or in?) <a href=\"https:\/\/www.linux.com\/news\/improve-your-writing-gnu-style-checkers\" target=\"_blank\" rel=\"noopener\">style<\/a>.<\/p>\n<h2>Pros and cons<\/h2>\n<p>Both *nix and microservices offer a number of challenges and opportunities<\/p>\n<h3>Composability<\/h3>\n<p>It&#8217;s hard to design something that has a clear, sharp focus and can also play well with others. It&#8217;s even harder to get it right across different versions and to introduce respective error case handling capabilities. In microservices, this could mean retry logic and timeouts\u2014maybe it&#8217;s a better option to outsource these features into a service mesh? It&#8217;s hard, but if you get it right, its reusability can be enormous.<\/p>\n<h3>Observability<\/h3>\n<p>In a monolith (in 2018) or a big program that tries to do it all (in 1984), it&#8217;s rather straightforward to find the culprit when things go south. But, in a<\/p>\n<p>yes | tr \\n x | head -c 450m | grep n<\/p>\n<p>or a request path in a microservices setup that involves, say, 20 services, how do you even <em>start<\/em> to figure out which one is behaving badly? Luckily we have standards, notably <a href=\"https:\/\/opencensus.io\/\" target=\"_blank\" rel=\"noopener\">OpenCensus<\/a> and <a href=\"https:\/\/opentracing.io\/\" target=\"_blank\" rel=\"noopener\">OpenTracing<\/a>. Observability still might be the biggest single blocker if you are looking to move to microservices.<\/p>\n<h3>Global state<\/h3>\n<p>While it may not be such a big issue for *nix programs, in microservices, global state remains something of a discussion. Namely, how to make sure the local (persistent) state is managed effectively and how to make the global state consistent with as little effort as possible.<\/p>\n<h2>Wrapping up<\/h2>\n<p>In the end, the question remains: Are you using the right tool for a given task? That is, in the same way a specialized *nix program implementing a range of functions might be the better choice for certain use cases or phases, it might be that a monolith <a href=\"https:\/\/robertnorthard.com\/devops-days-well-architected-monoliths-are-okay\/\" target=\"_blank\" rel=\"noopener\">is the best option<\/a> for your organization or workload. Regardless, I hope this article helps you see the many, strong parallels between the Unix philosophy and microservices\u2014maybe we can learn something from the former to benefit the latter.<\/p>\n<p><a href=\"http:\/\/lxer.com\/module\/newswire\/ext_link.php?rid=262532\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In 1984, Rob Pike and Brian W. Kernighan published an article called &#8220;Program Design in the Unix Environment&#8221; in the AT&amp;T Bell Laboratories Technical Journal, in which they argued the Unix philosophy, using the example of BSD&#8217;s cat -v implementation. In a nutshell that philosophy is: Build small, focused programs\u2014in whatever language\u2014that do only one &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw92\/index.php\/2018\/11\/08\/revisiting-the-unix-philosophy-in-2018\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Revisiting the Unix philosophy in 2018&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2900","post","type-post","status-publish","format-standard","hentry","category-linux"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts\/2900","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/comments?post=2900"}],"version-history":[{"count":1,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts\/2900\/revisions"}],"predecessor-version":[{"id":3111,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts\/2900\/revisions\/3111"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/media?parent=2900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/categories?post=2900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/tags?post=2900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}