<?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>Forem: Stream</title>
    <description>The latest articles on Forem by Stream (@getstream_io).</description>
    <link>https://forem.com/getstream_io</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%2Forganization%2Fprofile_image%2F220%2F735f68a5-0965-4317-817a-e8dd9544603a.png</url>
      <title>Forem: Stream</title>
      <link>https://forem.com/getstream_io</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/getstream_io"/>
    <language>en</language>
    <item>
      <title>Hello, we're Stream and we proudly support CodeLand!</title>
      <dc:creator>Tess Gordon</dc:creator>
      <pubDate>Thu, 23 Jul 2020 11:54:38 +0000</pubDate>
      <link>https://forem.com/getstream_io/hello-we-re-stream-and-we-proudly-support-codeland-4ncm</link>
      <guid>https://forem.com/getstream_io/hello-we-re-stream-and-we-proudly-support-codeland-4ncm</guid>
      <description>&lt;p&gt;Hello! We're &lt;a href="https://getstream.io" rel="noopener noreferrer"&gt;Stream&lt;/a&gt;, helping you build scalable activity feeds and in-app chat messaging in a few hours instead of weeks. &lt;/p&gt;

&lt;p&gt;We provide product teams with everything that they need to add activity feeds or chat to their app. This includes a UI kit, scalable APIs, frontend components for React, React Native, Flutter, iOS or Android, integrated machine learning/AI, and a management dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqsqkr67chz0ebs6eg9ol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqsqkr67chz0ebs6eg9ol.png" alt="key-stream-features"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr47t5ls8zuv5si4mjpw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr47t5ls8zuv5si4mjpw5.png" alt="partner-logos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stream enables our customers to get to market faster, grow without worrying about scalability, and ship a higher quality user experience.&lt;/p&gt;

&lt;p&gt;Here at Stream, we are all about sparking new ideas and encouraging collaboration. We deeply value the developer community, as we learn from and contribute to it every day. Therefore, we proudly support CodeLand and its efforts to create and provide networked learning opportunities in this space.   &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Come work with us!
&lt;/h3&gt;

&lt;p&gt;We are hiring! There are tons of open positions at Stream right now, and we will post many more in the future as we continue to grow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbs773bm5dx192ebgp0ld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbs773bm5dx192ebgp0ld.png" alt="culture-value-summary-sheet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out these open roles: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/careers/job/site-reliability-engineer/" rel="noopener noreferrer"&gt;Site Reliability Engineer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/careers/job/backend-software-engineer-amsterdam/" rel="noopener noreferrer"&gt;Backend Software Engineer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/careers/job/lead-uiux-designer/" rel="noopener noreferrer"&gt;Lead UI/UX Designer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/careers/job/pr-specialist/" rel="noopener noreferrer"&gt;PR Specialist&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/careers/job/account-manager/" rel="noopener noreferrer"&gt;Account Manager&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>codeland</category>
    </item>
    <item>
      <title>Engineer turned CEO, Ask Me Anything!</title>
      <dc:creator>Thierry</dc:creator>
      <pubDate>Thu, 11 Apr 2019 02:12:36 +0000</pubDate>
      <link>https://forem.com/getstream_io/engineer-turned-ceo-ask-me-anything-534h</link>
      <guid>https://forem.com/getstream_io/engineer-turned-ceo-ask-me-anything-534h</guid>
      <description>&lt;p&gt;7 years professionally as an engineer. Started hobbying with code since I was 13. &lt;br&gt;
Have been the CEO of &lt;a href="https://getstream.io/"&gt;Stream&lt;/a&gt; now for 4 years. &lt;/p&gt;

</description>
      <category>ama</category>
    </item>
    <item>
      <title>How a Go Program Compiles down to Machine Code</title>
      <dc:creator>Thierry</dc:creator>
      <pubDate>Tue, 25 Sep 2018 06:00:26 +0000</pubDate>
      <link>https://forem.com/getstream_io/how-a-go-program-compiles-down-to-machine-code-56o8</link>
      <guid>https://forem.com/getstream_io/how-a-go-program-compiles-down-to-machine-code-56o8</guid>
      <description>

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GyZvNM8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/09/digesting_3_pounds_of_steak_.png%3Fw%3D1024%26h%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GyZvNM8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/09/digesting_3_pounds_of_steak_.png%3Fw%3D1024%26h%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here at Stream, we use Go extensively, and it has drastically improved our productivity. We have also found that by using Go, the speed is outstanding and since we started using it, we have implemented mission-critical portions of our stack, such as our in-house storage engine powered by gRPC, Raft, and RocksDB.&lt;/p&gt;

&lt;p&gt;Today we are going to look at the Go 1.11 compiler and how it compiles down your Go source code to an executable to gain an understanding of how the tools we use everyday work. We will also see why Go code is so fast and how the compiler helps. We will take a look at three phases of the compiler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The scanner, which converts the source code into a list of tokens, for use by the parser.&lt;/li&gt;
&lt;li&gt;The parser, which converts the tokens into an Abstract Syntax Tree to be used by code generation.&lt;/li&gt;
&lt;li&gt;The code generation, which converts the Abstract Syntax Tree to machine code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: The packages we are going to be using (&lt;/em&gt; &lt;strong&gt;&lt;em&gt;go/scanner&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;,&lt;/em&gt; &lt;strong&gt;&lt;em&gt;go/parser&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;,&lt;/em&gt; &lt;strong&gt;&lt;em&gt;go/token&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;,&lt;/em&gt; &lt;strong&gt;&lt;em&gt;go/ast&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;, etc.) are not used by the Go compiler, but are mainly provided for use by tools to operate on Go source code. However, the actual Go compiler has very similar semantics. It does not use these packages because the compiler was once written in C and converted to Go code, so the actual Go compiler is still reminiscent of that structure.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;Scanner&lt;/h1&gt;

&lt;p&gt;The first step of every compiler is to break up the raw source code text into tokens, which is done by the scanner (also known as lexer). Tokens can be keywords, strings, variable names, function names, etc. Every valid program “word” is represented by a token. In concrete terms for Go, this might mean we have a token “package”, “main”, “func” and so forth.&lt;/p&gt;

&lt;p&gt;Each token is represented by its position, type, and raw text in Go. Go even allows us to execute the scanner ourselves in a Go program by using the &lt;strong&gt;go/scanner&lt;/strong&gt; and &lt;strong&gt;go/token&lt;/strong&gt; packages. That means we can inspect what our program looks like to the Go compiler after it has been scanned. To do so, we are going to create a simple program that prints all tokens of a Hello World program.&lt;/p&gt;

&lt;p&gt;The program will look like this:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/nparsons08/fb5d7350f2f052d8f50794c010285019"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will create our source code string and initialize the &lt;strong&gt;scanner.Scanner&lt;/strong&gt; struct which will scan our source code. We call &lt;strong&gt;Scan()&lt;/strong&gt; as many times as we can and print the token’s position, type, and literal string until we reach the End of File ( &lt;strong&gt;EOF&lt;/strong&gt; ) marker.&lt;/p&gt;

&lt;p&gt;When we run the program, it will print the following:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/koesie10/e312024b5f52795756e81a95906bd8e1"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here we can see what the Go parser uses when it compiles a program. What we can also see is that the scanner adds semicolons where those would usually be placed in other programming languages such as C. This explains why Go does not need semicolons: they are placed intelligently by the scanner.&lt;/p&gt;

&lt;h1&gt;Parser&lt;/h1&gt;

&lt;p&gt;After the source code has been scanned, it will be passed to the parser. The parser is a phase of the compiler that converts the tokens into an Abstract Syntax Tree (AST). The AST is a structured representation of the source code. In the AST we will be able to see the program structure, such as functions and constant declarations.&lt;/p&gt;

&lt;p&gt;Go has again provided us with packages to parse the program and view the AST: &lt;strong&gt;go/parser&lt;/strong&gt; and &lt;strong&gt;go/ast&lt;/strong&gt;. We can use them like this to print the full AST:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/nparsons08/234cc8ff0aa75067c22607d633d2e1f0"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/nparsons08/85f429cd024544f3b73dfa6c6d81c15d"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this output, you can see that there is quite some information about the program. In the &lt;strong&gt;Decls&lt;/strong&gt; fields, there is a list of all declarations in the file, such as imports, constants, variables, and functions. In this case, we only have two: our import of the &lt;strong&gt;fmt&lt;/strong&gt; package and the main function.&lt;/p&gt;

&lt;p&gt;To digest it further, we can look at this diagram, which is a representation of the above data, but only includes types and in red the code that corresponds to the nodes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mFbvkXde--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/09/image1-5.png%3Fw%3D1024%26h%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mFbvkXde--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/09/image1-5.png%3Fw%3D1024%26h%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main function is composed of three parts: the name, the declaration, and the body. The name is represented as an identifier with the value main. The declaration, specified by the Type field, would contain a list of parameters and return type if we had specified any. The body consists of a list of statements with all lines of our program, in this case only one.&lt;/p&gt;

&lt;p&gt;Our single &lt;strong&gt;fmt.Println&lt;/strong&gt; statement consists of quite a few parts in the AST. The statement is an &lt;strong&gt;ExprStmt&lt;/strong&gt; , which represents an expression, which can, for example, be a function call, as it is here, or it can be a literal, a binary operation (for example addition and subtraction), a unary operation (for instance negating a number) and many more. Anything that can be used in a function call’s arguments is an expression.&lt;/p&gt;

&lt;p&gt;Our &lt;strong&gt;ExprStmt&lt;/strong&gt; contains a &lt;strong&gt;CallExpr&lt;/strong&gt; , which is our actual function call. This again includes several parts, most important of which are &lt;strong&gt;Fun&lt;/strong&gt; and &lt;strong&gt;Args&lt;/strong&gt;. Fun contains a reference to the function call, in this case, it is a &lt;strong&gt;SelectorExpr&lt;/strong&gt; , because we select the &lt;strong&gt;Println&lt;/strong&gt; identifier from the fmt package. However, in the AST it is not yet known to the compiler that &lt;strong&gt;fmt&lt;/strong&gt; is a package, it could also be a variable in the AST.&lt;/p&gt;

