<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nic</title>
    <description>The latest articles on DEV Community by Nic (@snj).</description>
    <link>https://dev.to/snj</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F232021%2Fbc9a9436-b2e5-425b-a52a-30f9bf4f69fe.jpg</url>
      <title>DEV Community: Nic</title>
      <link>https://dev.to/snj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/snj"/>
    <language>en</language>
    <item>
      <title>My Favorite Tech Blogs</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Thu, 30 Dec 2021 00:09:30 +0000</pubDate>
      <link>https://dev.to/snj/my-favorite-tech-blogs-2ml5</link>
      <guid>https://dev.to/snj/my-favorite-tech-blogs-2ml5</guid>
      <description>&lt;p&gt;Hope you’re all enjoying your holidays!&lt;/p&gt;

&lt;p&gt;Today I want to share some of my favorites tech blogs. I have followed these sites for many years, and I think they are worth your time.&lt;/p&gt;

&lt;p&gt;The criteria I recommend are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Continuous updates for many years&lt;/li&gt;
&lt;li&gt;High quality and some articles have inspired me deeply&lt;/li&gt;
&lt;/ol&gt;




&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.joelonsoftware.com/"&gt;Joel on Software&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://www.paulgraham.com/articles.html"&gt;Paul Graham&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eli.thegreenplace.net/"&gt;Eli Bendersky’s website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I remember I found this blog when I tried to finish all the SICP exercises in 2008. There are almost all the answers to SICP exercises with detailed explanations!&lt;/p&gt;

&lt;p&gt;What is commendable is that the author Eli Bendersky has always insisted on writing his technical experience, and this blog is continuously updated. The quality of the content is very high, with both theory and code. For instance, he wrote the Raft series: &lt;a href="https://eli.thegreenplace.net/2020/implementing-raft-part-0-introduction/"&gt;Implementing Raft: Part 0-Introduction&lt;/a&gt;, which is simply a model of technical writing.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://flaviocopes.com/"&gt;Flavio Copes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog is maintained by an Italian developer, and the content is mostly on front-end and web development.&lt;/p&gt;

&lt;p&gt;I admire this blog because he keeps blogging almost every day! What he wrote may not be in depth, but it is useful to many people. I used SEO tools to read the data of this website, and the organic traffic brought by Google is very high.&lt;/p&gt;

&lt;p&gt;I recommend everyone who want to start with writing to read these two articles:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flaviocopes.com/developer-blog/"&gt;Every developer should have a blog. Here’s why, and how to stick with it&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flaviocopes.com/blog-seo/"&gt;I wrote 1 blog post every day for 2 years. Here’s 5 things I learned about SEO&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jvns.ca/"&gt;Julia Evans&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog covering a wide range of fields. This author deeply inspired me to learn programming by understanding internal principles: &lt;a href="https://jvns.ca/blog/learn-how-things-work/"&gt;Get better at programming by learning how things work&lt;/a&gt; . Of course there are many other technical articles such as: &lt;a href="https://jvns.ca/blog/2014/12/14/fun-with-threads/"&gt;Diving into concurrency: trying out mutexes and atomics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the author has made a lot of fancy e-books: &lt;a href="https://wizardzines.com/"&gt;wizard zines&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="http://journal.stuffwithstuff.com/"&gt;journal.stuffwithstuff.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He wrote a book on programming language implementation in 6 years, with the spirit of craftsmanship: &lt;a href="http://journal.stuffwithstuff.com/2020/04/05/crafting-crafting-interpreters/"&gt;Crafting “Crafting Interpreters”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the pictures here are drawn by hand, all details on font, color, alignment, etc., all these details are almost perfect, and the final book is an artwork. A technical book can be so beautiful!&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.swyx.io/"&gt;swyx’s site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The content involves development, personal growth, etc.&lt;br&gt;&lt;br&gt;
Among them, the concept of &lt;a href="https://www.swyx.io/learn-in-public/"&gt;Learn In Public (swyx.io)&lt;/a&gt; touched me a lot, and there are many awesome podcasts on this blog.&lt;/p&gt;




&lt;p&gt;That all for today, if you like it please tell me, I actually have more to share with you. 🙌&lt;/p&gt;

&lt;p&gt;See you!&lt;/p&gt;