&lt;p&gt;Args contains a list of expressions which are the arguments to the function. In this case, we have passed a literal string to the function, so it is represented by a &lt;strong&gt;BasicLit&lt;/strong&gt; with type &lt;strong&gt;STRING&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is clear that we are able to deduce a lot from the AST. That means that we can also inspect the AST further and find for example all function calls in the file. To do so, we are going to use the &lt;strong&gt;Inspect&lt;/strong&gt; function from the &lt;strong&gt;ast&lt;/strong&gt; package. This function will recursively walk the tree and allow us to inspect the information from all nodes.&lt;/p&gt;

&lt;p&gt;To extract all function calls, we are going to use the following code:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/koesie10/ba6af59e0dd8213260e5944c1464b0b1"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What we are doing here is looking for all nodes and whether they are of type &lt;strong&gt;*ast.CallExpr&lt;/strong&gt; , which we just saw represented our function call. If they are, we are going to print the name of the function, which was present in the &lt;strong&gt;Fun&lt;/strong&gt; member, using the printer package.&lt;/p&gt;

&lt;p&gt;The output for this code will be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;fmt.Println&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is indeed the only function call in our simple program, so we indeed found all function calls.&lt;/p&gt;

&lt;p&gt;After the AST has been constructed, all imports will be resolved using the GOPATH, or for Go 1.11 and up possibly &lt;a href="https://github.com/golang/go/wiki/Modules"&gt;modules&lt;/a&gt;. Then, types will be checked, and some preliminary optimizations are applied which make the execution of the program faster.&lt;/p&gt;

&lt;h1&gt;Code generation&lt;/h1&gt;

&lt;p&gt;After the imports have been resolved and the types have been checked, we are certain the program is valid Go code and we can start the process of converting the AST to (pseudo) machine code.&lt;/p&gt;

&lt;p&gt;The first step in this process is to convert the AST to a lower-level representation of the program, specifically into a Static Single Assignment (SSA) form. This intermediate representation is not the final machine code, but it does represent the final machine code a lot more. SSA has a set of properties that make it easier to apply optimizations, most important of which that a variable is always defined before it is used and each variable is assigned exactly once.&lt;/p&gt;

&lt;p&gt;After the initial version of the SSA has been generated, a number of optimization passes will be applied. These optimizations are applied to certain pieces of code that can be made simpler or faster for the processor to execute. For example, dead code, such as &lt;strong&gt;if (false) { fmt.Println(“test”) }&lt;/strong&gt; can be eliminated because this will never execute. Another example of an optimization is that certain nil checks can be removed because the compiler can prove that these will never false.&lt;/p&gt;

&lt;p&gt;Let’s now look at the SSA and a few optimization passes of this simple program:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/koesie10/c1499e5352f2558da6c7be93c203da78"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you can see, this program has only one function and one import. It will print 2 when run. However, this sample will suffice for looking at the SSA.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Only the SSA for the main function will be shown, as that is the interesting part.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To show the generated SSA, we will need to set the &lt;strong&gt;GOSSAFUNC&lt;/strong&gt; environment variable to the function we would like to view the SSA of, in this case main. We will also need to pass the -S flag to the compiler, so it will print the code and create an HTML file. We will also compile the file for Linux 64-bit, to make sure the machine code will be equal to what you will be seeing here. So, to compile the file we will run:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$ GOSSAFUNC=main GOOS=linux GOARCH=amd64 go build -gcflags “-S” simple.go&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It will print all SSA, but it will also generate a ssa.html file which is interactive so we will use that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uP63I01s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/09/image3-4.png%3Fw%3D1024%26h%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uP63I01s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/09/image3-4.png%3Fw%3D1024%26h%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you open ssa.html, a number of passes will be shown, most of which are collapsed. The start pass is the SSA that is generated from the AST; the lower pass converts the non-machine specific SSA to machine-specific SSA and genssa is the final generated machine code.&lt;/p&gt;

&lt;p&gt;The start phase’s code will look like this:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/nparsons08/cc9727e156fd51156892a039c4398f2d"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This simple program already generates quite a lot of SSA (35 lines in total). However, a lot of it is boilerplate and quite a lot can be eliminated (the final SSA version has 28 lines and the final machine code version has 18 lines).&lt;/p&gt;

&lt;p&gt;Each v is a new variable and can be clicked to view where it is used. The &lt;strong&gt;b&lt;/strong&gt;** ’s &lt;strong&gt;are blocks, so in this case, we have three blocks:&lt;/strong&gt; b1 *&lt;em&gt;**,&lt;/em&gt;*  &lt;strong&gt;b2&lt;/strong&gt; , and &lt;strong&gt;b3&lt;/strong&gt;&lt;strong&gt;. **&lt;/strong&gt; b1 &lt;strong&gt;will always be executed.&lt;/strong&gt; b2 &lt;strong&gt;and&lt;/strong&gt; b3 &lt;strong&gt;are conditional blocks, which can be seen by the&lt;/strong&gt; If v19 → b2 b3 (likely) &lt;strong&gt;at the end of&lt;/strong&gt; b1 &lt;strong&gt;. We can click the&lt;/strong&gt; v19 &lt;strong&gt;in that line to view where&lt;/strong&gt; v19 &lt;strong&gt;is defined. We see it is defined as&lt;/strong&gt; IsSliceInBounds  v14 v15*&lt;em&gt;, and by &lt;a href="https://github.com/golang/go/blob/3fd364988ce5dcf3aa1d4eb945d233455db30af6/src/cmd/compile/internal/ssa/gen/genericOps.go#L411"&gt;viewing the Go compiler source code&lt;/a&gt; we can see that&lt;/em&gt;&lt;em&gt;IsSliceInBounds **checks that&lt;/em&gt;* 0 &amp;lt;= arg0 &amp;lt;= arg1 &lt;strong&gt;. We can also click&lt;/strong&gt; v14 &lt;strong&gt;and&lt;/strong&gt; v15 &lt;strong&gt;to view how they are defined and we will see that&lt;/strong&gt; v14 = Const64  [0] *&lt;em&gt;**;&lt;/em&gt;*  &lt;strong&gt;Const64&lt;/strong&gt; is a constant 64-bit integer. &lt;strong&gt;v15&lt;/strong&gt; is defined as the same but as &lt;strong&gt;1&lt;/strong&gt;. So, we essentially have &lt;strong&gt;0 &amp;lt;= 0 &amp;lt;= 1&lt;/strong&gt; , which is obviously &lt;strong&gt;true&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The compiler is also able to prove this and when we look at the &lt;strong&gt;opt&lt;/strong&gt; phase (“machine-independent optimization”), we can see that it has rewritten &lt;strong&gt;v19&lt;/strong&gt; as &lt;strong&gt;ConstBool&lt;/strong&gt; &lt;strong&gt; [true]&lt;/strong&gt;. This will be used in the &lt;strong&gt;opt deadcode&lt;/strong&gt; phase, where &lt;strong&gt;b3&lt;/strong&gt; is removed because &lt;strong&gt;v19&lt;/strong&gt; from the conditional shown before is always true.&lt;/p&gt;

&lt;p&gt;We are now going to take a look at another, simpler, optimization made by the Go compiler after the SSA has been converted into machine-specific SSA, so this will be machine code for the amd64 architecture. To do so, we are going to compare lower to lowered deadcode. This is the content of the lower phase:&lt;/p&gt;

&lt;p&gt;View the code on &lt;a href="https://gist.github.com/nparsons08/be27cf0aa4dd376e1f1fa9867d6695e9"&gt;Gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the HTML file, some lines are greyed out, which means they will be removed or changed in one of the next phases. For example, &lt;strong&gt;v15&lt;/strong&gt; (&lt;strong&gt;MOVQconst  [1]&lt;/strong&gt;) is greyed out. By further examining &lt;strong&gt;v15&lt;/strong&gt; by clicking on it, we see it is used nowhere else, and &lt;strong&gt;MOVQconst&lt;/strong&gt; is essentially the same instruction as we saw before, &lt;strong&gt;Const64&lt;/strong&gt; , only machine-specific for &lt;strong&gt;amd64&lt;/strong&gt;. So, we are setting &lt;strong&gt;v15&lt;/strong&gt; to &lt;strong&gt;1&lt;/strong&gt;. However, &lt;strong&gt;v15&lt;/strong&gt; is used nowhere else, so it is useless (dead) code and can be eliminated.&lt;/p&gt;

&lt;p&gt;The Go compiler applies a lot of these kinds of optimization. So, while the first generation of SSA from the AST might not be the fastest implementation, the compiler optimizes the SSA to a much faster version. Every phase in the HTML file is a phase where speed-ups can potentially happen.&lt;/p&gt;

&lt;p&gt;If you are interested to learn more about SSA in the Go compiler, please check out the &lt;a href="https://github.com/golang/go/tree/master/src/cmd/compile/internal/ssa"&gt;Go compiler’s SSA source&lt;/a&gt;. Here, all operations, as well as optimizations, are defined.&lt;/p&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Go is a very productive and performant language, supported by its compiler and its optimization. To learn more about the Go compiler, &lt;a href="https://github.com/golang/go/tree/master/src/cmd/compile"&gt;the source code&lt;/a&gt; has a great README.&lt;/p&gt;

&lt;p&gt;If you would like to learn more about why Stream uses Go and in particular why we moved from Python to Go, please check out &lt;a href="https://getstream.io/blog/switched-python-go/"&gt;our blog post on switching to Go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://getstream.io/blog/how-a-go-program-compiles-down-to-machine-code/"&gt;How a Go Program Compiles down to Machine Code&lt;/a&gt; appeared first on &lt;a href="https://getstream.io/blog"&gt;The Stream Blog&lt;/a&gt;.&lt;/p&gt;


</description>
      <category>bestpractices</category>
      <category>go</category>
      <category>tutorial</category>
      <category>compilation</category>
    </item>
    <item>
      <title>Stream &amp; Go: News Feeds for Over 300+ Million End Users</title>
      <dc:creator>Nick Parsons</dc:creator>
      <pubDate>Sun, 08 Jul 2018 18:27:10 +0000</pubDate>
      <link>https://forem.com/getstream_io/stream--go-news-feeds-for-over-300-million-end-users-3mci</link>
      <guid>https://forem.com/getstream_io/stream--go-news-feeds-for-over-300-million-end-users-3mci</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0uj4kjzso534kurzmxn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0uj4kjzso534kurzmxn8.png" alt="GetStream.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; is an API that enables developers to build news feeds and activity streams (&lt;a href="https://getstream.io/try-the-api" rel="noopener noreferrer"&gt;try the API&lt;/a&gt;. We are used by over 500 companies and power the feeds of more than 300 million end users. Companies such as Product Hunt, Under Armour, Powerschool, Bandsintown, Dubsmash, Compass, and Fabric (Google) rely on Stream to power their news feeds. In addition to the API, the founders of Stream also wrote the most widely used &lt;a href="https://github.com/tschellenbach/stream-framework" rel="noopener noreferrer"&gt;open source solution for building scalable feeds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what Stream looks like today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of servers: 180&lt;/li&gt;
&lt;li&gt;Feed updates per month: 34 billion&lt;/li&gt;
&lt;li&gt;Average API response time: 12ms&lt;/li&gt;
&lt;li&gt;Average real-time response time: 2ms&lt;/li&gt;
&lt;li&gt;Regions: 4 (US-East, EU-West, Tokyo, and Singapore)&lt;/li&gt;
&lt;li&gt;1B API requests per month (~20k/minute)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given that most of our customers are engineers, we often talk about our stack. Here’s a high-level overview:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go is our primary programming language.&lt;/li&gt;
&lt;li&gt;We use a custom solution built on top of RocksDB + Raft for our primary database (we started out on Cassandra but wanted more control over performance). PostgreSQL stores configs, API keys, etc.&lt;/li&gt;
&lt;li&gt;OpenTracing and Jaeger handle tracing, StatsD and Grafana provide detailed monitoring and we use the ELK stack for centralized logging.&lt;/li&gt;
&lt;li&gt;Python is our language of choice for machine learning, DevOps and our website &lt;a href="https://getstream.io" rel="noopener noreferrer"&gt;https://getstream.io&lt;/a&gt; (Django, DRF &amp;amp; React).&lt;/li&gt;
&lt;li&gt;Stream uses a combination of fanout-on-write and fanout-on-read. This results in fast read performance when a users open their feed, as well as fast propagation times when a famous user posts an update.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://twitter.com/tommasobarbugli" rel="noopener noreferrer"&gt;Tommaso Barguli&lt;/a&gt; and &lt;a href="https://twitter.com/tschellenbach" rel="noopener noreferrer"&gt;Thierry Schellenbach&lt;/a&gt; are the developers who started Stream nearly 3 years ago. We founded the company in Amsterdam, participated in Techstars NYC 2015 and opened up our Boulder, Colorado office in 2016. It’s been quite a crazy ride in a fairly short amount of time! With over 15 developers and a host of supporting roles, including sales and marketing, the team feels enormous compared to the early days.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Challenge: News Feeds &amp;amp; Activity Streams
&lt;/h1&gt;

&lt;p&gt;The nature of follow relationships makes it hard to scale feeds. Most of you will remember Facebook’s long load times, Twitter’s fail whale or Tumblr’s year of technical debt. Feeds are hard to scale since there is no clear way to shard the data. Follow relationships connect everyone to everyone else. This makes it difficult to split data across multiple machines. If you want to learn more about this problem, check out these papers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Twitter’s tech back in the days with 150 million active users&lt;/li&gt;
&lt;li&gt;LinkedIn’s ranked feeds&lt;/li&gt;
&lt;li&gt;Yahoo/Princeton research paper&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a very high level there are 3 different ways to scale your feeds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fanout-on-write: basically precompute everything. It’s expensive, but it's easy to shard the data.&lt;/li&gt;
&lt;li&gt;Fanout-on-read: hard to scale, but more affordable and new activities show up faster.&lt;/li&gt;
&lt;li&gt;Combination of the above two approaches: better performance and reduced latency, but increased code complexity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stream uses a combination of fanout-on-write and fanout-on-read. This allows us to effectively support both customers with highly connected graphs, as well as customers with a more sparse dataset. This is important since the ways in which our customers use Stream are very different. Have a look at these screenshots from Bandsintown, Unsplash, and Product Hunt:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq36lzs68cfjqq9lk1igo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq36lzs68cfjqq9lk1igo.png" alt="Product Hunt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Switching from Python to Go
&lt;/h1&gt;

&lt;p&gt;After years of optimizing our existing feed technology, we decided to make a larger leap with 2.0 of Stream. While the first iteration of Stream was powered by Python and Cassandra, for Stream 2.0 of our infrastructure we switched to Go. The main reason why we switched from Python to Go is performance. Certain features of Stream such as aggregation, ranking and serialization were very difficult to speed up using Python.&lt;/p&gt;

&lt;p&gt;We’ve been using Go since March 2017 and it’s been a great experience so far. Go has greatly increased the productivity of our development team. Not only has it improved the speed at which we develop, it’s also 30x faster for many components of Stream.&lt;/p&gt;

&lt;p&gt;The performance of Go greatly influenced our architecture in a positive way. With Python we often found ourselves delegating logic to the database layer purely for performance reasons. The high performance of Go gave us more flexibility in terms of architecture. This led to a huge simplification of our infrastructure and a dramatic improvement of latency. For instance, we saw a 10 to 1 reduction in web-server count thanks to the lower memory and CPU usage for the same number of requests.&lt;/p&gt;

&lt;p&gt;Initially, we struggled a bit with package management for Go. However, using &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;Dep&lt;/a&gt; together with the &lt;a href="https://github.com/getstream/vg" rel="noopener noreferrer"&gt;VG package&lt;/a&gt; contributed to creating a great workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6fhsczu1mvjshc14xzmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6fhsczu1mvjshc14xzmm.png" alt="VG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’ve never tried Go, you’ll want to try this online tour: &lt;a href="https://tour.golang.org/welcome/1" rel="noopener noreferrer"&gt;https://tour.golang.org/welcome/1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go as a language is heavily focused on performance. The built-in PPROF tool is amazing for finding performance issues. Uber’s Go-Torch library is great for visualizing data from PPROF and will be bundled in PPROF in Go 1.10.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnpipzmly6upg9gifoigq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnpipzmly6upg9gifoigq.png" alt="Flame Graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Switching from Cassandra to RocksDB &amp;amp; Raft
&lt;/h1&gt;

&lt;p&gt;1.0 of Stream leveraged Cassandra for storing the feed. Cassandra is a common choice for building feeds. Instagram, for instance, started, out with Redis but eventually switched to Cassandra to handle their rapid usage growth. Cassandra can handle write-heavy workloads very efficiently.&lt;/p&gt;

&lt;p&gt;Cassandra is a great tool that allows you to scale write capacity simply by adding more nodes, though it is also very complex. This complexity made it hard to diagnose performance fluctuations. Even though we had years of experience with running Cassandra, it still felt like a bit of a black box. When building Stream 2.0 we decided to go for a different approach and build Keevo. Keevo is our in-house key-value store built upon RocksDB, gRPC, and Raft.&lt;/p&gt;

&lt;p&gt;RocksDB is a highly performant embeddable database library developed and maintained by Facebook’s data engineering team. RocksDB started as a fork of Google’s LevelDB that introduced several performance improvements for SSD. Nowadays RocksDB is a project on its own and is under active development. It is written in C++ and it’s fast. Have a look at how this benchmark handles 7 million QPS. In terms of technology, it’s much more simple than Cassandra. This translates into reduced maintenance overhead, improved performance and, most importantly, more consistent performance. It’s interesting to note that LinkedIn also uses RocksDB for their feed.&lt;/p&gt;

&lt;p&gt;Our infrastructure is hosted on AWS and is designed to survive entire availability zone outages. Unlike Cassandra, Keevo clusters organize nodes into leaders and followers. When a leader (master) node becomes unavailable the other nodes in the same deployment will start an election and pick a new leader. Electing a new leader is a fast operation and barely impacts live traffic.&lt;/p&gt;

&lt;p&gt;To do this, Keevo implements the Raft consensus algorithm using Hashicorp’s Go implementation. This ensures that every bit stored in Keevo is stored on 3 different servers and operations are always consistent. This site does a great job of visualizing how Raft works: &lt;a href="https://raft.github.io/" rel="noopener noreferrer"&gt;https://raft.github.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fi2yyomms1acdelsb3ubl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fi2yyomms1acdelsb3ubl.png" alt="Consensus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Not Quite Microservices
&lt;/h1&gt;

&lt;p&gt;By leveraging Go and RocksDB we’re able to achieve great feed performance. The average response time is around 12ms. The architecture lies somewhere between a monolith and a microservice. Stream runs on the following 7 services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stream API&lt;/li&gt;
&lt;li&gt;Keevo&lt;/li&gt;
&lt;li&gt;Real-time &amp;amp; Firehose&lt;/li&gt;
&lt;li&gt;Analytics&lt;/li&gt;
&lt;li&gt;Personalization &amp;amp; Machine learning&lt;/li&gt;
&lt;li&gt;Site &amp;amp; Dashboard&lt;/li&gt;
&lt;li&gt;Async Workers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To see all our services divided into stacks, head over &lt;a href="https://dev.tohere"&gt;https://stackshare.io/stream/stacks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personalization &amp;amp; Machine Learning
&lt;/h2&gt;

&lt;p&gt;Almost all large apps with feeds use machine learning and personalization. For instance, LinkedIn prioritizes the items in your feed. Instagram’s explore feed displays pictures outside of the people you follow that you might be interested in. Etsy uses a similar approach to optimize e-commerce conversion. Stream supports the following 5 use cases for personalization:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv38nu2y06fs7cq9gvdzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv38nu2y06fs7cq9gvdzs.png" alt="Social"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getstream.io/docs/" rel="noopener noreferrer"&gt;Documentation for building personalized feeds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All of these personalization use cases rely on combining feeds with analytics and machine learning. For the machine learning side, we generate the models using Python. The models are different for each of our enterprise customers. Typically we’ll use one of these amazing libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LightFM — How to implement recommender systems&lt;/li&gt;
&lt;li&gt;XGBoost&lt;/li&gt;
&lt;li&gt;Scikit learn&lt;/li&gt;
&lt;li&gt;Numpy, Pandas, and Dask&lt;/li&gt;
&lt;li&gt;Jupyter Notebook (For development)&lt;/li&gt;
&lt;li&gt;Mesa Framework&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Analytics
&lt;/h2&gt;