</description>
      <category>blog</category>
      <category>writing</category>
    </item>
    <item>
      <title>How to Keep A Program Running with Ssh logout</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Thu, 25 Nov 2021 15:08:01 +0000</pubDate>
      <link>https://dev.to/snj/how-to-keep-a-program-running-with-ssh-logout-36e7</link>
      <guid>https://dev.to/snj/how-to-keep-a-program-running-with-ssh-logout-36e7</guid>
      <description>&lt;p&gt;Some times we need to keep jobs running without a &lt;code&gt;ssh&lt;/code&gt; session, here there are three ways to achieve this. I suggest to learn a terminal multiplexer in long term, it’s really useful when you have long time working on Linux/Unix system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1: &lt;code&gt;nohup&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The best and simplest way is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nohup long-running-command &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was made specifically for this, by default it will log stdout to &lt;code&gt;nohup.log&lt;/code&gt;, if standard output is not a terminal, logs will be appended to &lt;code&gt;~/nohup.log&lt;/code&gt;. If you want to specify the output log into a different file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nohup COMMAND &amp;gt; FILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More details can refer to &lt;code&gt;man nohup&lt;/code&gt;. What &lt;code&gt;nohup&lt;/code&gt; does, is to effectively separate the process from the terminal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It closes standard input (the program will &lt;em&gt;not&lt;/em&gt; be able to read any input, even if it is run in the foreground. it is not halted, but will receive an error code or &lt;code&gt;EOF&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;It redirects standard output and standard error to the file &lt;code&gt;nohup.out&lt;/code&gt;, so the program won’t fail for writing to standard output if the terminal fails, so whatever the process writes is not lost.&lt;/li&gt;
&lt;li&gt;It prevents the process from receiving a &lt;code&gt;SIGHUP&lt;/code&gt; (thus the name).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Option 2: &lt;code&gt;bg&lt;/code&gt; + &lt;code&gt;disown&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you already have started the program and don’t want restart it, we can use &lt;code&gt;ctrl+z&lt;/code&gt; to stop current execution and then use &lt;code&gt;bg&lt;/code&gt; to resume it and switch the running program to background (We can use &lt;code&gt;fg&lt;/code&gt; to pull the job to frontground)&lt;/p&gt;

&lt;p&gt;Finally we use &lt;code&gt;disown&lt;/code&gt; to remove the process from the shell’s job control.&lt;/p&gt;

&lt;p&gt;So, even you logout from a &lt;code&gt;ssh&lt;/code&gt; session, the program will still keep running in background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ctrl+zbgdisown -h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Option 3: Use terminal multiplexer
&lt;/h2&gt;

&lt;p&gt;We have three choices for this, [[screen]], [[tmux]], and [[byobu]].&lt;/p&gt;

&lt;p&gt;&lt;code&gt;screen&lt;/code&gt; and &lt;code&gt;tmux&lt;/code&gt; is mostly used ones. On Ubuntu or Debian system, we install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install screen sudo apt-get install tmux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.byobu.org/"&gt;Byobu&lt;/a&gt; is an enhancement for the GNU Screen, you can install it with this commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo add-apt-repository ppa:byobu/ppasudo apt-get updatesudo apt-get install byobu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tools</category>
      <category>linux</category>
    </item>
    <item>
      <title>Rust Warp: Use Cookie for Authorization</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Wed, 24 Nov 2021 13:11:48 +0000</pubDate>
      <link>https://dev.to/snj/rust-warp-use-cookie-for-authorization-2gk7</link>
      <guid>https://dev.to/snj/rust-warp-use-cookie-for-authorization-2gk7</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/seanmonstar/warp"&gt;Warp&lt;/a&gt; is a composable, web server in Rust. It's code is very small and focus on speed.&lt;/p&gt;

&lt;p&gt;The fundamental building block of &lt;code&gt;warp&lt;/code&gt; is the &lt;code&gt;Filter&lt;/code&gt;, they can be combined and composed to express rich requirements on requests.&lt;/p&gt;

&lt;p&gt;But it's actually not easy to use if you are not familiar with it's concept, and the type system will also scare some beginners.&lt;/p&gt;

&lt;p&gt;For example, I actually spend some time to figure out how to use Cookie for authorization. &lt;/p&gt;

&lt;p&gt;Suppose we have defined a Struct to represent the User:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;And we have a logic to authorize whether the login request has a valid username and password, the detail implementation depends on your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The question is how to set a Cookie in response and how to verify each request after authorization. &lt;/p&gt;

&lt;h3&gt;
  
  
  Set a cookie
&lt;/h3&gt;

&lt;p&gt;When a user send login request and passed the authorization, we use &lt;code&gt;reply&lt;/code&gt; with &lt;code&gt;with_header&lt;/code&gt; to set a cookie to store a token, which will be used for later requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;path!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;body&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nn"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;verify_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;gen_token&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="s"&gt;"set-cookie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"token={}; Path=/; HttpOnly; Max-Age=1209600"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.into_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.into_response&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;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="nf"&gt;.or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use cookie for Authorization
&lt;/h3&gt;

&lt;p&gt;To authorize request, we need to implement a &lt;code&gt;filter&lt;/code&gt; in Warp, and use it like this, here we use &lt;code&gt;Filter::untuple_one&lt;/code&gt; to unroll nested tuple layers from extractions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;verify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;path!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s"&gt;"verify"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;auth_validation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.untuple_one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.into_response&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="nf"&gt;.or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the &lt;code&gt;auth_validation&lt;/code&gt; will call another built-in filter &lt;code&gt;warp::cookie&lt;/code&gt; to extract the &lt;code&gt;token&lt;/code&gt; from request header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Unauthorized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nn"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Reject&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Unauthorized&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;auth_validation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Extract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((),),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Rejection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Copy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.and_then&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"token: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;verify_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;warp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Unauthorized&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;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Some thoughts
&lt;/h3&gt;

&lt;p&gt;Even I have spent some time writing code in Rust, I still need to learn some new concepts or some details in a Web framework such as Warp. From my experience, there are some unnatural part for users who used to some other programming languages. For example, the return type of a filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Extract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((),),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Rejection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Copy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's just not so easy to say what this mean? And why we need to call &lt;code&gt;untuple_one&lt;/code&gt; with the filter? &lt;/p&gt;

&lt;p&gt;I know we must obey the rules of type system, and we need to add more annotations when writing Rust code, it's just not so easy for learning as other programming languages. &lt;/p&gt;

&lt;p&gt;Even so, I'm still having fun with it for it bringing some new things for programming.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>warp</category>
    </item>
    <item>
      <title>The Best Way To Learn Frontend As An Experienced Programmer</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Tue, 23 Nov 2021 15:33:36 +0000</pubDate>
      <link>https://dev.to/snj/the-best-way-to-learn-frontend-as-an-experienced-programmer-1pp0</link>
      <guid>https://dev.to/snj/the-best-way-to-learn-frontend-as-an-experienced-programmer-1pp0</guid>
      <description>&lt;p&gt;I have done some front-end programming recently. Even I have been coding for almost 16 years, I haven’t done much on the front-end in my coding time.&lt;/p&gt;

&lt;p&gt;The reason is, I never found Front-end programming interesting. I thought front-end is only manipulate the HTML elements, and provides some styles for the UI of web. I found CSS is trivial and there is not logic behind the css code. We must remember a lot of stuff to write CSS. I don’t want to remember …&lt;/p&gt;

&lt;p&gt;Until recently, I have done more work in front-end. My career don’t involve front-end much , but I have spent some time to learn it by myself. The motivation behind it is my side-project.&lt;/p&gt;

&lt;p&gt;I finished several projects in my spare time, and got more interests on it. Here are some of my projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/chenyukang/gomoku"&gt;gomoku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/chenyukang/obweb"&gt;obweb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, with about one year experiences of practice, I improved much on it. I found these rules for learning front-end as an experienced programmer. It also may help for beginners:&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn by doing
&lt;/h3&gt;

&lt;p&gt;This is always my #1 role of learning programming.&lt;/p&gt;

&lt;p&gt;I guess I still won’t have learned frontend programming without my side-project. I have some desire on my side-project, I tried to finish it with perfection in my mind.&lt;/p&gt;

&lt;p&gt;Learning frontend is the extra credits of finishing my projects. So, if you don’t have much desire on learning frontend(or programming), maybe you need to find some thing which interested you, try to find those things attract you desire. For instance, if you want to develop a game, you may need to learn Game programming or something like C++ programming.&lt;/p&gt;

&lt;p&gt;When you begin to get hands dirty with your keyboard, other things will follow.&lt;/p&gt;

&lt;p&gt;If you don’t find any good project to start with, here are some learn-by-doing style of courses:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.freecodecamp.org/learn"&gt;Learn to Code (freecodecamp.org)&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Play with open-source projects
&lt;/h3&gt;

&lt;p&gt;It’s the best time for learning programming right now. Compared with 10 years ago, we have many many open-source projects to learn.&lt;/p&gt;

&lt;p&gt;As as a beginner in front-end, I get much fun and interests when I played all the demo of this project: &lt;a href="https://github.com/bradtraversy/vanillawebprojects"&gt;Mini projects built with HTML5, CSS &amp;amp; JavaScript.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I read the source code of each sub-project, and try to do some modification on them. After finish it, I learned a lot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read Books, Ignore Videos
&lt;/h3&gt;

&lt;p&gt;When you want to go deeper about front-end, there are actually a lot of theory stuff need to learn. For these essential knowledge, I would suggest you to learn by reading some classic books, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://javascript.info/"&gt;The Modern JavaScript Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3nGQB2j"&gt;JavaScript: The Definitive Guide: Activate Your Web Pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many videos for learning Web development, it’s only helpful when you are starting without any experience. If you have got some learning experience, you should step out relay on watching those videos. Because almost none of them will teach you deeper skills and knowledges. Classic books and other authoritative materials will be helpful.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>The Great Programming Quotes </title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Sat, 10 Jul 2021 06:11:37 +0000</pubDate>
      <link>https://dev.to/snj/the-great-programming-quotes-2lp6</link>
      <guid>https://dev.to/snj/the-great-programming-quotes-2lp6</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T3rudBDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/kimberly-farmer-lUaaKCUANVI-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T3rudBDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/kimberly-farmer-lUaaKCUANVI-unsplash.jpg" alt="kimberly-farmer @ unsplash.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Several days ago, I came across &lt;a href="https://twitter.com/id_aa_carmack/status/1047504598527856642?lang=en"&gt;John Carmack’s post&lt;/a&gt; on learning programming. His advice is truly helpful for programming beginners and worth more reading.&lt;br&gt;&lt;br&gt;
This reminds me to spread other great quotes in mind, which from great programmers and computer scientist.&lt;/p&gt;

&lt;p&gt;Some of them help me understanding more on computing, some of them are principles I’m trying to apply to my daily work, and some of them are funny.&lt;/p&gt;

&lt;h1&gt;
  
  
  Design and architecture
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Abstraction is essential
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Complexity is anything that makes software hard to understand or to modify.&lt;br&gt;&lt;br&gt;
-–John Ousterhout&lt;/p&gt;

&lt;p&gt;“All problems in computer science can be solved by another level of indirection”&lt;br&gt;&lt;br&gt;
– David Wheeler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The power of these can be seen in the domains of software development, design patterns, architecture and hardware design. The computing world is a combination of different abstraction layers, operating system, networking model, distribution system and graphic libraries are all abstractions, in different levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep simple and changeable
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Simplicity is prerequisite for reliability&lt;br&gt;&lt;br&gt;
– Edsger Dijkstra&lt;/p&gt;

&lt;p&gt;Walking on water and developing software from a specification are easy if both are frozen.&lt;br&gt;&lt;br&gt;
– Edward V Berard&lt;/p&gt;

&lt;p&gt;Design is the art of arranging code to work today, and be changeable forever.&lt;br&gt;&lt;br&gt;
-– Sandi Metz&lt;/p&gt;

&lt;p&gt;There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.&lt;br&gt;&lt;br&gt;
– C.A.R. Hoare.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Dutch computer pioneer Dijkstra, had many profound insights on computing complexity and algorithms. He is possibly one of favorite computer scientist in world wide. One of his most cherished habits was in creating &lt;a href="https://www.cs.utexas.edu/users/EWD/"&gt;amazing articles&lt;/a&gt;. Most of the articles written in a fountain pen.&lt;/p&gt;

&lt;p&gt;Simplicity doesn’t mean doing less; rather, it’s a way to keep your software maintainable.&lt;/p&gt;

&lt;p&gt;When you start writing code, you tend to make it very complex. As you become an experienced programmer, you will find that keeping things simple is the surest way to build complex systems.&lt;/p&gt;

&lt;p&gt;Ability to make complex things simple is what sets apart a great programmer from an average one.&lt;/p&gt;

&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Do things in right way
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Make it work, make it right, make it fast.”&lt;br&gt;&lt;br&gt;
– Kent Beck&lt;/p&gt;

&lt;p&gt;When in doubt, use brute force.&lt;br&gt;&lt;br&gt;
——Ken Thompson&lt;/p&gt;

&lt;p&gt;The sooner you start to code, the longer the program will take.&lt;br&gt;&lt;br&gt;
—— Roy Carlson&lt;/p&gt;

&lt;p&gt;If you can’t write it down in English, you can’t code it.&lt;br&gt;&lt;br&gt;
—— Peter Halpern&lt;/p&gt;

&lt;p&gt;Get your data structures correct first, and the rest of the program will write itself.&lt;br&gt;&lt;br&gt;
—— David Jones&lt;/p&gt;

&lt;p&gt;Don’t write a new program if one already does moie or less what you want. And if you must write a program, use existing code to do as much of the work as possible.&lt;br&gt;&lt;br&gt;
—— Richard Hill&lt;/p&gt;

&lt;p&gt;Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.&lt;br&gt;&lt;br&gt;
– Rick Osborne&lt;/p&gt;

&lt;p&gt;We better hurry up and start coding, there are going to be a lot of bugs to fix. 😏&lt;br&gt;&lt;br&gt;
– Anonymous&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m always happy to follow these principles when programming. These advice helped me to save a lot of time. Remember, do the right thing at proper time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimize it or not
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Before optimizing, use a profiler to locate the “hot spots” of the program.&lt;br&gt;&lt;br&gt;
—— Mike Morton&lt;/p&gt;

&lt;p&gt;In non-I/O-bound programs, less than four per cent of a program generally accounts for more than half of its running time.&lt;br&gt;&lt;br&gt;
—— Don Knuth&lt;/p&gt;

&lt;p&gt;Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.&lt;/p&gt;

&lt;p&gt;Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified.&lt;br&gt;&lt;br&gt;
—— Don Knuth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Premature optimization&lt;/em&gt; means begin to optimize a program without “hot spot” tracing. You won’t fix performance issue and introduce bugs in this kind of optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep code readable
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Programs must be written for people to read, and only incidentally for machines to execute.&lt;br&gt;&lt;br&gt;
–Hal Abelson and Gerald Sussman. Structure and Interpretation of Computer Programs&lt;/p&gt;

&lt;p&gt;Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&lt;br&gt;&lt;br&gt;
– Martin Fowler&lt;/p&gt;

&lt;p&gt;It’s harder to read code than to write it&lt;br&gt;&lt;br&gt;
– Joel Spolsky&lt;/p&gt;

&lt;p&gt;Don’t comment bad code. Rewrite it.&lt;br&gt;&lt;br&gt;
– Brian Kernighan&lt;/p&gt;

&lt;p&gt;Good code is its own best documentation. As you’re about to add a comment, ask yourself:&lt;br&gt;&lt;br&gt;
‘How can I improve the code so that this comment isn’t needed?’&lt;br&gt;&lt;br&gt;
– Steve McConnell (Code Complete)&lt;/p&gt;

&lt;p&gt;If the code and the comments disagree, then both are probably wrong.&lt;br&gt;&lt;br&gt;
—— Norm Schryer&lt;/p&gt;

&lt;p&gt;When explaining a command, or language feature, or hardware widget, first describe the problem it is designed to solve.&lt;br&gt;&lt;br&gt;
—— David Martin&lt;/p&gt;

&lt;p&gt;Code is like humor. When you have to explain it, it’s bad.&lt;br&gt;&lt;br&gt;
-– Cory House&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do you have trouble in reading the code written by yourself two years ago?&lt;/p&gt;

&lt;p&gt;A single piece of code will, over its lifetime, be read hundreds, maybe thousands of times. It will be read hundreds or thousands of times because it must be understood.&lt;/p&gt;

&lt;p&gt;Comments will help much on making code readable. Good programmers will write easy to understand the code, and don’t care whether the machine can run, compilers and interpreters will keep your code is right in syntax.&lt;/p&gt;

&lt;p&gt;But too much of comments also will not help. If the code is self-explanatory, there is no need for comments. Even if you do need a comment, the comment should be about why you did it, not about what you did.&lt;/p&gt;

&lt;p&gt;When writing code, it is better to be clear than to be clever. “Be cleaver” is something like: condensing multiple lines of code into one, using those tricky algorithms, or using some obscure feature of programming language to accomplish a task in a novel way. Tricky code will make it hard to maintain.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Testing can show the presence of bugs, but not their absence.&lt;br&gt;&lt;br&gt;
—— Edsger W. Dijkstra&lt;/p&gt;

&lt;p&gt;If debugging is the process of removing bugs, programming must be the process of putting them in.&lt;br&gt;&lt;br&gt;
– Edsger Dijkstra&lt;/p&gt;

&lt;p&gt;Testing leads to failure, and failure leads to understanding.&lt;br&gt;&lt;br&gt;
– Burt Rutan&lt;/p&gt;

&lt;p&gt;It takes 3 times the effort to find and fix bugs in system test than when done by the developer. It takes 10 times the effort to find and fix bugs in the field than when done in system test. Therefore insist on unit tests by the developer.&lt;br&gt;&lt;br&gt;
– Larry Bernstein&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is no doubt about the importance of testing. I’m afraid to maintain a code base which don’t contains enough test cases. We should try to find bugs in development phase as many as possible.&lt;/p&gt;

&lt;p&gt;Unit testing, integrated testing, fuzzing testing are all good practices to improve the coding quantity. From my experience, the testing code is also document for code, which helpful for others understanding code.&lt;/p&gt;

&lt;p&gt;Embrace testing, it will save you much of time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deugging
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Of all my programming bugs, 80% are syntax errors. Of the remaining 20%, 80% are trivial logical errors. Of the remaining 4%, 80% are pointer errors. And the remaining 0.8% are hard.&lt;br&gt;&lt;br&gt;
—— Marc Donner&lt;/p&gt;

&lt;p&gt;The first step in fixing a broken program is getting it to fail repeatably.&lt;br&gt;&lt;br&gt;
—— Tom Duff&lt;/p&gt;

&lt;p&gt;Programming is like sex. One mistake and you have to support it for the rest of your life&lt;br&gt;&lt;br&gt;
– Michael Sinz&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Debugging is a last-ditch effort to save the code. Debugging code is more difficult than writing code. Because when we need to debug, it means the error have escaped from coding, reviewing, testing.&lt;/p&gt;

&lt;p&gt;Usually, find the root cause of a bug is much harder than fix it. If you have reproduced a bug, you almost finished 90% of work.&lt;/p&gt;

&lt;p&gt;I’m a fan of Printf Debugging(a.k.a Caveman Debugging).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.&lt;br&gt;&lt;br&gt;
-— Brian Kernighan, “Unix for Beginners” (1979)&lt;/p&gt;

&lt;p&gt;Debuggers don’t remove bugs. They only show them in slow motion.&lt;br&gt;&lt;br&gt;
– Anonymous&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Productivity
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t reapeat yourself. Every piece of knowledge must have a single, unambiguous, authoritative representation within a system”&lt;br&gt;&lt;br&gt;
– Andy Hunt and Dave Thomas&lt;/p&gt;

&lt;p&gt;I’m not a great programmer; I’m just a good programmer with great habits.&lt;br&gt;&lt;br&gt;
– Kent Beck&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lazy programmers are good programmers, who want to do avoid duplication and won’t do thing reputably.&lt;/p&gt;

&lt;p&gt;If there is a lot of repetition in the code, it is likely that we should spend time to refactor the code. Most repeated task is more suitable finished by machine, so we should make it automation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tools
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;The most disastrous thing that you can ever learn is your first programming language.&lt;br&gt;&lt;br&gt;
– Alan Kay&lt;/p&gt;

&lt;p&gt;A language that doesn’t affect the way you think about programming is not worth knowing.&lt;br&gt;&lt;br&gt;
― Alan J. Perlis&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Programming languages, editors, libraries, all these are tools for programmers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Learning
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;The only way to learn a new programming language is by writing programs in it.&lt;br&gt;&lt;br&gt;
– Dennis Ritchie&lt;/p&gt;

&lt;p&gt;The first principle is that you must not fool yourself and you are the easiest person to fool.&lt;br&gt;&lt;br&gt;
―- Richard P. Feynman&lt;/p&gt;

&lt;p&gt;Avoid “cookbook programming”, where you copy and paste bits of code that you have found to make something work. Make sure you fully understand what everything it actually doing, and that you are comfortable applying the techniques in other situations.&lt;br&gt;&lt;br&gt;
– John&lt;/p&gt;

&lt;p&gt;Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.&lt;br&gt;&lt;br&gt;
– Eric S. Raymond&lt;/p&gt;

&lt;p&gt;Programming isn’t about what you know; it’s about what you can figure out.&lt;br&gt;&lt;br&gt;
– Chris Pine&lt;/p&gt;

&lt;p&gt;Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why.&lt;br&gt;&lt;br&gt;
– Anonymous&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I learned programming, I was also anxious about knowing the details of everything, language syntax, libraries.&lt;/p&gt;

&lt;p&gt;We have a ton to lear. This way of learning will make a learner frustrated.&lt;/p&gt;

&lt;p&gt;Instead, don’t learn details, learn the essentials and concepts, apply them in practice. Problem-solving is the skill we end up using most.&lt;/p&gt;

&lt;p&gt;Finally, don’t lose your curiosity.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Copilot Will Not Change Programming</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Sat, 03 Jul 2021 07:35:18 +0000</pubDate>
      <link>https://dev.to/snj/why-copilot-will-not-change-programming-4347</link>
      <guid>https://dev.to/snj/why-copilot-will-not-change-programming-4347</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y8iC3qFt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/s-tsuchiya-_WjhfEzRDak-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y8iC3qFt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/s-tsuchiya-_WjhfEzRDak-unsplash.jpg" alt="progrmming duck"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hottest tech new of last week is &lt;a href="https://copilot.github.com/"&gt;Copilot&lt;/a&gt;. Seems almost all programmers are playing or waiting for play with this new fancy AI coding assistant.&lt;/p&gt;

&lt;p&gt;Someone says it will totally change the world of programming, an innovative and game-change one!&lt;/p&gt;

&lt;p&gt;But, I am not so optimistic about it. From my perspective as an old-school programmer, this kind of tool looks fancy but not so helpful as people give credit for. Not to mention it will be a substitute for real programmers.&lt;/p&gt;

&lt;p&gt;Let me explain it to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding faster is not a big deal
&lt;/h2&gt;

&lt;p&gt;Think about it. How much time do you spend on coding?&lt;/p&gt;

&lt;p&gt;In fact, the time we spend on writing code is not a high proportion of the overall software development cycle, even less than a quarter(especially in some tech giants).&lt;/p&gt;

&lt;p&gt;We spend much more time on requirements analysis, technical design, testing, debugging, team collaboration.&lt;/p&gt;

&lt;p&gt;Software engineering is hard, mostly because of the high complexity of the real world. We can’t change this in truth, abstractions in computing over time are inevitable. And no project ever failed with slow coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wfz58xYS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/still-is-code.jfif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wfz58xYS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/still-is-code.jfif" alt="still code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coding faster will not make you a better programmer, instead, the ability of abstraction, design, and real experience of real-world engineering will make you a better programmer.&lt;/p&gt;

&lt;p&gt;Some aged programmers typing slowly for bad eyesight, but they write bug-free code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Will help on coding faster?
&lt;/h2&gt;

&lt;p&gt;Years ago I was fascinated by this kind of programming aids. There is a popular template system in Emacs called &lt;a href="https://github.com/joaotavora/yasnippet"&gt;snippets&lt;/a&gt;. We can define our own templates and functions, and then a shortcut would generate code template for me, and I’d just need to fill in the rest.&lt;/p&gt;

&lt;p&gt;That looks cool, really cool…&lt;/p&gt;

&lt;p&gt;It makes me like a movielike super programmer.&lt;/p&gt;

&lt;p&gt;But after I got deep into it, it turns out not as useful as I thought.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.tabnine.com/"&gt;tabnine&lt;/a&gt; is a similar AI tool with Copilot, which will generate part of the code based on your previous inputs. Copilot will even suggest based on you comments, name of function.&lt;/p&gt;

&lt;p&gt;The problem is, when I’m coding with it, &lt;strong&gt;I need to constantly review whether the completion is right&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DHGf-CW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/E5IbxwXWYAUoi3U.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DHGf-CW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/E5IbxwXWYAUoi3U.png" alt="copilot-funny"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a kind of distraction for me. Imagine that, you are an experienced and solid programmer, this AI-tools is a naïve and occasional dumb one, he will pair coding with you.&lt;/p&gt;

&lt;p&gt;No, I don’t want it!&lt;/p&gt;

&lt;p&gt;The best practice to make programming faster is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;focus, focus, and focus&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Think clearly before coding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shortcut, variable completion, class attribute, and method names completion are all helpful for coding faster, it will help your typing to catch up with thinking.&lt;/p&gt;

&lt;p&gt;But code generation is a different thing. It will distract you, even more than 50% of the completion catches your coding intention, the other nonsense part will slow you down.&lt;/p&gt;

&lt;p&gt;If the code base which contains a lot of repetitive pieces or logic, this kind of tool can definitely speed up your coding. Such as most front-end programming, web programming which contains lots of similar CRUD logic.&lt;/p&gt;

&lt;p&gt;But I don’t believe this stuff will make a fundamental change to programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Will help on learning programming?
&lt;/h2&gt;

&lt;p&gt;Copilot will help to reduce the duplicated tasks like search code from Web. As a beginner to learn programming, it may help you, since when you type some keywords, the code snippet will show up in front of you.&lt;/p&gt;

&lt;p&gt;But, as a reminder, copy and make it work is not a better way to improve your coding ability or qualify of work.&lt;/p&gt;

&lt;p&gt;Instance coding suggestion may make you happy when coding, but will not help you in long term.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x8R1Pt8j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/freestocks-p_jg3JF68SQ-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x8R1Pt8j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/freestocks-p_jg3JF68SQ-unsplash.jpg" alt="Photo by unsplash.com/@freestocks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Programming is a craft such as writing, we are writing source code to express ideas. Do you think it’s a good idea to let AI to assist a learner what the next sentence or paragraph will be?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Word completion will help, and sentence auto-completion will become a burden.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Same as writing, if we want to be better at programming, the only way is coding a lot and reading a lot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://d3dvortex.blogspot.com/2005/07/programming-advice-from-john-carmack-i.html"&gt;John Carmack&lt;/a&gt; when talking about learning programming:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Avoid “cookbook programming”, where you copy and paste bits of code that you have found to make something work. Make sure you fully understand what everything it actually doing, and that you are comfortable applying the techniques in other situations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The potential risks
&lt;/h2&gt;

&lt;p&gt;There are several kinds of risk come with AI coding assistance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Potential bug introduced in. If the user didn’t pay attention to review the generated code, it will be a nightmare.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The copyright and ownership issue of code. If a code snippet &lt;a href="https://twitter.com/mitsuhiko/status/1410886329924194309"&gt;generated from GPL authorized code&lt;/a&gt; base and adapted by a commercial company. Whose fault? And who is the owner when the code is generated?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security. Is it possible for hackers to train some code snippets intensively and induce attacking code to users?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The potential benefits
&lt;/h2&gt;

&lt;p&gt;Of course, this tool may also give some benefits in some scenarios.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To make the tool more useful, we may trend to write more meaningful names and better documents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interview will be easier if we allowed to use it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make you not longly when programming, it will give you a sense that someone is always with you. Maybe feel better than a small yellow duck.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>codenewbie</category>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Top 5 VSCode Extensions for Markdown</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Sat, 29 May 2021 07:26:52 +0000</pubDate>
      <link>https://dev.to/snj/top-5-vscode-extensions-for-markdown-15mi</link>
      <guid>https://dev.to/snj/top-5-vscode-extensions-for-markdown-15mi</guid>
      <description>&lt;p&gt;I moved from Emacs to VSCode for almost one year. Most of the time, I’m editing Markdown.&lt;/p&gt;

&lt;p&gt;Let me share these 5 extensions which are useful for boosting your productivity on Markdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown All in One
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/yzhang-gh/vscode-markdown"&gt;Markdown All in One&lt;/a&gt; is a must one for editing Markdown. It contains Markdown preview,&lt;br&gt;&lt;br&gt;
keyboard shortcuts, auto preview, etc.&lt;/p&gt;

&lt;p&gt;The shortcuts will make editing Markdown much easy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--akSwPZNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/tab-backspace.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--akSwPZNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/tab-backspace.gif" alt="file:tab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The completion also contains pathfinding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--su9StZJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/vscode-markdown-all-in-one.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--su9StZJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/vscode-markdown-all-in-one.gif" alt="file:vscode-markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can print Markdown to HTML with the command: &lt;code&gt;Markdown: Print current document to HTML&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, it comes with a beautiful Math support:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KLVpNKt7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/markdown-math.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KLVpNKt7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/markdown-math.png" alt="img:vscode-math"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Dictionary Completion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=yzhang.dictionary-completion"&gt;Dictionary Completion&lt;/a&gt; is another extension to help you input English words quicker. Because I’m not a native English speaker, this also helps me to write words correctly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FELW3y9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/vscode-markdown-dict.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FELW3y9s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/vscode-markdown-dict.gif" alt="img:vscode-dict"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Markdown does not support quick suggestions in default, we need to add the below snippet to make hints appear when type in a Markdown file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"[markdown]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.quickSuggestions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paste Image
&lt;/h2&gt;

&lt;p&gt;I’d love to insert more screenshots to my Markdown files. &lt;a href="https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image"&gt;Paste Image&lt;/a&gt; helps you save your images from xclip. This extension supports Mac/Windows/Linux.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--miCN0133--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/vscode-paste-image.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--miCN0133--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/vscode-paste-image.gif" alt="img:markdown-paste-img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PlantUML
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=jebbs.plantuml"&gt;PlantUML&lt;/a&gt; is an awesome extension if you need to draw diagrams.&lt;br&gt;&lt;br&gt;
In PlantUML, diagrams are defined using a &lt;a href="https://plantuml.com/"&gt;simple and intuitive language&lt;/a&gt;. When you editing the source files of the diagrams, you can also preview the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6l9t3GTx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/plantuml-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6l9t3GTx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/plantuml-demo.gif" alt="img:markdown-plantuml"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PlantUML supports all kinds of diagrams used by developers, such as sequence diagrams, object and class diagrams, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown Emoji
&lt;/h2&gt;

&lt;p&gt;We need more smiles!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=bierner.markdown-emoji"&gt;Markdown Emoji&lt;/a&gt; does one simple thing: add some Emoji faces in your document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jNntoE3C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/markdown-emoji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jNntoE3C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/markdown-emoji.png" alt="img:emoji"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I found a defect for this extension, my Hexo rendered result does not show Emoji correct in HTML. There is another similar extension &lt;a href="https://marketplace.visualstudio.com/items?itemName=Perkovec.emoji"&gt;Emoji&lt;/a&gt; solves this issue. And you can even add Emoji in code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YOH311FQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/markdown-emoji-2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YOH311FQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/markdown-emoji-2.gif" alt="img:markdown-emoji"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That all, happy editing Markdown!&lt;/p&gt;

</description>
      <category>tools</category>
      <category>vscode</category>
      <category>programming</category>
    </item>
    <item>
      <title>5 Fancy Shells You Should Have A Try</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Thu, 27 May 2021 19:55:00 +0000</pubDate>
      <link>https://dev.to/snj/5-fancy-shells-you-should-have-a-try-1anc</link>
      <guid>https://dev.to/snj/5-fancy-shells-you-should-have-a-try-1anc</guid>
      <description>&lt;p&gt;I love command-line because it makes me more productive.&lt;/p&gt;

&lt;p&gt;Most of the time, I live in a Shell in daily work. Shell is simply a command-line interface (CLI) that allows users to interact with the operating system.&lt;/p&gt;

&lt;p&gt;Since I have worked with command-line so much of time, I tried many different Shells. I find these 5 Shell worth to be known by more people.&lt;/p&gt;

&lt;p&gt;Some of them are already production-ready for daily usage, some are still in rapid development. Maybe you will find your favorite one as your next Shell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fish Shell
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/fish-shell/fish-shell"&gt;Fish&lt;/a&gt; stands for “the friendly interactive shell”.&lt;/p&gt;

&lt;p&gt;It is a smart and user-friendly command line Shell for macOS and Linux family OS.&lt;br&gt;&lt;br&gt;
Many fancy features are included by default, such as syntax highlighting, autosuggest-as-you-type, and fancy tab completions.&lt;/p&gt;

&lt;p&gt;The configuration file is located at &lt;code&gt;~/.config/fish/config.fish&lt;/code&gt;. We can add custom functions to it. Fish also provides a web interface to configure the file. Run &lt;strong&gt;fish_config&lt;/strong&gt; , the browser will open port 8000 of the machine, and the user can configure fish on the web page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RS6HMZMF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/fish.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RS6HMZMF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/fish.jpg" alt="file:fish"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fish is Shell with more than ten years, it’s mature and loved by many programmers. I think the most impressive feature is auto-completion.&lt;br&gt;&lt;br&gt;
If you want to use it in daily work, don’t forget &lt;a href="https://github.com/oh-my-fish/oh-my-fish"&gt;oh-my-fish&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oil Shell
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/oilshell/oil"&gt;Oil Shell&lt;/a&gt; is a new Unix shell. Shell scripting is a domain-specific language for dealing with concurrent processes, text strings, and the file system, it is hard to learn and a nightmare for maintenance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZafU1sbw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/bash-error.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZafU1sbw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/bash-error.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;| Oil is also aimed at people who know say Python or JavaScript, but purposely avoid shell&lt;/p&gt;

&lt;p&gt;Since we have so many existing shell programs, you can not ignore them. &lt;code&gt;Oil&lt;/code&gt; helps you gradually migrate away from Shell scripting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bin/osh&lt;/code&gt; runs your existing shell scripts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bin/oil&lt;/code&gt; is a brand new language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://www.oilshell.org/blog/2020/01/simplest-explanation.html"&gt;Oil language&lt;/a&gt; is a new dialect which is parsed and evaluated like Python or JavaScript, it’s more concrete than Shell scripting.&lt;/p&gt;

&lt;p&gt;The funny thing is, this project is implemented in Python, and then automatically translated to C++ with custom tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  xonsh
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/xonsh/xonsh"&gt;xonsh&lt;/a&gt; is another Python implemented Shell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4PvkmAfA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/xonsh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4PvkmAfA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/xonsh5.png" alt="file:xonsh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;xonsh&lt;/code&gt;‘s syntax is more like Python, actually, all Python code is runnable in xonsh. xonsh is based on Python, and with additional syntax added that makes calling subprocess commands, manipulating the environment, and dealing with the file system easy.&lt;/p&gt;

&lt;p&gt;Unlike &lt;code&gt;Oil&lt;/code&gt;, you can not reuse existing Bash scripts in &lt;code&gt;xonsh&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nushell
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nushell/nushell"&gt;Nushell&lt;/a&gt; is a new Shell, written in Rust. It’s inspired by PowerShell in Windows. Rather than thinking of files and services as raw streams of text, Nushell looks at each input as something with structure. In this way, users can make filters with Pipelines easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wyhQfnn7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/nushell-autocomplete5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wyhQfnn7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://coderscat.com/images/nushell-autocomplete5.gif" alt="file:nushell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nushell has not reached release 1.0, but worth having a try for fun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zsh
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.zsh.org/"&gt;Zsh&lt;/a&gt; is fully compatible with Bash and has extremely rich plug-ins.&lt;/p&gt;

&lt;p&gt;Zsh was first released in 1990 and is included in many OS. Actually, Mac OS has already replaced Bash with Zsh as the default shell in Catalina.&lt;/p&gt;

&lt;p&gt;If you use Zsh, you won’t miss &lt;a href="https://github.com/ohmyzsh/ohmyzsh"&gt;oh-my-zsh&lt;/a&gt;. It’s a community-driven framework for managing your zsh configuration, the repo contains hundreds of powerful plugins and beautiful themes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8dB1N_yp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/ohmyzsh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8dB1N_yp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/ohmyzsh.jpg" alt="file:nushell"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tools</category>
      <category>linux</category>
    </item>
    <item>
      <title>Bloom Filter: Concept and Implementation</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Mon, 17 May 2021 23:52:00 +0000</pubDate>
      <link>https://dev.to/snj/bloom-filter-concept-and-implementation-4gh0</link>
      <guid>https://dev.to/snj/bloom-filter-concept-and-implementation-4gh0</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Think about this scenario, given a list of strings with number of N, where N is large than 1 million.&lt;br&gt;
Let's implement a data structure to check whether a target string is in given strings.&lt;/p&gt;

&lt;p&gt;If N is not so huge, a HashDict could be used to build a dictionary. When N is huge, memory is the key point for this challenge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Different data structures will give you different facility and benefits. &lt;br&gt;
To properly use the power and accessibility of the data structures you need to &lt;br&gt;
know the trade-offs of using one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, we need a data structure which optimized with space. This is where &lt;strong&gt;bloom filter&lt;/strong&gt; can be used.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Concept
&lt;/h2&gt;

&lt;p&gt;Bloom Filter was proposed by Burton Howard Bloom in 1970. The related paper is: &lt;a href="https://dl.acm.org/doi/10.1145/362686.362692"&gt;Space/time Trade-offs in Hash Coding with Allowable Errors&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It's an efficiency in time and space with a very clever design. The cost for space efficiency is accuracy, we called it as a probabilistic data structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the returned result is false, it's 100% correct.&lt;/li&gt;
&lt;li&gt;When the returned result is true, it may be wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why? Let's come up with the details of &lt;strong&gt;bloom filter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The bottom data structure of the &lt;strong&gt;bloom filter&lt;/strong&gt; is a bit array(like BitMap). Initially, when the represented set is empty, all bits are 0: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--30VsoqwP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/bloomfilter1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--30VsoqwP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/bloomfilter1.png" alt="file:img/bloom-filter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we initialize the bit array, we use multiple &lt;em&gt;hash functions&lt;/em&gt; to compute multiple indexes according the the strings, and set the bit at index positions to 1.&lt;br&gt;
Why we need multiple hash functions? This is the core idea of &lt;strong&gt;bloom filter&lt;/strong&gt;. Think about HashMap, usually we use one hash function to calculate a hash value, but we also store all the keys in HashMap.&lt;br&gt;
Different keys with same hash function may come out with the same hash value, this is called &lt;em&gt;collision&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jFGYAL4V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./images/bloom-filter-hashs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jFGYAL4V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./images/bloom-filter-hashs.png" alt="file:img/bloom-filter-hash-functions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;bloom filter&lt;/strong&gt;, we use multiple hash functions to reduce the possibility of collision.&lt;/p&gt;

&lt;p&gt;Even the possibility of collision could be very small, it may happen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RvA9m8Be--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/bloomfilter2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RvA9m8Be--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/bloomfilter2.png" alt="file:img/bloom-filter2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For query API, we do similar hash calculations, but when we find one hash bit is not set to 1, we can safely return false. For naive Bloom Filter, the keys added into table can not be deleted. If we want to delete key, a variant named &lt;strong&gt;Counting Bloom Filter(CBF)&lt;/strong&gt; could be used.&lt;/p&gt;

&lt;p&gt;We can have some trivial tunning about the data structures, you can modify the false positive rate of your filter. From above description, a larger filter will have less false positives, and more hash functions will introduce more cost in computation. Given a Bloom filter with &lt;em&gt;m&lt;/em&gt; bits and &lt;em&gt;k&lt;/em&gt; hashing functions with &lt;em&gt;n&lt;/em&gt; insertion.&lt;/p&gt;

&lt;p&gt;Your false positive rate will be approximately $$ (1-e^{-kn/m})^k $$.&lt;/p&gt;
&lt;h3&gt;
  
  
  Implementation of C
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;limits.h&amp;gt;
#include &amp;lt;stdarg.h&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;hashfunc_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;asize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;nfuncs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;hashfunc_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;BloomFilter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define SETBIT(a, n) (a[n / CHAR_BIT] |= (1 &amp;lt;&amp;lt; (n % CHAR_BIT)))
#define GETBIT(a, n) (a[n / CHAR_BIT] &amp;amp; (1 &amp;lt;&amp;lt; (n % CHAR_BIT)))
&lt;/span&gt;
&lt;span class="n"&gt;BloomFilter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;bloom_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;nfuncs&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;span class="n"&gt;BloomFilter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;va_list&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;bloom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BloomFilter&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calloc&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CHAR_BIT&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;CHAR_BIT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hashfunc_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nfuncs&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hashfunc_t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;va_start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nfuncs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nfuncs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;va_arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashfunc_t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;va_end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nfuncs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nfuncs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;asize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;bloom_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BloomFilter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nfuncs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;SETBIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;asize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;bloom_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BloomFilter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nfuncs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GETBIT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;asize&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sax_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sdbm_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;     
    &lt;span class="n"&gt;BloomFiler&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bloom_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2500000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sax_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sdbm_hash&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;h3&gt;
  
  
  Implementation of Python
&lt;/h3&gt;

&lt;p&gt;Please refer to &lt;a href="https://pypi.org/project/bloom-filter/"&gt;Pure Python Bloom Filter module&lt;/a&gt;. The usage is straight forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;bloom_filter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BloomFilter&lt;/span&gt;

&lt;span class="n"&gt;bloom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BloomFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_elements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;"test-key"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test-key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;"test-key"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://chromium.googlesource.com/chromium/blink/+/refs/heads/main/Source/wtf/BloomFilter.h"&gt;Chromium with a Counting Bloom Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jaybaird/python-bloomfilter"&gt;python-bloomfilter is a Scalable Bloom Filter&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google/leveldb/blob/master/util/bloom.cc"&gt;LevelDB use double-hashing instead of multiple hash functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;b.com/google/leveldb/blob/master/util/bloom.cc)&lt;/p&gt;

</description>
      <category>programming</category>
      <category>bloomfilter</category>
    </item>
    <item>
      <title>5 Tips For Techical Interview</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Sun, 16 May 2021 23:52:00 +0000</pubDate>
      <link>https://dev.to/snj/5-tips-for-techical-interview-m6b</link>
      <guid>https://dev.to/snj/5-tips-for-techical-interview-m6b</guid>
      <description>&lt;p&gt;As a tech lead worked at several technical giants, I have participated in dozens of interviews as a interviewer. Here I want to share with you some tips in a programming interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be confident and honest
&lt;/h2&gt;

&lt;p&gt;Many candidates (especially for some new-grads), because they don't have much experience on interviewing, they may tend to be unconfident. They cannot express their opinions fully and freely. And when the interviewer challenge them, they will immediately turned to be timid. This is a red flag for interviewer. Because this will give a impression that they are not assertive enough, or their foundation of computer science is not solid.&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/http%3A%2F%2Fcoderscat.com%2Fimages%2Fphoto-1607000975677-90533e4355fe.jfif" 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/http%3A%2F%2Fcoderscat.com%2Fimages%2Fphoto-1607000975677-90533e4355fe.jfif" alt="file:img/confidence"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another important point is &lt;em&gt;be honest&lt;/em&gt;, most interviewer don't want a un-honest colleague. I found a candidate tried to pretend that she knew something on a topic which actually she was not familiar with. She told me a lot stuff but it's wrong, and further more she tried to change the subject since she didn't know the right answer. This seems a clever trick in daily communication, but it is not a good way in a interview. If you don't know the answers for some questions, just admit you don't know it. It's OK, nobody knows all technical details or answer every questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication is important
&lt;/h2&gt;

&lt;p&gt;Interview is not all about a game of answering questions or examination. Instead, interview is a mocking scenario in daily work. The interviewer is trying to find a human but not a machine. Because in daily work, collaboration is an key part of software development.  Although the your answering and coding is important, effective communication is also necessary.&lt;/p&gt;

&lt;p&gt;A smooth self-introduction is necessary, practice it until you feel comfortable.&lt;/p&gt;

&lt;p&gt;When you faced with challenge that you can't find the solution, don't let the entire interview fall into silence. Instead, tell the interviewers what you know, and what you think, actively ask the interviewer for hints.&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/http%3A%2F%2Fcoderscat.com%2Fimages%2Fphoto-1517245386807-bb43f82c33c4.jfif" 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/http%3A%2F%2Fcoderscat.com%2Fimages%2Fphoto-1517245386807-bb43f82c33c4.jfif" alt="file:img/communication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t give out your ideas, we don't know the way of your thinking and the style of your reasoning.&lt;/p&gt;

&lt;p&gt;Good questions from you can also show your thinking advantages.  I have given HIRE result to some candidates who did not come up with the final answers, because their thinking process are good. &lt;/p&gt;

&lt;p&gt;The interviewers prefer to candidate with a clear thinking. We doesn’t just want you to write down the answer, we value the process of how you get there. People who can explain something clearly tend to be a better collaborator. &lt;/p&gt;

&lt;h2&gt;
  
  
  Write clean and readable code
&lt;/h2&gt;

&lt;p&gt;Write clean and readable code is not easy, this may need some deliberate training, &lt;a href="//./learn-from-source-code"&gt;try to learning from great source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After finishing your code, you should spend a some amount of time to optimize your code structure to make it more readable.&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/http%3A%2F%2Fcoderscat.com%2Fimages%2Fphoto-1606159068539-43f36b99d1b2.jfif" 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/http%3A%2F%2Fcoderscat.com%2Fimages%2Fphoto-1606159068539-43f36b99d1b2.jfif" alt="file:img/coding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For instance, it can be better abstracted with appropriate helper functions for duplicated code. &lt;/p&gt;

&lt;p&gt;Variable naming is a key point, even the code is usually less than 100 lines in a interviewing.&lt;/p&gt;

&lt;p&gt;Appropriate comments will also impress interviewers. But, remember you need to avoid overly abstraction, which will make it very difficult to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add testing for your code
&lt;/h2&gt;

&lt;p&gt;In daily work, add testing is your necessary task for any changes, especially for a complicated system.&lt;/p&gt;

&lt;p&gt;Take the initiative to propose corner cases, which reflects your careful thinking and is very important for the positions of software development!&lt;/p&gt;

&lt;p&gt;After coding, you should analyze the time and space complexity, and then run some basic examples to verify your solution. If you have time, please add more testing for your code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Show your passion and curiosity
&lt;/h2&gt;

&lt;p&gt;Many candidates seems treat interviewing as an examination. We prefer to the candidate who has a passion and curiosity in computer science, because these two qualities will make everything easier in their career. Those who truly love programming will find more fun and have a better performance in work. For those who don't love the craft of programming, even if they manage to get a job, they will hate it.&lt;/p&gt;

&lt;p&gt;A perfect way to show your passions is your hobby project, or your contributions to the open source community.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>interview</category>
    </item>
    <item>
      <title>Top 5 Books for Python Programming</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Tue, 17 Nov 2020 10:38:37 +0000</pubDate>
      <link>https://dev.to/snj/top-5-books-for-python-programming-bhp</link>
      <guid>https://dev.to/snj/top-5-books-for-python-programming-bhp</guid>
      <description>&lt;p&gt;&lt;a href="http://coderscat.com/awesome-books-for-python-programming/"&gt;Original Post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python is a language I like very much, and it is also hot right now. In this post, I will list some Python books for beginners and experienced programmers who are interested in Python.&lt;/p&gt;

&lt;p&gt;Let’s start from beginner to expert levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/38NF2iO"&gt;Python Crash Course&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PttTfj7K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201117124104104.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PttTfj7K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201117124104104.png" alt="image-20201117124104104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This book is a good introduction to Python. It will teach you the basic syntax, such as variables, lists, classes, control flows, etc. All the chapter contains some handy exercises for readers. In the second half part, we will practice Python with several small projects, play with some handy libraries.&lt;/p&gt;

&lt;p&gt;It’s well written and easy to understand. If you are a fresh new sailor, start your Python journey with it!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/38SHrsC"&gt;Fluent Python: Clear, Concise, and Effective Programming&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pc_AdAQZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116191142235.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pc_AdAQZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116191142235.png" alt="image-20201116191142235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the strongly recommended one for those who have got some Python programming experiences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://amzn.to/38SHrsC"&gt;Fluent Python&lt;/a&gt; skips over the basics, instead, this book will focus on those specific features which rarely presented in other programming languages, it also provides enough details about implementations. It felt like a treasure box to me.&lt;/p&gt;

&lt;p&gt;I spent about one month to read it. I read it slowly, a few pages every night. It’s a pleasure.&lt;/p&gt;

&lt;p&gt;Never has a Python book gave me such an interesting experience. It’s so detailed and informative, the author is really good at writing and teaching.&lt;/p&gt;

&lt;p&gt;If you looking to upgrade your Python skills, this is THE book. I promise you no regrets for the time you spend on this book.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/3ptH5Pf"&gt;Python Essential Reference&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nNAT2-FQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116192402893.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nNAT2-FQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116192402893.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This book explains in detail the most important parts of the core Python language and the Python library. It covers types and objects, operators and expressions, programming structures and control flows, input and output, testing, debugging, and more, as well as some advanced topics not covered in the official Python documentation or other references.&lt;/p&gt;

&lt;p&gt;Although this kind of book looks a bit boring, it’s definitely beneficial for a Python programmer to read. Or, at least, go through the topics interested you and treat it as a reference book.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/32MiUl8"&gt;The Hacker’s Guide To Python&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b0m9A6yv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116192138356.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b0m9A6yv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116192138356.png" alt="image-20201116192138356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This book contains more advanced topics. The horizon is no longer on the language details. The author is a Python expert and had led some super large Python projects. There are many thoughts on software engineering, which will benefit to all software engineers, not just Python programmers.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://amzn.to/2KcXSpv"&gt;High-Performance Python: Practical Performant Programming for Humans&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6RlOJuhW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116192243047.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6RlOJuhW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116192243047.png" alt="image-20201116192243047"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python is a programming language with a high level of abstraction, and one of its great strengths is the efficiency of the development, with the cost of default performance.&lt;/p&gt;

&lt;p&gt;This book is for those who have already started with Python and want to tune the performance of Python code. It’s mainly focused on performance optimization related topics.&lt;/p&gt;

&lt;p&gt;A major goal of this book is to introduce packages and principles that will enable rapid Python development while avoiding many performance limitations, reducing development and maintenance costs, and regain the benefits of system efficiency.&lt;/p&gt;

</description>
      <category>python</category>
      <category>books</category>
    </item>
    <item>
      <title>Config Nginx For Security</title>
      <dc:creator>Nic</dc:creator>
      <pubDate>Mon, 16 Nov 2020 22:52:00 +0000</pubDate>
      <link>https://dev.to/snj/config-nginx-for-security-5129</link>
      <guid>https://dev.to/snj/config-nginx-for-security-5129</guid>
      <description>&lt;p&gt;&lt;a href="http://coderscat.com/config-nginx-for-security/"&gt;Orignal Post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I was in the security group, we found many programmers don't know how to handle, or don't have the awareness of Nginx's security. We found many exploitations or cases of sensitive data was pulled from web servers by attackers.&lt;/p&gt;

&lt;p&gt;Here I will list some configurations for Nginx's Security. Please do adjustments to these configurations according to your actual requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q0VVwtAD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/1638974.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q0VVwtAD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/1638974.png" alt="Nginx Logo - LogoDix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Forbidden any sensitive request path
&lt;/h2&gt;

&lt;p&gt;Many source codes are using Git as version control tools. The directory &lt;code&gt;.git&lt;/code&gt; will contains all the metadata of codebase, including some secrets, etc. Expose it to the public will make your codebase downable for attackers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t4FhbjQV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116125232230.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t4FhbjQV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://coderscat.com/images/image-20201116125232230.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we need to disable the &lt;code&gt;.git&lt;/code&gt; related request routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.git&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;## Disable .htaccess and other hidden files&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;/\.(?!well-known).*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;access_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;log_not_found&lt;/span&gt; &lt;span class="no"&gt;off&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;h2&gt;
  
  
  Forbidden unnecessary HTTP request methods
&lt;/h2&gt;

&lt;p&gt;The most commonly used HTTP request methods are GET, POST, HEAD. We should return 444 for any other unused methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;## Only allow these request methods ##&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request_method&lt;/span&gt; &lt;span class="s"&gt;!~&lt;/span&gt; &lt;span class="s"&gt;^(GET|HEAD|POST)&lt;/span&gt;$ &lt;span class="s"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;## Do not accept DELETE, SEARCH, and other methods ##&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add request rate limiting
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.nginx.com/blog/rate-limiting-nginx/"&gt;Rate limiting&lt;/a&gt; will block many malicious requests, and it is also a frequently used tool to defend against network and application-level &lt;strong&gt;DDoS attacks&lt;/strong&gt; against websites.&lt;/p&gt;

&lt;p&gt;We can add the maximum request limit for a single IP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;limit_req_zone&lt;/span&gt; &lt;span class="nv"&gt;$binary_remote_addr&lt;/span&gt; &lt;span class="s"&gt;zone=ip:10m&lt;/span&gt; &lt;span class="s"&gt;rate=5r/s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;limit_req&lt;/span&gt; &lt;span class="s"&gt;zone=ip&lt;/span&gt; &lt;span class="s"&gt;burst=12&lt;/span&gt; &lt;span class="s"&gt;delay=8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://website&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;h2&gt;
  
  
  Add HTTPS for your service
&lt;/h2&gt;

&lt;p&gt;If you are deploying a non-company project,  &lt;a href="https://letsencrypt.org/"&gt;Let's encrypt&lt;/a&gt; will be enough for personal usage. And remember to redirect all non-HTTPS requests to HTTPS with 301.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt;               &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt;               &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt;          &lt;span class="s"&gt;www.coderscat.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;      &lt;span class="n"&gt;/etc/letsencrypt/live/coderscat.com/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt;  &lt;span class="n"&gt;/etc/letsencrypt/live/coderscat.com/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://coderscat.com&lt;/span&gt;&lt;span class="nv"&gt;$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt; &lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;coderscat.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# ssl on;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;       &lt;span class="n"&gt;/etc/letsencrypt/live/coderscat.com/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt;  &lt;span class="n"&gt;/etc/letsencrypt/live/coderscat.com/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;ssl_protocols&lt;/span&gt;        &lt;span class="s"&gt;TLSv1&lt;/span&gt; &lt;span class="s"&gt;TLSv1.1&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_ciphers&lt;/span&gt;          &lt;span class="s"&gt;ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt;  &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_session_cache&lt;/span&gt;    &lt;span class="s"&gt;shared:SSL:10m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_session_timeout&lt;/span&gt;  &lt;span class="mi"&gt;10m&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;h2&gt;
  
  
  Enable SELinux
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SELiunux&lt;/code&gt; stands for Security-Enhanced Linux, it is a Linux kernel security module that provides a mechanism for supporting access control security policies, including mandatory access controls (MAC).  It can prevent several attacks before your system being hacked.&lt;/p&gt;

&lt;p&gt;Install it on Ubuntu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;policycoreutils selinux-utils selinux-basics
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;selinux-activate
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;selinux-config-enforcing  &lt;span class="o"&gt;(&lt;/span&gt;Then reboot system&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sestatus &lt;span class="o"&gt;(&lt;/span&gt;query the status of SELinux&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clickjacking Attack
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.imperva.com/learn/application-security/clickjacking/"&gt;Clickjacking attack&lt;/a&gt;  will cause users to unwittingly download malware, visit malicious web pages, provide credentials or sensitive information.&lt;/p&gt;

&lt;p&gt;We can inject &lt;code&gt;X-FRAME-OPTIONS&lt;/code&gt; in HTTP Header to prevent a clickjacking attack(Even this can be bypassed in some ways). This is achieved by adding below in &lt;code&gt;nginx.conf&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"SAMEORIGIN"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above header will instruct a browser to load the resources ONLY from the same origin.&lt;/p&gt;

&lt;h3&gt;
  
  
  X-XSS Protection
&lt;/h3&gt;

&lt;p&gt;Inject HTTP Header with X-XSS protection to mitigate Cross-Site scripting attack. Modify &lt;code&gt;nginx.conf&lt;/code&gt; file to add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-XSS-Protection&lt;/span&gt; &lt;span class="s"&gt;"1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;mode=block"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the configuration file and restart Nginx. You can use the &lt;a href="https://gf.dev/http-headers-test"&gt;Headers Test&lt;/a&gt; tool to verify after implementation.&lt;/p&gt;

&lt;p&gt;You may also be interested in implementing OWASP recommended secure headers which are explained &lt;a href="https://geekflare.com/http-header-implementation/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://amzn.to/3f21Uwd"&gt;Mastering NGINX Second Edition&lt;/a&gt; is an excellent reference book for the introduction of Nginx.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>dveops</category>
      <category>nginx</category>
    </item>
  </channel>
</rss>