&lt;p&gt;Analytics data is collected using a tiny Go-based server. In the background, it will spawn go-routines to rollup the data as needed. The resulting metrics are stored in Elastic. In the past, we looked at Druid, which seems like a solid project. For now, we could get away with a simpler solution though.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dashboard &amp;amp; Site
&lt;/h2&gt;

&lt;p&gt;The dashboard is powered by React and Redux. We also use React and Redux for all of our example applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getstream.io/cabin/" rel="noopener noreferrer"&gt;Cabin: A tutorial series on building a social network with React &amp;amp; Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getstream.io/winds" rel="noopener noreferrer"&gt;Winds: Open source RSS &amp;amp; Podcast app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The site, as well as the API for the site, is powered by Python, Django and Django Rest Framework. Stream is sponsoring Django Rest Framework since it’s a pretty great open source project. If you need to build an API quickly there is no better tool than DRF and Python.&lt;/p&gt;

&lt;p&gt;We use Imgix to resize the images on our site. For us, Imgix is cost-efficient, fast and overall a great service. Thumbor is a good open source alternative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-time
&lt;/h2&gt;

&lt;p&gt;Our real-time infrastructure is based on Go, Redis and the excellent gorilla websocket library. It implements the Bayeux protocol. In terms of architecture, it’s very similar to the node based Faye library.&lt;/p&gt;

&lt;p&gt;It was interesting to read the “Ditching Go for Node.js” post on Hacker News. The author moves from Go to Node to improve performance. We actually did the exact opposite and moved from Node to Go for our real-time system. The new Go-based infrastructure handles 8x the traffic per node.&lt;/p&gt;

&lt;h1&gt;
  
  
  Devops, Testing &amp;amp; Multiple Regions
&lt;/h1&gt;

&lt;p&gt;In terms of DevOps, the provisioning and configuration of instances is fully automated using a combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudFormation&lt;/li&gt;
&lt;li&gt;Cloud-Init&lt;/li&gt;
&lt;li&gt;Puppet&lt;/li&gt;
&lt;li&gt;Boto &amp;amp; Fabric&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because our infrastructure is defined in the code it has become trivial to launch new regions. We heavily use CloudFormation. Every single piece of our stack is defined in a CloudFormation template. If needed we are able to spawn a new dedicated shard in a few minutes. In addition, AWS Parameter Store is used to hold application settings. Our largest deployment is in US-East, but we also have regions in Tokyo, Singapore and Dublin.&lt;/p&gt;

&lt;p&gt;A combination of Puppet and Cloud-init is used to configure our instances. We run our self-contained Go’s binaries directly on the EC2 instance without any additional containerization layer.&lt;/p&gt;

&lt;p&gt;Releasing new versions of our services are done by Travis. Travis first runs our test suite. Once it passes, it publishes a new release binary to GitHub. Common tasks such as installing dependencies for the Go project, or building a binary are automated using plain old Makefiles. (We know, crazy old school, right?) Our binaries are compressed using UPX.&lt;/p&gt;

&lt;p&gt;Tool highlight: &lt;strong&gt;Travis&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Travis has come a long way over the past years. I used to prefer Jenkins in some cases since it was easier to debug broken builds. With the addition of the aptly named “debug build” button, Travis is now the clear winner. It’s easy to use and free for open source, with no need to maintain anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fixvc5ccrhxteuxp83ku1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fixvc5ccrhxteuxp83ku1.png" alt="Travis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we use Fabric to do a rolling deploy to our AWS instances. If anything goes wrong during the deploy it will halt the deploy. We take stability very seriously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A high level of test coverage is required.&lt;/li&gt;
&lt;li&gt;Releases are created by Travis (making it hard to deploy without running tests).&lt;/li&gt;
&lt;li&gt;Code is reviewed by at least 2 team members.&lt;/li&gt;
&lt;li&gt;Our extensive QA integration test suite evaluates if all 7 components still work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ve written about our experience with testing our Go codebase. When things do break we do our best to be transparent about the ongoing issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;StatusPage&lt;/li&gt;
&lt;li&gt;Twilio for 24/7 phone support&lt;/li&gt;
&lt;li&gt;VictorOps for notifying our team&lt;/li&gt;
&lt;li&gt;#firefighting channel on Slack&lt;/li&gt;
&lt;li&gt;Intercom for customer support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VictorOps is a recent addition to our support stack. It’s made it very easy to collaborate on ongoing issues.&lt;/p&gt;

&lt;p&gt;Tool Highlight: &lt;strong&gt;VictorOps&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best part about VictorOps is how they use a timeline to collaborate amongst team members. VictorOps is an elegant way to keep our team in the loop about outages. It also integrates well with Slack. This setup enables us to quickly react to any problems that make it into production, work together and resolve them faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F19u5udut103ecmdj04rt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F19u5udut103ecmdj04rt.png" alt="VictorOps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The vast majority of our infrastructure runs on AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ELB for load balancing&lt;/li&gt;
&lt;li&gt;RDS for reliable Postgres hosting&lt;/li&gt;
&lt;li&gt;ElastiCache for Redis hosting&lt;/li&gt;
&lt;li&gt;Route53 for our DNS&lt;/li&gt;
&lt;li&gt;CloudFront for our CDN&lt;/li&gt;
&lt;li&gt;AWS ElasticSearch for ELK and tracing with Jaeger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The DevOps responsibilities are shared across our team. While we do have one dedicated DevOps engineer, all our developers have to understand and own the entire workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;Stream uses OpenTracing for tracing and Grafana for beautiful dashboards. The tracking for Grafana is done using StatsD. The end result is this beauty:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff6o2vf1mh35zhxzmpnuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff6o2vf1mh35zhxzmpnuw.png" alt="Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We track our errors in Sentry and use the ELK stack to centralize our logs.&lt;/p&gt;

&lt;p&gt;Tool Highlight: &lt;strong&gt;OpenTracing + Jaegar&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One new addition to the stack is OpenTracing. In the past, we used New Relic, which works like a charm for Python but isn’t able to automatically measure tracing information for Go. OpenTracing with Jaeger is a great solution that works very well for Stream. It also has, perhaps, the best logo for a tracing solution:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fp6smhl03dfhhgrlrkpns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fp6smhl03dfhhgrlrkpns.png" alt="Gopher"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Closing Thoughts
&lt;/h1&gt;

&lt;p&gt;Go is an absolutely amazing language and has been a major win in terms of performance and developer productivity. For tracing we use OpenTracing and Jaeger. Our monitoring is running on StatsD and Graphite. Centralized logging is handled by the ELK stack.&lt;/p&gt;

&lt;p&gt;Stream’s main database is a custom solution built on top of RocksDB and Raft. In the past, we used Cassandra, which we found hard to maintain and which didn’t give us enough control over performance when compared to RocksDB.&lt;/p&gt;

&lt;p&gt;We leverage external tools and solutions for everything that’s not a core competence. Redis hosting is handled by ElastiCache, Postgres by RDS, email by Mailgun, test builds by Travis and error reporting by Sentry.&lt;/p&gt;

&lt;p&gt;Thank you for reading about our stack! If you’re a user of &lt;a href="https://getstream.io" rel="noopener noreferrer"&gt;Stream&lt;/a&gt;, please be sure to add Stream to your stack on StackShare. If you’re a talented individual, come work with us! And finally, if you haven’t tried out Stream yet, take a look at this &lt;a href="https://getstream.io/try-the-api" rel="noopener noreferrer"&gt;quick tutorial&lt;/a&gt; for the API.&lt;/p&gt;

</description>
      <category>go</category>
      <category>python</category>
      <category>django</category>
      <category>database</category>
    </item>
    <item>
      <title>React Fragments – the end of the wrapper div</title>
      <dc:creator>Ken Hoff</dc:creator>
      <pubDate>Mon, 18 Jun 2018 08:30:55 +0000</pubDate>
      <link>https://forem.com/getstream_io/react-fragments--the-end-of-the-wrapper-div-pp2</link>
      <guid>https://forem.com/getstream_io/react-fragments--the-end-of-the-wrapper-div-pp2</guid>
      <description>

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi there! I’m Ken. I’m a Developer Advocate over at &lt;a href="https://getstream.io/"&gt;GetStream.io&lt;/a&gt;, where we build personalized and scalable activity feeds.&lt;/p&gt;

&lt;p&gt;For the last several months, I’ve been working on Winds 2.0, an open-source RSS reader and podcast listening app. It’s built in Node.js, Electron, Redux and React, and as of this writing, has over 5,000 stars on GitHub. If you’d like to check it out, head on over to &lt;a href="https://getstream.io/winds/"&gt;https://getstream.io/winds/&lt;/a&gt;, or check out the source code at &lt;a href="https://github.com/GetStream/winds"&gt;https://github.com/GetStream/winds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Winds, we had a couple of unique frontend situations requiring the use of &lt;strong&gt;React Fragments&lt;/strong&gt;. React Fragments are a neat little feature that were released late last year with &lt;a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html"&gt;React v16.2.0&lt;/a&gt; — it’s a pretty small feature, but just knowing about the existence of them can save developers a huge headache when running into some very specific layout and styling situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, so what’s a React Fragment?
&lt;/h2&gt;

&lt;p&gt;Let’s back up a little — I’m sure that every React developer will have run into this at some point in their career (or will, very soon):&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I would&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;really like&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;to render&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;an array&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Looks fine to me! But when we run it through the JSX transpiler…&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Failed to compile.

    ./src/App.js
    Syntax error: Adjacent JSX elements must be wrapped in an enclosing tag (6:8)

        4 |         return (&amp;lt;p&amp;gt;I would
        5 |         &amp;lt;/p&amp;gt;
        6 |         &amp;lt;p&amp;gt;
          |         ^
        7 |             really like
        8 |         &amp;lt;/p&amp;gt;
        9 |         &amp;lt;p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our JSX transpiler doesn’t like that 🙁&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;( &lt;strong&gt;What’s happening behind the curtain here?&lt;/strong&gt; JSX is turning all of our &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s and &lt;code&gt;&amp;lt;MyComponent&amp;gt;&lt;/code&gt;s into &lt;code&gt;React.createElement()&lt;/code&gt; calls — when the JSX transpiler sees multiple elements instead of a single element, it doesn’t know what tag name to render with. See &lt;a href="https://reactjs.org/docs/react-api.html#createelement"&gt;React.createElement in the React documentation&lt;/a&gt;.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, what do we do? The same thing that we do every time we need to wrap a couple elements together, Pinky — wrap it in a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;! Just like web developers have been doing since the invention of the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag, another nested &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; in the DOM won’t hurt anything (probably).&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I would&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;really like&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;to render&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;an array&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Right, problem solved. But it turns out, there’s one more way to render this group of content on the page inside of a single React Component – by having the &lt;code&gt;render&lt;/code&gt; method return an &lt;em&gt;array&lt;/em&gt; of nodes.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I would&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;really like&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;to render&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;an array&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we return an &lt;em&gt;array&lt;/em&gt; of elements, then React will transpile and render this just fine, &lt;em&gt;without a wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/em&gt;. Neat!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(Remember how the JSX transpiler is just turning the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;MyComponent&amp;gt;&lt;/code&gt; tags into &lt;code&gt;React.createElement()&lt;/code&gt; calls? In this case, the transpiler is just putting together an array of those calls and affixing them directly to the parent element as children, as opposed to an array of uncontained elements that it can’t find a parent for. This feature got introduced with React v16.0.0.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See, here’s the thing – Dan Abramov and the super duper smart folks on the React team looked at this and said:&lt;/p&gt;

&lt;p&gt;“Okay, so you can render an array of elements in two different ways – either by introducing an extra &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; into the DOM, or by using some clunky non-JSX syntax. That doesn’t make for a good developer experience!”&lt;/p&gt;

&lt;p&gt;So, in v16.2.0, they &lt;a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html"&gt;released support for React Fragments&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, &lt;strong&gt;now&lt;/strong&gt; what’s a React Fragment?
&lt;/h2&gt;

&lt;p&gt;Here’s the correct way to use a React Fragment:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I would&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;really like&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;to render&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;an array&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Check this out – we write this just like we would the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;-wrapper method, but it’ll behave functionally equivalent to the array-render method, just with some nice JSX syntax. This will render those paragraph elements as an array, without any kind of wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There’s also an alternate, more concise syntax for using React Fragments:&lt;/p&gt;
&lt;/blockquote&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I would&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;really like&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;to render&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;an array&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Depending on your tooling, linters, build pipeline, etc, this might not work for you – the release notes say that wider support is on the way, but I’ve noticed &lt;code&gt;create-react-app&lt;/code&gt; doesn’t support it yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Okay, but when do I actually use them?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Whenever you need to get rid of a wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s it – if you ever find yourself in a situation where a wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; is screwing up the layout of your React components, use a React Fragment.&lt;/p&gt;

&lt;p&gt;So, whenever you want to turn this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    (...a bunch of other elements)

    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt; (my react component)
        &lt;span class="nt"&gt;&amp;lt;ComponentA&amp;gt;&amp;lt;/ComponentA&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ComponentB&amp;gt;&amp;lt;/ComponentB&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ComponentC&amp;gt;&amp;lt;/ComponentC&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    (...a bunch more elements)

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Into this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    (...a bunch of other elements)

    &lt;span class="nt"&gt;&amp;lt;ComponentA&amp;gt;&amp;lt;/ComponentA&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ComponentB&amp;gt;&amp;lt;/ComponentB&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ComponentC&amp;gt;&amp;lt;/ComponentC&amp;gt;&lt;/span&gt;

    (...a bunch more elements)

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Example: 2×2 CSS grid
&lt;/h2&gt;

&lt;p&gt;In Winds 2.0, we made pretty heavy use of &lt;a href="https://css-tricks.com/snippets/css/complete-guide-grid/"&gt;CSS Grid&lt;/a&gt;. This is one of the general layouts that you’ll see when looking through podcasts or RSS feeds:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tpKZbNPS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/06/Screen-Shot-2018-06-15-at-10.49.13-AM.png%3Fw%3D300%26h%3D300" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tpKZbNPS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://getstream-blog.imgix.net/blog/wp-content/uploads/2018/06/Screen-Shot-2018-06-15-at-10.49.13-AM.png%3Fw%3D300%26h%3D300" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t know CSS Grid yet, don’t worry – this bit of CSS will give you a quick idea of how things are laid out:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-areas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="s2"&gt;'topnav header'&lt;/span&gt; 
        &lt;span class="s2"&gt;'subnav content'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Okay, let’s unpack this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the upper left, we’ve got our brand / top-level navigation bits. &lt;/li&gt;
&lt;li&gt;In the lower left, we’ve got our “sub-navigation” – this can respond to a couple changes in global and local state, like “active” states, tabs, or collapsing navigation.&lt;/li&gt;
&lt;li&gt;On the right side, we’ve got the content that we’d like to show on the screen — in Winds, this is something like an RSS feed or article header, paired with an article list or article contents. &lt;strong&gt;These two sections will be a single React component –&lt;/strong&gt; the props for both components change based on URL navigation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these components interact with global (redux + URL) and local state slightly differently. This view is structured so that we’ve got &lt;strong&gt;three&lt;/strong&gt; React components as siblings:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"grid"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TopNav&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SubNav&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ContentComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But, we want &lt;strong&gt;four&lt;/strong&gt; elements actually rendered to the page:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"topnav"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"subnav"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This...presents kind of a problem without React Fragments. Imagine that we’re creating the component that wraps the two right sections of our 2×2 grid view, the &lt;code&gt;ContentComponent&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ContentComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"header"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we wrap the rendered content in &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s, then we’ll get the following rendered output:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"topnav"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"subnav"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This won’t work –&lt;/strong&gt; it will &lt;em&gt;totally&lt;/em&gt; screw up the CSS grid. From the browser’s point of view, only 3 items are present inside the grid, and one of them doesn’t have a &lt;code&gt;grid-area&lt;/code&gt; style set.&lt;/p&gt;

&lt;p&gt;Remember when we’re supposed to use React Fragments? &lt;strong&gt;Whenever we want to get rid of a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/strong&gt; If we wrap our &lt;code&gt;ContentComponent&lt;/code&gt; in React Fragments instead of a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ContentComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"header"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we’ll see a much different rendered output:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"topnav"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"subnav"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that works exactly as expected! No wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; is rendered, our 4 elements are rendered from 3 React components, the browser sees all elements with the correct &lt;code&gt;grid-area&lt;/code&gt; style, and our CSS Grid is rendered correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Neat! What now?
&lt;/h2&gt;

&lt;p&gt;React Fragments aren’t the most significant feature that’s shown up in React recently, but they are &lt;em&gt;tremendously&lt;/em&gt; helpful in some specific situations. Just by knowing about the existence of React Fragments, you’ll save many hours of google-fu-induced headaches. They let us render an array of elements / components in a JSX-y way, which can solve a lot of layout and styling issues with tables, lists, and CSS grids.&lt;/p&gt;

&lt;p&gt;If you’re interested in seeing some of these React Fragments in a production app, check out the source code for Winds 2.0 over at &lt;a href="https://github.com/GetStream/winds"&gt;https://github.com/GetStream/winds&lt;/a&gt; — or, you can download and use Winds 2.0 over at &lt;a href="https://getstream.io/winds/"&gt;https://getstream.io/winds/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Until next time – cheers!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The post &lt;a href="https://getstream.io/blog/react-fragments/"&gt;React Fragments – the end of the wrapper div&lt;/a&gt; appeared first on &lt;a href="https://getstream.io/blog"&gt;The Stream Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;


</description>
      <category>bestpractices</category>
      <category>tutorial</category>
      <category>react</category>
      <category>tips</category>
    </item>
    <item>
      <title>Winds 2.0: It’s Time to Revive RSS</title>
      <dc:creator>Thierry</dc:creator>
      <pubDate>Tue, 22 May 2018 09:21:07 +0000</pubDate>
      <link>https://forem.com/getstream_io/winds-20-its-time-to-revive-rss-45di</link>
      <guid>https://forem.com/getstream_io/winds-20-its-time-to-revive-rss-45di</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3cciog2g91rsavubom9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3cciog2g91rsavubom9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I love using RSS to follow the programming and tech news I care about. Unfortunately, the number of sites supporting RSS has been in rapid decline over the last few years. The reader ecosystem is slowly degrading as well. Facebook and Twitter’s dominance is now delivering its final blow to the open standard of RSS.&lt;/p&gt;

&lt;p&gt;It’s time to turn the tide. &lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; is releasing &lt;a href="https://getstream.io/winds/" rel="noopener noreferrer"&gt;Winds 2.0&lt;/a&gt;, an open-source Podcast &amp;amp; RSS Reader. You can download Winds &lt;a href="https://getstream.io/winds/" rel="noopener noreferrer"&gt;here&lt;/a&gt; or head over to &lt;a href="https://github.com/getstream/winds" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for the code. (Also, Winds is currently trending on &lt;a href="https://www.producthunt.com/posts/winds-2-0" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhi91ielnwninrhtn5nmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhi91ielnwninrhtn5nmg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many power users of RSS are developers, designers and journalists. Together, we hope to tip the balance and &lt;strong&gt;#ReviveRSS&lt;/strong&gt;. With the help of the community we can build an RSS experience that’s polished, bug free and popular enough to convince publications to improve their support for open standards and RSS.&lt;/p&gt;

&lt;p&gt;Winds is not perfect yet, we’re working on it though and with your help we might just manage to # &lt;strong&gt;ReviveRSS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/getstream/winds" rel="noopener noreferrer"&gt;Star Winds on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Share your feedback on Winds’ features and roadmap on &lt;a href="https://www.producthunt.com/posts/winds-2-0" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bit.ly/winds-tweet" rel="noopener noreferrer"&gt;Tweet about Winds &amp;amp; RSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ask your favorite publications to fix and/or implement RSS support&lt;/li&gt;
&lt;li&gt;Write about Winds and RSS&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/getstream/winds" rel="noopener noreferrer"&gt;Contribute to Winds on Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A huge thank you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/getstream_io/stream--go-news-feeds-for-over-300-million-end-users-605-temp-slug-6856636"&gt;Hackernoon&lt;/a&gt; for sharing this message&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/"&gt;Dev.to&lt;/a&gt; for getting the community involved&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.producthunt.com/" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; for the product feedback&lt;/li&gt;
&lt;li&gt;My colleagues at &lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; for building and sponsoring Winds&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.algolia.com/" rel="noopener noreferrer"&gt;Algolia&lt;/a&gt; for sponsoring Winds&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://mbsy.co/mongodb/228644" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt; for helping with promotion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of a course many thanks to the devrel team at &lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt; for taking what started out as an example app and turning it into such a beautiful polished experience!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getstream.io/winds" rel="noopener noreferrer"&gt;Download Winds&lt;/a&gt; or checkout the code on &lt;a href="https://github.com/getstream/winds" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://getstream.io/blog/winds-2-0-its-time-to-revive-rss/" rel="noopener noreferrer"&gt;Winds 2.0: It’s Time to Revive RSS&lt;/a&gt; appeared first on &lt;a href="https://getstream.io/blog" rel="noopener noreferrer"&gt;The Stream Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>rss</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Stream &amp; Go: News Feeds for Over 300 Million End Users</title>
      <dc:creator>Thierry</dc:creator>
      <pubDate>Mon, 29 Jan 2018 18:56:01 +0000</pubDate>
      <link>https://forem.com/getstream_io/stream--go-news-feeds-for-over-300-million-end-users-55ni</link>
      <guid>https://forem.com/getstream_io/stream--go-news-feeds-for-over-300-million-end-users-55ni</guid>
      <description>

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G60-N0vm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/690/1%2AhlWxQRXVUz4GJysQCV4F9Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G60-N0vm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/690/1%2AhlWxQRXVUz4GJysQCV4F9Q.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getstream.io/"&gt;&lt;strong&gt;Stream&lt;/strong&gt;&lt;/a&gt; is an API that enables developers to build news feeds and activity streams (&lt;a href="https://getstream.io/try-the-api/"&gt;&lt;strong&gt;try the API&lt;/strong&gt;&lt;/a&gt;). We are used by over 500 companies and power the feeds of more than 300 million end users. Companies such as Product Hunt, &lt;a href="https://stackshare.io/under-armour/connected-fitness"&gt;&lt;strong&gt;Under Armour&lt;/strong&gt;&lt;/a&gt;, Powerschool, &lt;a href="https://stackshare.io/bandsintown/bandsintown"&gt;&lt;strong&gt;Bandsintown&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://stackshare.io/dubsmash/dubsmash-scaling-to-200-million-users-with-3-engineers"&gt;&lt;strong&gt;Dubsmash&lt;/strong&gt;&lt;/a&gt;, Compass and Fabric (Google) rely on Stream to power their news feeds. In addition to the API, the founders of Stream also wrote the most widely used &lt;a href="https://github.com/tschellenbach/stream-framework"&gt;&lt;strong&gt;open source solution for building scalable feeds&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what Stream looks like today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of servers: 180&lt;/li&gt;
&lt;li&gt;Feed updates per month: 34 billion&lt;/li&gt;
&lt;li&gt;Average API response time: 12ms&lt;/li&gt;
&lt;li&gt;Average real-time response time: 2ms&lt;/li&gt;
&lt;li&gt;Regions: 4 (US-East, EU-West, Tokyo and Singapore)&lt;/li&gt;
&lt;li&gt;1B API requests per month (~20k/minute)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given that most of our customers are engineers, we often talk about our stack. Here’s a high level overview:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/go"&gt;&lt;strong&gt;Go&lt;/strong&gt;&lt;/a&gt; is our primary programming language.&lt;/li&gt;
&lt;li&gt;We use a custom solution built on top of &lt;a href="https://stackshare.io/rocksdb"&gt;&lt;strong&gt;RocksDB&lt;/strong&gt;&lt;/a&gt; + &lt;a href="https://raft.github.io/"&gt;&lt;strong&gt;Raft&lt;/strong&gt;&lt;/a&gt; for our primary database (we started out on &lt;a href="https://stackshare.io/cassandra"&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;&lt;/a&gt; but wanted more control over performance). &lt;a href="https://stackshare.io/postgresql"&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/a&gt; stores configs, API keys, etc.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/opentracing"&gt;&lt;strong&gt;OpenTracing&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://stackshare.io/jaeger"&gt;&lt;strong&gt;Jaeger&lt;/strong&gt;&lt;/a&gt; handle tracing, &lt;a href="https://stackshare.io/statsd"&gt;&lt;strong&gt;StatsD&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://stackshare.io/grafana"&gt;&lt;strong&gt;Grafana&lt;/strong&gt;&lt;/a&gt; provide detailed monitoring and we use the &lt;a href="https://www.elastic.co/products"&gt;&lt;strong&gt;ELK&lt;/strong&gt;&lt;/a&gt; stack for centralized logging.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/python"&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/a&gt; is our language of choice for machine learning, devops and our website &lt;a href="https://getstream.io/"&gt;&lt;strong&gt;https://getstream.io&lt;/strong&gt;&lt;/a&gt; (&lt;a href="https://stackshare.io/django"&gt;&lt;strong&gt;Django&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://stackshare.io/django-rest-framework"&gt;&lt;strong&gt;DRF&lt;/strong&gt;&lt;/a&gt; &amp;amp; &lt;a href="https://stackshare.io/react"&gt;&lt;strong&gt;React&lt;/strong&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Stream uses a combination of &lt;strong&gt;fanout-on-write&lt;/strong&gt; and &lt;strong&gt;fanout-on-read&lt;/strong&gt;. This results in fast read performance when a users open their feed, as well as fast propagation times when a famous user posts an update.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://twitter.com/tommasobarbugli"&gt;&lt;strong&gt;Tommaso Barguli&lt;/strong&gt;&lt;/a&gt; and I (&lt;a href="https://twitter.com/tschellenbach"&gt;&lt;strong&gt;@tschellenbach&lt;/strong&gt;&lt;/a&gt;) are the developers who started Stream nearly 3 years ago. We founded the company in Amsterdam, participated in Techstars NYC 2015 and opened up our Boulder, Colorado office in 2016. It’s been quite a crazy ride in a fairly short amount of time! With over 15 developers and a host of supporting roles, including sales and marketing, the team feels enormous compared to the early days.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge: News Feeds &amp;amp; Activity Streams
&lt;/h3&gt;

&lt;p&gt;The nature of follow relationships makes it hard to scale feeds. Most of you will remember Facebook’s long load times, Twitter’s fail whale or Tumblr’s year of technical debt. Feeds are hard to scale since there is no clear way to shard the data. Follow relationships connect everyone to everyone else. This makes it difficult to split data across multiple machines. If you want to learn more about this problem, check out these papers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html"&gt;&lt;strong&gt;Twitter’s tech back in the days with 150 million active users&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://engineering.linkedin.com/blog/2016/03/followfeed--linkedin-s-feed-made-faster-and-smarter"&gt;&lt;strong&gt;LinkedIn’s ranked feeds&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jeffterrace.com/docs/feeding-frenzy-sigmod10-web.pdf"&gt;&lt;strong&gt;Yahoo/Princeton research paper&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a very high level there are 3 different ways to scale your feeds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fanout-on-write: basically precompute everything. It’s expensive, but its easy to shard the data.&lt;/li&gt;
&lt;li&gt;Fanout-on-read: hard to scale, but more affordable and new activities show up faster.&lt;/li&gt;
&lt;li&gt;Combination of the above two approaches: better performance and reduced latency, but increased code complexity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stream uses a combination of fanout-on-write and fanout-on-read. This allows us to effectively support both customers with highly connected graphs, as well as customers with a more sparse dataset. This is important since the ways in which our customers use Stream are very different. Have a look at these screenshots from &lt;a href="https://stackshare.io/bandsintown/bandsintown"&gt;&lt;strong&gt;Bandsintown&lt;/strong&gt;&lt;/a&gt;, Unsplash, and &lt;a href="https://stackshare.io/product-hunt/product-hunt"&gt;&lt;strong&gt;Product Hunt&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o6qnIgeC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A0vgRcttdQVBKyzWfwNtSgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o6qnIgeC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A0vgRcttdQVBKyzWfwNtSgg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching from &lt;a href="https://stackshare.io/python"&gt;Python&lt;/a&gt; to &lt;a href="https://stackshare.io/go"&gt;Go&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;After years of optimizing our existing feed technology we decided to make a larger leap with 2.0 of Stream. While the first iteration of Stream was powered by Python and Cassandra, for Stream 2.0 of our infrastructure we &lt;a href="https://getstream.io/blog/switched-python-go/"&gt;&lt;strong&gt;switched to Go&lt;/strong&gt;&lt;/a&gt;. The main reason why we switched from Python to Go is performance. Certain features of Stream such as aggregation, ranking and serialization were very difficult to speed up using Python.&lt;/p&gt;

&lt;p&gt;We’ve been using Go since March 2017 and it’s been a great experience so far. Go has greatly increased the productivity of our development team. Not only has it improved the speed at which we develop, it’s also 30x faster for many components of Stream.&lt;/p&gt;

&lt;p&gt;The performance of Go greatly influenced our architecture in a positive way. With Python we often found ourselves delegating logic to the database layer purely for performance reasons. The high performance of Go gave us more flexibility in terms of architecture. This led to a huge simplification of our infrastructure and a dramatic improvement of latency. For instance, we saw a 10 to 1 reduction in web-server count thanks to the lower memory and CPU usage for the same number of requests.&lt;/p&gt;

&lt;p&gt;Initially we struggled a bit with package management for Go. However, using &lt;a href="https://github.com/golang/dep"&gt;&lt;strong&gt;Dep&lt;/strong&gt;&lt;/a&gt; together with the &lt;a href="https://github.com/getstream/vg"&gt;&lt;strong&gt;VG package&lt;/strong&gt;&lt;/a&gt; contributed to creating a great workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tj9G88sY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/434/1%2A3YtBsG5iw6brMTHvPA4ztQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tj9G88sY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/434/1%2A3YtBsG5iw6brMTHvPA4ztQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’ve never tried Go, you’ll want to try this online tour: &lt;a href="https://tour.golang.org/welcome/1"&gt;&lt;strong&gt;https://tour.golang.org/welcome/1&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go as a language is heavily focused on performance. The built-in &lt;a href="https://golang.org/pkg/net/http/pprof/"&gt;&lt;strong&gt;PPROF&lt;/strong&gt;&lt;/a&gt; tool is amazing for finding performance issues. Uber’s &lt;a href="https://github.com/uber/go-torch"&gt;&lt;strong&gt;Go-Torch&lt;/strong&gt;&lt;/a&gt; library is great for visualizing data from PPROF and will be bundled in PPROF in Go 1.10.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dYuw-FAv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1000/1%2AuCWv4L8tYxlUsBjLPz2_Fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dYuw-FAv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1000/1%2AuCWv4L8tYxlUsBjLPz2_Fw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching from Cassandra to &lt;a href="https://stackshare.io/rocksdb"&gt;RocksDB&lt;/a&gt; &amp;amp; Raft
&lt;/h3&gt;

&lt;p&gt;1.0 of Stream leveraged &lt;a href="https://stackshare.io/cassandra"&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;&lt;/a&gt; for storing the feed. Cassandra is a common choice for building feeds. Instagram, for instance started, out with &lt;a href="https://stackshare.io/redis"&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/a&gt; but eventually &lt;a href="https://www.datastax.com/dev/blog/facebooks-instagram-making-the-switch-to-cassandra-from-redis-a-75-insta-savings"&gt;&lt;strong&gt;switched to Cassandra&lt;/strong&gt;&lt;/a&gt; to handle their rapid usage growth. Cassandra can handle write heavy workloads very efficiently.&lt;/p&gt;

&lt;p&gt;Cassandra is a great tool that allows you to scale write capacity simply by adding more nodes, though it is also very complex. This complexity made it hard to diagnose performance fluctuations. Even though we had years of experience with running Cassandra, it still felt like a bit of a black box. When building Stream 2.0 we decided to go for a different approach and build &lt;strong&gt;Keevo&lt;/strong&gt;. Keevo is our in-house key-value store built upon RocksDB, gRPC and Raft.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackshare.io/rocksdb"&gt;&lt;strong&gt;RocksDB&lt;/strong&gt;&lt;/a&gt; is a highly performant embeddable database library developed and maintained by Facebook’s data engineering team. RocksDB started as a fork of Google’s LevelDB that introduced several performance improvements for SSD. Nowadays RocksDB is a project on its own and is under active development. It is written in C++ and it’s fast. Have a look at how this &lt;a href="https://github.com/facebook/rocksdb/wiki/RocksDB-In-Memory-Workload-Performance-Benchmarks"&gt;&lt;strong&gt;benchmark handles 7 million QPS&lt;/strong&gt;&lt;/a&gt;. In terms of technology it’s much more simple than Cassandra. This translates into reduced maintenance overhead, improved performance and, most importantly, more consistent performance. It’s interesting to note that &lt;a href="https://stackshare.io/linkedin/linkedin"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; also uses RocksDB for &lt;a href="https://engineering.linkedin.com/blog/2016/03/followfeed--linkedin-s-feed-made-faster-and-smarter"&gt;&lt;strong&gt;their feed&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our infrastructure is hosted on &lt;a href="https://stackshare.io/amazon-ec2"&gt;&lt;strong&gt;AWS&lt;/strong&gt;&lt;/a&gt; and is designed to survive entire availability zone outages. Unlike Cassandra, Keevo clusters organizes nodes into leaders and followers . When a leader (master) node becomes unavailable the other nodes in the same deployment will start an election and pick a new leader. Electing a new leader is a fast operation and barely impacts live traffic.&lt;/p&gt;

&lt;p&gt;To do this, Keevo implements the Raft consensus algorithm using &lt;a href="https://github.com/hashicorp/raft"&gt;&lt;strong&gt;Hashicorp’s Go implementation&lt;/strong&gt;&lt;/a&gt;. This ensures that every bit stored in Keevo is stored on 3 different servers and operations are always consistent. This site does a great job of visualizing how Raft works: &lt;a href="https://raft.github.io/"&gt;&lt;strong&gt;https://raft.github.io/&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B7QtcpQV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/965/1%2Al3C6o4EqveWRd5KImjf5gA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B7QtcpQV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/965/1%2Al3C6o4EqveWRd5KImjf5gA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Not Quite Microservices
&lt;/h3&gt;

&lt;p&gt;By leveraging Go and RocksDB we’re able to achieve great feed performance. The average response time is around 12ms. The architecture lies somewhere between a monolith and a microservice. Stream runs on the following 7 services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/stream/stream-api"&gt;&lt;strong&gt;Stream API&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/stream/keevo"&gt;&lt;strong&gt;Keevo&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/stream/realtime"&gt;&lt;strong&gt;Real time &amp;amp; Firehose&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/stream/analytics"&gt;&lt;strong&gt;Analytics&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/stream/machine-learning-and-personalization"&gt;&lt;strong&gt;Personalization &amp;amp; Machine learning&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/stream/site-and-dashboard"&gt;&lt;strong&gt;Site &amp;amp; Dashboard&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Async Workers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To see all our services divided into stacks, head over &lt;a href="https://stackshare.io/stream/stacks"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Personalization &amp;amp; Machine Learning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Almost all large apps with feeds use machine learning and personalization. For instance, LinkedIn prioritizes the items in your feed. Instagram’s explore feed displays pictures outside of the people you follow that you might be interested in. Etsy uses a similar approach to optimize ecommerce conversion. Stream supports the following 5 use cases for personalization:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RthVxgQN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/786/1%2A0XAcnQgsD_f-JNAoll-_4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RthVxgQN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/786/1%2A0XAcnQgsD_f-JNAoll-_4w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getstream.io/docs_personalization/"&gt;&lt;strong&gt;Documentation for building personalized feeds.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of these personalization use cases rely on combining feeds with analytics and machine learning. For the machine learning side we generate the models using &lt;a href="https://stackshare.io/python"&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/a&gt;. The models are different for each of our enterprise customers. Typically we’ll use one of these amazing libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/lyst/lightfm"&gt;&lt;strong&gt;LightFM&lt;/strong&gt;&lt;/a&gt; — &lt;a href="https://www.infoworld.com/article/3241852/machine-learning/how-to-implement-a-recommender-system.html"&gt;&lt;strong&gt;How to implement recommender systems&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dmlc/xgboost"&gt;&lt;strong&gt;XGBoost&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/scikit-learn"&gt;&lt;strong&gt;Scikit learn&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/numpy"&gt;&lt;strong&gt;Numpy&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://stackshare.io/pandas"&gt;&lt;strong&gt;Pandas&lt;/strong&gt;&lt;/a&gt; and Dask&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/jupyter"&gt;&lt;strong&gt;Jupyter Notebook&lt;/strong&gt;&lt;/a&gt; (For development)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/projectmesa/mesa"&gt;&lt;strong&gt;Mesa Framework&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Analytics data is collected using a tiny Go-based server. In the background, it will spawn go-routines to rollup the data as needed. The resulting metrics are stored in &lt;a href="https://stackshare.io/elasticsearch"&gt;&lt;strong&gt;Elastic&lt;/strong&gt;&lt;/a&gt;. In the past, we looked at &lt;a href="https://stackshare.io/druid"&gt;&lt;strong&gt;Druid&lt;/strong&gt;&lt;/a&gt;, which seems like a solid project. For now, we could get away with a simpler solution though.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dashboard &amp;amp; Site&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The dashboard is powered by &lt;a href="https://stackshare.io/react"&gt;&lt;strong&gt;React&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://stackshare.io/reduxjs"&gt;&lt;strong&gt;Redux&lt;/strong&gt;&lt;/a&gt;. We also use React and Redux for all of our example applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://cabin.getstream.io/"&gt;&lt;strong&gt;Cabin: A tutorial series on building a social network with React &amp;amp; Redux&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://github.com/getstream/winds"&gt;&lt;strong&gt;Winds: Open source RSS &amp;amp; Podcast app&lt;/strong&gt;&lt;/a&gt; (Winds 2.0 is coming out very soon)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The site, as well as the API for the site, is powered by &lt;a href="https://stackshare.io/python"&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://stackshare.io/django"&gt;&lt;strong&gt;Django&lt;/strong&gt;&lt;/a&gt; and &lt;a href="http://www.django-rest-framework.org/"&gt;&lt;strong&gt;Django Rest Framework&lt;/strong&gt;&lt;/a&gt;. Stream is sponsoring Django Rest Framework since it’s a pretty great open source project. If you need to build an API quickly there is no better tool than DRF and Python.&lt;/p&gt;

&lt;p&gt;We use &lt;a href="https://stackshare.io/imgix"&gt;&lt;strong&gt;Imgix&lt;/strong&gt;&lt;/a&gt; to resize the images on our site. For us, Imgix is cost efficient, fast and overall a great service. &lt;a href="https://github.com/thumbor/thumbor"&gt;&lt;strong&gt;Thumbor&lt;/strong&gt;&lt;/a&gt; is a good open source alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our real time infrastructure is based on Go, Redis and the excellent &lt;a href="https://github.com/gorilla/websocket"&gt;&lt;strong&gt;gorilla websocket&lt;/strong&gt;&lt;/a&gt; library. It implements the Bayeux protocol. In terms of architecture it’s very similar to the node based &lt;a href="https://stackshare.io/faye"&gt;&lt;strong&gt;Faye&lt;/strong&gt;&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;It was interesting to read the “&lt;a href="https://news.ycombinator.com/item?id=15766011"&gt;&lt;strong&gt;Ditching Go for Node.js&lt;/strong&gt;&lt;/a&gt;” post on Hacker News. The author moves from Go to Node to improve performance. We actually did the exact opposite and moved from Node to Go for our real time system. The new Go-based infrastructure handles 8x the traffic per node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Devops, Testing &amp;amp; Multiple Regions
&lt;/h3&gt;

&lt;p&gt;In terms of devops the provisioning and configuration of instances is fully automated using a combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/aws-cloudformation"&gt;&lt;strong&gt;CloudFormation&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cloud-Init&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/puppet"&gt;&lt;strong&gt;Puppet&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Boto &amp;amp; &lt;a href="https://stackshare.io/fabric"&gt;&lt;strong&gt;Fabric&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because our infrastructure is defined in code it has become trivial to launch new regions. We heavily use &lt;a href="https://stackshare.io/aws-cloudformation"&gt;&lt;strong&gt;CloudFormation&lt;/strong&gt;&lt;/a&gt;. Every single piece of our stack is defined in a CloudFormation template. If needed we are able to spawn a new dedicated shard in a few minutes. In addition, AWS Parameter Store is used to hold application settings. Our largest deployment is in US-East, but we also have regions in Tokyo, Singapore and Dublin.&lt;/p&gt;

&lt;p&gt;A combination of Puppet and Cloud-init is used to configure our instances. We run our self-contained Go’s binaries directly on the EC2 instance without any additional containerization layer.&lt;/p&gt;

&lt;p&gt;Releasing new versions of our services is done by &lt;a href="https://stackshare.io/travis-ci"&gt;&lt;strong&gt;Travis&lt;/strong&gt;&lt;/a&gt;. Travis first runs our test suite. Once it passes, it publishes a new release binary to &lt;a href="https://stackshare.io/github"&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/a&gt;. Common tasks such as installing dependencies for the Go project, or building a binary are automated using plain old Makefiles. (We know, crazy old school, right?) Our binaries are compressed using UPX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool highlight:&lt;/strong&gt; &lt;a href="https://stackshare.io/travis-ci"&gt;&lt;strong&gt;Travis&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://stackshare.io/travis-ci"&gt;&lt;strong&gt;Travis&lt;/strong&gt;&lt;/a&gt; has come a long way over the past years. I used to prefer &lt;a href="https://stackshare.io/jenkins"&gt;&lt;strong&gt;Jenkins&lt;/strong&gt;&lt;/a&gt; in some cases since it was easier to debug broken builds. With the addition of the aptly named “debug build” button, Travis is now the clear winner. It’s easy to use and free for open source, with no need to maintain anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LlrgH-VK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/888/1%2Ah7BP-v2TyRosk8_LvWTEWQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LlrgH-VK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/888/1%2Ah7BP-v2TyRosk8_LvWTEWQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we use &lt;a href="https://stackshare.io/fabric"&gt;&lt;strong&gt;Fabric&lt;/strong&gt;&lt;/a&gt; to do a rolling deploy to our AWS instances. If anything goes wrong during the deploy it will halt the deploy. We take stability very seriously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A high level of test coverage is required.&lt;/li&gt;
&lt;li&gt;Releases are created by Travis (making it hard to deploy without running tests).&lt;/li&gt;
&lt;li&gt;Code is reviewed by at least 2 team members.&lt;/li&gt;
&lt;li&gt;Our extensive QA integration test suite evaluates if all 7 components still work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ve written about our experience with &lt;a href="https://getstream.io/blog/how-we-test-go-at-stream/"&gt;&lt;strong&gt;testing our Go codebase&lt;/strong&gt;&lt;/a&gt;. When things do break we do our best to be transparent about the ongoing issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackshare.io/statuspage-io"&gt;&lt;strong&gt;StatusPage&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/twilio"&gt;&lt;strong&gt;Twilio&lt;/strong&gt;&lt;/a&gt; for 24/7 phone support&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/victorops"&gt;&lt;strong&gt;VictorOps&lt;/strong&gt;&lt;/a&gt; for notifying our team&lt;/li&gt;
&lt;li&gt;#firefighting channel on &lt;a href="https://stackshare.io/slack"&gt;&lt;strong&gt;Slack&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/intercom"&gt;&lt;strong&gt;Intercom&lt;/strong&gt;&lt;/a&gt; for customer support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VictorOps is a recent addition to our support stack. It’s made it very easy to collaborate on ongoing issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool Highlight:&lt;/strong&gt; &lt;a href="https://stackshare.io/victorops"&gt;&lt;strong&gt;VictorOps&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best part about &lt;a href="https://stackshare.io/victorops"&gt;&lt;strong&gt;VictorOps&lt;/strong&gt;&lt;/a&gt; is how they use a timeline to collaborate amongst team members. VictorOps is an elegant way to keep our team in the loop about outages. It also integrates well with &lt;a href="https://stackshare.io/slack"&gt;&lt;strong&gt;Slack&lt;/strong&gt;&lt;/a&gt;. This setup enables us to quickly react to any problems that make it into production, work together and resolve them faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6BmLYeer--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/430/1%2AJxfmNSyUsFHmKMZLZJmINQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6BmLYeer--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/430/1%2AJxfmNSyUsFHmKMZLZJmINQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The vast majority of our infrastructure runs on AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/aws-elastic-load-balancing"&gt;&lt;strong&gt;ELB&lt;/strong&gt;&lt;/a&gt; for load balancing&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/amazon-rds-for-postgresql"&gt;&lt;strong&gt;RDS&lt;/strong&gt;&lt;/a&gt; for reliable Postgres hosting&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/amazon-elasticache"&gt;&lt;strong&gt;ElastiCache&lt;/strong&gt;&lt;/a&gt; for Redis hosting&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/amazon-route-53"&gt;&lt;strong&gt;Route53&lt;/strong&gt;&lt;/a&gt; for our DNS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/amazon-cloudfront"&gt;&lt;strong&gt;Cloudfront&lt;/strong&gt;&lt;/a&gt; for our CDN&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackshare.io/amazon-elasticsearch-service"&gt;&lt;strong&gt;AWS ElasticSearch&lt;/strong&gt;&lt;/a&gt; for ELK and tracing with &lt;a href="https://stackshare.io/jaeger"&gt;&lt;strong&gt;Jaeger&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The devops responsibilities are shared across our team. While we do have one dedicated devops engineer, all our developers have to understand and own the entire workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stream uses &lt;a href="https://stackshare.io/opentracing"&gt;&lt;strong&gt;OpenTracing&lt;/strong&gt;&lt;/a&gt; for tracing and &lt;a href="https://stackshare.io/grafana"&gt;&lt;strong&gt;Grafana&lt;/strong&gt;&lt;/a&gt; for beautiful dashboards. The tracking for Grafana is done using &lt;a href="https://stackshare.io/statsd"&gt;&lt;strong&gt;StatsD&lt;/strong&gt;&lt;/a&gt;. The end result is this beauty:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bw54zYDp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AFLDN9Kgu-A7EwtFMQlckkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bw54zYDp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AFLDN9Kgu-A7EwtFMQlckkg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We track our errors in &lt;a href="https://stackshare.io/sentry"&gt;&lt;strong&gt;Sentry&lt;/strong&gt;&lt;/a&gt; and use the ELK stack to centralize our logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool Highlight:&lt;/strong&gt; &lt;a href="https://stackshare.io/opentracing"&gt;&lt;strong&gt;OpenTracing&lt;/strong&gt;&lt;/a&gt; *&lt;em&gt;+ *&lt;/em&gt; &lt;a href="https://stackshare.io/jaegar"&gt;&lt;strong&gt;Jaegar&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One new addition to the stack is &lt;a href="https://stackshare.io/opentracing"&gt;&lt;strong&gt;OpenTracing&lt;/strong&gt;&lt;/a&gt;. In the past we used &lt;a href="https://stackshare.io/new-relic"&gt;&lt;strong&gt;New Relic&lt;/strong&gt;&lt;/a&gt;, which works like a charm for Python, but isn’t able to automatically measure tracing information for Go. OpenTracing with &lt;a href="https://stackshare.io/jaeger"&gt;&lt;strong&gt;Jaeger&lt;/strong&gt;&lt;/a&gt; is a great solution that works very well for Stream. It also has, perhaps, the best logo for a tracing solution:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rMrPC-M3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/484/1%2AEKEsybT_RuPyfpm3CYA8lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rMrPC-M3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/484/1%2AEKEsybT_RuPyfpm3CYA8lw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing Thoughts
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://stackshare.io/go"&gt;&lt;strong&gt;Go&lt;/strong&gt;&lt;/a&gt; is an absolutely amazing language and has been a major win in terms of performance and developer productivity. For tracing we use OpenTracing and Jaeger. Our monitoring is running on StatsD and Graphite. Centralized logging is handled by the ELK stack.&lt;/p&gt;

&lt;p&gt;Stream’s main database is a custom solution built on top of &lt;a href="https://stackshare.io/rocksdb"&gt;&lt;strong&gt;RocksDB&lt;/strong&gt;&lt;/a&gt; and Raft. In the past we used Cassandra, which we found hard to maintain and which didn’t give us enough control over performance when compared to RocksDB.&lt;/p&gt;

&lt;p&gt;We leverage external tools and solutions for everything that’s not a core competence. &lt;a href="https://stackshare.io/redis"&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/a&gt; hosting is handled by ElastiCache, Postgres by RDS, email by &lt;a href="https://stackshare.io/mailgun"&gt;&lt;strong&gt;Mailgun&lt;/strong&gt;&lt;/a&gt;, test builds by Travis and error reporting by Sentry.&lt;/p&gt;

&lt;p&gt;Thank you for reading about our stack! If you’re a user of Stream, please be sure to add &lt;a href="https://stackshare.io/stream"&gt;&lt;strong&gt;Stream&lt;/strong&gt;&lt;/a&gt; to your stack on StackShare. If you’re a talented individual, &lt;a href="https://stackshare.io/stream/stacks#jobs"&gt;&lt;strong&gt;come work with us&lt;/strong&gt;&lt;/a&gt;! And finally, if you haven’t tried out Stream yet, take a look at this quick &lt;a href="https://getstream.io/try-the-api/"&gt;&lt;strong&gt;tutorial for the API&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally written by Thierry Schellenbach, CEO at&lt;/em&gt; &lt;a href="https://getstream.io"&gt;&lt;em&gt;GetStream.io&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. The original post can be found at&lt;/em&gt; &lt;a href="https://stackshare.io/stream/stream-and-go-news-feeds-for-over-300-million-end-users"&gt;&lt;em&gt;https://stackshare.io/stream/stream-and-go-news-feeds-for-over-300-million-end-users&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;





</description>
      <category>go</category>
      <category>django</category>
      <category>python</category>
      <category>cloudcomputing</category>
    </item>
  </channel>
</rss>
