<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://angrynerds.co/blog/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Blog</title>
    <link>https://angrynerds.co/blog</link>
    <description />
    <generator>Articulate, blogging built on Umbraco</generator>
    <item>
      <guid isPermaLink="false">4650</guid>
      <link>https://angrynerds.co/blog/how-can-custom-mobile-development-affect-your-business-s-growth/</link>
      <category>Business</category>
      <category>Culture</category>
      <category>Design</category>
      <category>Development</category>
      <title>How Can Custom Mobile Development Affect Your Business’s Growth?</title>
      <description>&lt;h3&gt;Firstly, what does custom development mean?&lt;/h3&gt;
&lt;p&gt;Custom app development is the process of creating applications that are especially suited to a company’s needs. Whether fully or partially personalized, it is designed to meet the demands of a specific target market rather than a large audience. &lt;/p&gt;
&lt;p&gt;According to Statista, there are more than &lt;a href="https://www.statista.com/statistics/330695/number-of-smartphone-users-worldwide/"&gt;six billion smartphone subscriptions&lt;/a&gt; worldwide, with this figure anticipated to rise by several hundred million in the next few years. Additionally, an average smartphone user actively goes on 10 apps per day. With the increased number of options and a decreasing attention span of users, it is essential to maintain a competitive advantage and showcase something unique that other apps cannot offer. &lt;/p&gt;
&lt;p&gt;There are two ways to go about building a &lt;a href="https://angrynerds.co/services/custom-development/"&gt;custom mobile application&lt;/a&gt;. One is to build a custom application from scratch, or to customize and build on existing software. Either way that you choose for your mobile application, brings a set of advantages that we will discuss in this article. &lt;/p&gt;
&lt;h4&gt;Core benefits of developing a custom application&lt;/h4&gt;
&lt;h4&gt;1. Scalability&lt;/h4&gt;
&lt;p&gt;The significant benefit of developing a mobile application for your brand is that it can expand with your business. Pre-built software frequently has a specific objective in mind, whether it is a small company start-up or a large enterprise. It is tough to locate a software that can effortlessly switch between the two. &lt;/p&gt;
&lt;p&gt;Custom development is an excellent option if you want to start small and observe how your business grows without constraints. Custom mobile applications will be ready to manage a bigger quantity of data and expand with your business after you've established your market position and begin scaling up.&lt;/p&gt;
&lt;h4&gt;2. A real representation of your brand’s identity&lt;/h4&gt;
&lt;p&gt;This is not to imply that mobile websites are unimportant. In fact, for greater flexibility, organizations could provide a compatible set of channels, including a mobile-friendly website and a mobile app, in order to be competitive. &lt;/p&gt;
&lt;p&gt;A custom-made application has the advantage of differing from any pre-made software. It may be hard to stay competitive if your application cannot implement unique features, which other businesses cannot offer. &lt;/p&gt;
&lt;p&gt;Custom mobile development makes it possible to create ideas and turn them into technologically feasible products. Whether you have a workout app or an on-demand delivery business, your brand’s identity should be truly represented through the application’s features and a seamless interface. &lt;/p&gt;
&lt;h4&gt;3. Building a connection with your users&lt;/h4&gt;
&lt;p&gt;The benefit of having a custom application is that there are no boundaries and limits when it comes to creating ways to interact with the app users. You can leverage the data that the user enters when creating an app account, and use it in order to personalize your customer service to the maximum. Implement the newest technology, such as live chatbots or personalized welcome messages, or pairing with external devices. &lt;/p&gt;
&lt;p&gt;Custom mobile development allows for a higher level of personalization and interaction with your audience also in a visual way, for example through photos, videos, or voice recognition and real-time tracking of the delivery process. Depending on your industry, the options are limitless when it comes to creating a real, personal experience for your users. &lt;/p&gt;
&lt;h4&gt;4.  Maintenance and control of the development process&lt;/h4&gt;
&lt;p&gt;Another advantage of custom mobile development is the bird’s eye view of the creation process. Rather than purchasing a ready off-the-shelf application, you can really engage with the development team and be a part of the creation process. &lt;/p&gt;
&lt;p&gt;Additionally, since you will know the team and the insights of your app, the maintenance process is going to be a lot more efficient and accessible. &lt;/p&gt;
&lt;h4&gt;How to create a successful custom mobile app?&lt;/h4&gt;
&lt;h4&gt;Find the right team&lt;/h4&gt;
&lt;p&gt;The first and most important aspect of custom development, is a creative and competent team, with a personal and open-minded approach. You are going to need a team, which is going to fully understand your creative idea and translate it into technology. &lt;/p&gt;
&lt;p&gt;Creating an application is not only about its functionality, but it serves as a medium to represent your brand’s identity. Your team should be able to understand you as a brand and represent that through an excellent UX/UI that goes hand in hand with your brand’s personality. &lt;/p&gt;
&lt;p&gt;From a seamless interface to the color scheme, visuals, and features. When choosing a provider, keep in mind their level of adaptability and interest in the concept and identity behind your brand, not only the technical aspects. &lt;/p&gt;
&lt;h4&gt;Follow the latest trends and customer demand&lt;/h4&gt;
&lt;p&gt;Research is crucial before starting to develop your custom application in order to determine whether your concept actually satisfies market demands. You can adapt your idea to fit the requirements of your niche, for instance, by incorporating features like connectivity with external devices or chatbots that can offer client support around-the-clock.&lt;/p&gt;
&lt;h4&gt;Specify the message that you want to convey through your app&lt;/h4&gt;
&lt;p&gt;Is the application supposed to be the main channel for your business, or more of an extension of your website? Before the development process, it is necessary to list down all the requirements for your application and make sure that you are clear in terms of your vision with the development team. Clear communication will allow them to create a product that truly visualizes the idea that you have in mind and exceeds your expectations. &lt;/p&gt;
&lt;p&gt;If you have an excellent idea in mind, but are not an expert in technology, contact one of our team members today and let us help you bring your custom mobile app vision to life. &lt;/p&gt;
</description>
      <pubDate>Thu, 20 Oct 2022 15:47:29 Z</pubDate>
      <a10:updated>2022-10-20T15:47:29Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">4607</guid>
      <link>https://angrynerds.co/blog/how-to-write-and-run-kotlin-script/</link>
      <category>Business</category>
      <category>Culture</category>
      <title>How to quickly write and run Kotlin script - practical guide</title>
      <description>&lt;p&gt;Recently, we completed a test with a large address book containing thousands of contacts. To have such a vast collection, we needed to generate a vCard file with random contacts.
​&lt;/p&gt;
&lt;p&gt;The easiest way to execute Kotlin code quickly in Android Studio project is by creating an empty Kotlin file, and typing &lt;code&gt;psvm&lt;/code&gt; to auto-generate main function (or &lt;code&gt;psvma&lt;/code&gt; for one with args). Inside it, we can write our Kotlin code. Last step is to click the green run button next to the main and viola — code is executed with the output presented.
​&lt;/p&gt;
&lt;p&gt;Since parameters should always be given via altering configuration in the &amp;quot;Program Arguments&amp;quot; area, it is not a simple or easily reproducible setup from my perspective.
​&lt;/p&gt;
&lt;p&gt;I came to the conclusion that it will be easier to have it in the form of an executable script from the command line. As Kotlin has that ability with &lt;code&gt;.kts&lt;/code&gt; (Kotlin script) files, I started looking for ways to achieve it in the fastest and simplest way possible. &lt;/p&gt;
&lt;p&gt;Following is the summary of my discoveries:&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;• What you need is &lt;code&gt;kotlin compiler&lt;/code&gt; in order to run our script from command line.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    brew update
    brew install kotlin
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;• As I’m using mac and brew, this command was the simplest to get, but if you have a different hardware/software setup, use these &lt;a href="https://kotlinlang.org/docs/command-line.html#install-the-compiler"&gt;instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;• Text editor - I’ve just used Android Studio, but anything that understands Kotlin will be enough.&lt;/p&gt;
&lt;h2&gt;Script&lt;/h2&gt;
&lt;p&gt;There are several ways of creating and running scripts with Kotlin. The easiest one to use is called &lt;strong&gt;Kotlin-main-kts&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Let’s create the easiest hello-world script with it:&lt;/p&gt;
&lt;p&gt;• create file with &lt;code&gt;.main.kts&lt;/code&gt; extension e.g. &lt;code&gt;helloworld.main.kts&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;• add “header” as a first line to indicate it should be our Kotlin script &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   #!/usr/bin/env kotlin
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
• below it insert your script content e.g. &lt;code&gt;println(&amp;quot;Hello world.&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;• make your file executable with &lt;code&gt;chmod +x helloworld.main.kts&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;• now you can run your script with standard command of running executable files &lt;code&gt;./hellowrold.main.kts&lt;/code&gt; — &lt;strong&gt;remember that in order to run it, other people will also need to install Kotlin compiler&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Arguments&lt;/h2&gt;
&lt;p&gt;Arguments are accessible right away by calling &lt;code&gt;args&lt;/code&gt; e.g. &lt;code&gt;args[0]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;No main function needed as we’re inside of it. So all code is wrote top-level like.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (args.size != 2) {
    println(&amp;quot;Please specify exactly 2 arguments in this example&amp;quot;)
} else {
    println(&amp;quot;Your arguments are: ${args[0]}, ${args[1]}&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;Now run it with: &lt;code&gt;./helloworld.main.kts “Hello” “World”&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Which is equivalent to: &lt;code&gt;kotlinc -script helloworld.main.kts &amp;quot;Hello&amp;quot; &amp;quot;World&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;That’s it - quick and easy to use or run.&lt;/p&gt;
&lt;p&gt;For a curious real-life yet very basic example here’s our vCard file generating script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/env kotlin

import java.io.File

fun generateVCard(numberOfContacts: Int): String {
    val vCard: StringBuilder = StringBuilder()
    (1..numberOfContacts).forEach { number -&amp;gt;
        vCard.append(
            &amp;quot;&amp;quot;&amp;quot;
            BEGIN:VCARD
            VERSION:3.0
            PRODID:-//Apple Inc.//macOS 12.4//EN
            N:Surname$number;Name$number;;;
            FN:Name$number Surname$number
            TEL;type=CELL;type=VOICE;type=pref:+48 101 000 $number
            END:VCARD

            &amp;quot;&amp;quot;&amp;quot;.trimIndent()
        )
    }
    return vCard.toString()
}

if (args.size != 1) {
    println(&amp;quot;No argument. Please specify number and try again&amp;quot;)
} else {
    val numberOfContacts = args[0].toIntOrNull()

    if (numberOfContacts == null) {
        println(&amp;quot;Specified number is not Integer, please try again&amp;quot;)
    } else {
        println(&amp;quot;Executing script&amp;quot;)

        val vCard = generateVCard(numberOfContacts)

        File(&amp;quot;contacts$numberOfContacts.vcf&amp;quot;).writeText(vCard)

        println(&amp;quot;Generating vCard completed.&amp;quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/marczewski-krzysztof/"&gt;Krzysztof Marczewski&lt;/a&gt; is an Android Developer at Angry Nerds, focused on developing great code and constantly growing his tech skills.
Delighted with Kotlin, Compose, and multiplatform. Non-fiction bookworm who loves minimal UI, smart UX, and clever copywriting. He writes his development-related blog - &lt;a href="https://selfformat.com/"&gt;https://selfformat.com/&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Tue, 30 Aug 2022 15:47:29 Z</pubDate>
      <a10:updated>2022-08-30T15:47:29Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">4413</guid>
      <link>https://angrynerds.co/blog/github-copilot-ai-pair-programming-review-of-reviews/</link>
      <category>Development</category>
      <title>Reviewing GitHub Copilot Reviews - Is AI Pair Programming Worthwhile?</title>
      <description>&lt;p&gt;Will AI replace programmers? When GPT-3 from OpenAI came along, it was most visibly praised for &lt;a href="https://www.theguardian.com/commentisfree/2020/sep/08/robot-wrote-this-article-gpt-3" target="_blank"&gt;writing human-like articles&lt;/a&gt;. At the same time, many programmers used GPT-3 to write HTML and CSS, or do things like &lt;a href="https://blog.seekwell.io/gpt3" target="_blank"&gt;program SQL database requests&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The hype for AI pair programming started gaining steam, and then &lt;a href="https://copilot.github.com/" target="_blank"&gt;GitHub’s Copilot&lt;/a&gt; came out. The heart of Copilot is an engine that predicts code. It’s based on OpenAI Codex (GPT-3’s kid with a special knack for programming), it's trained on public code from all of GitHub’s users, and it's controversial.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.infoworld.com/article/3627319/github-copilot-is-unacceptable-and-unjust-says-free-software-foundation.html" target="_blank"&gt;The Free Software Foundation even called it “unacceptable and unjust”&lt;/a&gt;, bringing into light many important issues. For example, &lt;strong&gt;if Copilot gives you code that’s exactly the same as someone else’s, aren’t you breaking copyright?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s a tricky, legally unregulated area. GitHub responded to criticism very positively, with a statement that they are “&lt;em&gt;keen to engage in a discussion with developers on these topics and lead the industry in setting appropriate standards for training AI models&lt;/em&gt;”. &lt;/p&gt;
&lt;p&gt;Copilot was released in July, the criticism from FSF was back in August, and now we’re nearing the end of 2021. &lt;strong&gt;How is Copilot doing, and has GitHub kept its promises?&lt;/strong&gt; To find out, we're going to review several reviews published online by different tech experts.&lt;/p&gt;
&lt;h2&gt;GitHub Copilot’s Limitations 🤖&lt;/h2&gt;
&lt;p&gt;Copilot is paving the way towards AI programmers. There are &lt;a href="https://sourceforge.net/software/product/GitHub-Copilot/alternatives" target="_blank" rel="nofollow"&gt;at least ten alternatives&lt;/a&gt;, but for the time being, GitHub’s product is the most hyped up.&lt;/p&gt;
&lt;p&gt;Nonetheless, &lt;strong&gt;Copilot has limitations&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It comes as an add-on to only a few most popular code editors;&lt;/li&gt;
&lt;li&gt;It’s free, but there’s a waitlist to get access;&lt;/li&gt;
&lt;li&gt;It’s still a technical preview version, not a complete product.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the time being, Copilot isn’t a great, well-rounded programmer in its own right. It’s more of a helper. It watches what you’re doing and suggests different options to push your coding along.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/2750/angry-coffee-and-github-copilot.png" alt="Screens with code on them and a cup of angry coffee" /&gt;&lt;/p&gt;
&lt;p&gt;Sometimes it writes decent code for you. Other times it writes bad code:&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;You absolutely need to review the code that Copilot generates. Treat it as though it was written by a green programmer intern who is good with Google searches but needs close supervision.&lt;/em&gt;” - &lt;a href="https://www.infoworld.com/article/3639552/github-copilot-preview-gives-me-hope.html" target="_blank"&gt;Martin Heller, InfoWorld&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main promise of AI engines, like the one that powers Copilot, is that they get better with time. As users keep generating new data, Copilot will keep getting smarter. &lt;/p&gt;
&lt;p&gt;At the moment, you can’t just unleash Copilot on your code and let it rip. &lt;strong&gt;Human review is still a critical element to ensure that AI-generated code is OK&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;That 'human in the loop' review stage is important to the responsible use of large language models because it's a way to catch a problem before [...] the code goes into production. Code licences are one issue when it comes to writing code, but AI-generated text could create all sorts of headaches, some embarrassing and some more serious.&lt;/em&gt;” - &lt;a href="https://www.zdnet.com/article/why-ai-still-needs-humans-in-the-loop-at-least-for-now/" target="_blank"&gt;Mary Branscombe, ZDNet&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Expert reviews of Copilot and AI pair programming 💬&lt;/h2&gt;
&lt;p&gt;Whenever there’s a lot of hype around something, it’s good to seek out level-headed people that can offer perspective on the subject.&lt;/p&gt;
&lt;p&gt;Just by looking at the stats, it seems that Copilot is doing great. &lt;a href="https://www.axios.com/copilot-artificial-intelligence-coding-github-9a202f40-9af7-4786-9dcb-b678683b360f.html" target="_blank"&gt;GitHub reportedly found on their platform that&lt;/a&gt; “&lt;em&gt;about 30% of newly written code is being suggested by [...] Copilot&lt;/em&gt;”. Plus, half the developers who tried Copilot kept on using it regularly.&lt;/p&gt;
&lt;p&gt;To further understand why the industry seems to be liking AI pair programming and GitHub Copilot, let’s see what tech experts are saying about it online.&lt;/p&gt;
&lt;h3&gt;“&lt;em&gt;Feels quite magical to use&lt;/em&gt;” 🔮&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.fast.ai/2021/07/19/copilot/" target="_blank"&gt;Jeremy Howard, a founding researcher at fast.ai&lt;/a&gt;, sees Copilot as a blessing on one hand and a potential curse on the other.&lt;/p&gt;
&lt;p&gt;He notes that Copilot isn’t the first AI-powered pair programmer but it’s the most powerful so far, because “it can generate entire multi-line functions and even documentation and tests, based on the full context of a file of code”.&lt;/p&gt;
&lt;p&gt;“&lt;em&gt;The code Copilot writes is not very good code&lt;/em&gt;”, 
however, 
“&lt;em&gt;complaining about the quality of the code written by Copilot feels a bit like coming across a talking dog, and complaining about its diction. The fact that it’s talking at all is impressive enough!&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;Mr Howard explains that Copilot is kind of doomed to be inaccurate. The reason lies at the heart of how AI models like this work. Copilot doesn’t understand whether the code is good or not. But it has analyzed endless codebases similar to yours, so it can predict what your code should look like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You’re going to have to edit Copilot’s code down, though:&lt;/strong&gt; 
“&lt;em&gt;Copilot’s code is verbose, and it’s so easy to generate lots of it that you’re likely to end up with a lot of code!&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;Copilot might be a good thing, but there’s a possibility that &lt;strong&gt;it could wreck your project with a sort of death by a thousand cuts&lt;/strong&gt;:
“&lt;em&gt;For those for whom it’s a curse, they may not find that out for years, because the curse would be that they’re learning less, learning slower, increasing technical debt, and introducing subtle bugs – are all things that you might well not notice, particularly for newer developers&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/2751/robot-representing-ai-programmer.png" alt="robot with nerd hat representing ai pair programmer" /&gt;&lt;/p&gt;
&lt;p&gt;Ultimately, for Mr Howard, Copilot didn’t fulfil the promise of being an AI pair programmer right after launch (his review is from July). But it was still a huge step for code-generating language models. Plus, it was already visibly useful in some niche areas, like helping coders get comfortable with a new programming language.&lt;/p&gt;
&lt;p&gt;If we want AI that writes code fully by itself, “&lt;em&gt;we’ll need to go beyond just language models, to a more holistic solution that incorporates best practices around human-computer interaction, software engineering, testing, and many other disciplines&lt;/em&gt;”.&lt;/p&gt;
&lt;h3&gt;“&lt;em&gt;It's not gonna take our jobs anytime soon&lt;/em&gt;” 🙅‍♀️&lt;/h3&gt;
&lt;p&gt;In a &lt;a href="https://the-stack-overflow-podcast.simplecast.com/episodes/github-copilot-can-write-code-for-you-we-put-it-to-the-test" target="_blank"&gt;review from the Stack Overflow Podcast crew&lt;/a&gt;, we hear that Copilot is great for boilerplate code (repetitive, non-creative things you need to write to enable standard functionalities), but “&lt;em&gt;if you start doing anything more complex than that, that's when you start to say, okay, you need to calm down Copilot&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;Another reviewer on the podcast thinks “&lt;em&gt;it's actually very aptly named Copilot because you are supposed to be the pilot, and you're supposed to write most of the code&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;Throughout the episode, reviewers echo the sentiment that &lt;strong&gt;Copilot is great for those standard things that developers always have to Google&lt;/strong&gt;. The small things that developers have written millions of times in the same way, so Copilot doesn’t have any issue knowing what the best option is. &lt;/p&gt;
&lt;p&gt;One of the reviewers is convinced that Copilot is “&lt;em&gt;a lot like the Gmail autocomplete&lt;/em&gt;”. Just like Gmail finishes phrases like 'All the best' for you, Copilot is great as an autocomplete for developers. &lt;/p&gt;
&lt;p&gt;It seems that Copilot didn’t amaze the Stack Overflow Podcast crew with its capabilities, but it was definitely an impressive prequel to the future of AI pair programming. &lt;/p&gt;
&lt;p&gt;Just like the first one, this review is from July. So &lt;strong&gt;now let’s check out a fresh review from November 13, 2021.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;”&lt;em&gt;Productivity boost that will most likely create more jobs&lt;/em&gt;” 💪&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=PDNt07UePvk" target="_blank"&gt;Programmer / YouTuber sentdex&lt;/a&gt; notes that Copilot’s engine is much lighter than GPT-3 (12 billion parameters compared to 175 billion parameters), so it’s much faster to run.&lt;/p&gt;
&lt;p&gt;GPT-3 had a limit of 4kb for context file weight. Copilot has a limit of 14kb which, as sentdex shows, is about 400 lines of code. To be clear, &lt;strong&gt;Copilot will still work on files bigger than that, but it can only take those 400 lines of code as its context for code prediction&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;He goes on to show proof that Copilot has some deeper understanding of the code, it’s not just pattern-matching code lines to each other, because it can predict the outputs of functions with perfect accuracy.&lt;/p&gt;
&lt;p&gt;Ultimately, &lt;strong&gt;sentdex sees Copilot as another layer of abstraction from code&lt;/strong&gt;. He compares it to using Python instead of C++:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;with Python, you can build bigger things faster because you’re using bigger, ready-made blocks;&lt;/li&gt;
&lt;li&gt;with C++, you have to specify every tiny detail in your code and build your own blocks, so it takes longer to build big things.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/2748/ai-pair-programmer-as-duckie-in-post.png" alt="Cute duckie represents AI pair programmer" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This makes Copilot a great productivity boost&lt;/strong&gt;. Sentdex has a refreshing perspective, saying that tools like Copilot won’t kick programmers out of their jobs. Instead, AI pair programmers will be a way for software developers to build more things, get more experience, and increase their value on the market. &lt;/p&gt;
&lt;p&gt;Another great thing that sentdex found in his review is that Copilot fosters fast learning. When sentdex wanted to check out a new code library, he just wrote a prompt and Copilot guided him through using that library. &lt;strong&gt;It even showed him methods that he didn’t know existed&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Normally developers need to go through pages of documentation and several Stack Overflow threads when starting to use a new tool. Having an AI friend give you a quickstart guide instead of doing all of that research has to be &lt;strong&gt;very convenient&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;When it comes to limitations, sentdex noticed that Copilot makes mistakes. It doesn’t always understand your intention. Just like with Googling, &lt;strong&gt;writing prompts that get Copilot to do exactly what you want is a skill that takes time to learn&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ultimately, sentdex admits that he generally doesn’t like tools like this so he didn’t expect to like Copilot. However, &lt;strong&gt;he was very positively surprised and found Copilot very useful, and perfect for increasing productivity as a software developer&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Decent assistant, long way from replacement 🚧&lt;/h2&gt;
&lt;p&gt;The general consensus seems to be that &lt;strong&gt;Copilot is a great tool that can enhance your productivity, but it won’t solve all of your problems for you, and you’ll probably need to edit Copilot’s code quite a bit&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But, if you’re a software developer who's willing to take advice from a robot assistant, you might just:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;learn new things quicker than before, &lt;/li&gt;
&lt;li&gt;enhance your productivity,&lt;/li&gt;
&lt;li&gt;increase your value on the software development market.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Copilot, along with its biggest competitors, opened the door towards mass adoption of AI programming assistants. It’s unlikely that these systems will make programmers obsolete. Plus, this technology is still limited. To replace programmers, we would need powerful Artificial General Intelligence (AGI), meaning systems that think like humans. &lt;/p&gt;
&lt;p&gt;We’re still far from developing technology like this. And, if almost all of science-fiction is to be believed, the development of AGI would cause problems much bigger than unemployment among programmers—leaving even fewer reasons to worry about it.&lt;/p&gt;
</description>
      <pubDate>Fri, 19 Nov 2021 17:30:00 Z</pubDate>
      <a10:updated>2021-11-19T17:30:00Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3684</guid>
      <link>https://angrynerds.co/blog/css-tips-and-tricks-for-text-based-content/</link>
      <category>Development</category>
      <title>CSS tips and tricks for text-based content</title>
      <description>&lt;p&gt;This is why today, instead of exploring advanced Javascript’s logic, Typescript’s shadows, and new versions of Angular, we want to get back to basics and share with you some useful tricks in CSS that can help you improve and speed up your daily work with styling text content.&lt;/p&gt;
&lt;h2&gt;Selectors&lt;/h2&gt;
&lt;p&gt;There are a lot of available selectors in CSS that can specify the exact element you want to style. We chose a few to show you their power - and inspire you to discover more.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; in the selector selects the direct child of the element. It’s very useful for example when you want to change the styles of paragraphs in a particular section. 
The below code will change styles of paragraphs only if they’re direct children of the .sidebar container.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.sidebar &amp;gt; p
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
&lt;code&gt;+&lt;/code&gt; in the selector selects only the adjacent sibling of the first element. The below code will change styles of the paragraph which is placed directly after the .sidebar container, but not inside of it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.sidebar+p 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
You can also use &lt;code&gt;+&lt;/code&gt; with &lt;code&gt;*&lt;/code&gt; sign and easily select all paragraphs on your website.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*+p
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
&lt;code&gt;:first-letter&lt;/code&gt; added to a selector will change the style of the first letter only and make a drop cap.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p:first-letter {
color: #07072d;
display: block;
font-size: 3em;
float: left;
margin: 0 3px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2118/dropcap.png"&gt;
&lt;/div&gt;
&lt;p&gt;In the most common cases &lt;code&gt;:nth-child()&lt;/code&gt; is used by developers with static value (&lt;code&gt;:nth-child(2)&lt;/code&gt;) to select the exact child of the element. But did you know that you can use this selector also with an expression? For instance, if you have a leaderboard and want to change the font color of the top three you can simply select them by:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:nth-child(-n + 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="display: block; width: 200px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2117/leaderboard.png"&gt;
&lt;/div&gt;
&lt;h2&gt;Counters&lt;/h2&gt;
&lt;p&gt;Counters in CSS allow you to automatically number the elements on the website based on how many times they’re used. There are a few simple rules you should know before starting using counters:&lt;/p&gt;
&lt;p&gt;→ Counters should be initialized by counter-reset property (0 by default):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;counter-reset: section;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
→ You have to specify the value of the element which should increment the counter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;counter-increment: section;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
 → You have to set the counters’ content: &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content: &amp;quot;Section no. &amp;quot; counter(section) &amp;quot;: &amp;quot;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
→ To combine counters in nested lists use counters() method and join counters into one value: &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content: counter(section) &amp;quot;.&amp;quot; counter(article) &amp;quot; &amp;quot;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
Here’s the result - all the characters in orange are made with CSS only:&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2123/counters.png"&gt;
&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;Shape-outside&lt;/h2&gt;
&lt;p&gt;A wall of text looks boring and you want to add some pictures to your article without interrupting users’ reading? The &lt;code&gt;shape-outside&lt;/code&gt; property will be helpful in blending the content together.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shape-outside: inset(70px 0px 60px 0px);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2119/shape1.png"&gt;
&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;At first look, it doesn’t look very special but imagine you can mix it with clip-path property and adjust text and indentations to every shape you can think of - isn’t it cool?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shape-outside: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2122/shape2.png"&gt;
&lt;/div&gt;
&lt;h2&gt;Line-clamp&lt;/h2&gt;
&lt;p&gt;Small wrapper and a lot of text? To avoid breaking the layout you need to cut the text and make it fit the size of the container.
You can do it simply by &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
and change this:&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2120/lineclamp1.png"&gt;
&lt;/div&gt;
&lt;p&gt;into this:&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2124/lineclamp2.png"&gt;
&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Nice, but we clipped a lot of content and now it’s almost unreadable for the user. If you want to cut the text, e.g. after the 3rd line, it’ll be a little challenging to do it this way. Of course, you can do it once and reuse the code every time you need, but you can also just use the &lt;code&gt;line-clamp&lt;/code&gt; property and effortlessly achieve this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-webkit-line-clamp: 3;
-webkit-box-orient: vertical;  
display: -webkit-box;
overflow: hidden;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2121/lineclamp3.png"&gt;
&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;::selection&lt;/h2&gt;
&lt;p&gt;Do you know that you can change the styles of the text highlighted by the user? Using pseudo-class &lt;code&gt;::selection&lt;/code&gt; you can change styles to whatever you want and make your website more customized, consistent - and simply cool!&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2127/selection1.gif"&gt;
&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2126/selection2.gif"&gt;
&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;h5&gt;Hope you enjoyed these CSS tips and tricks! We encourage you to try them out and see for yourself how they can make your work easier and more enjoyable. Let us know if you have any questions or want to share your thoughts!&lt;/h5&gt;
&lt;h3&gt;Happy styling 🎨&lt;/h3&gt;
&lt;h4&gt;You may be also interested in:&lt;/h4&gt;
&lt;p&gt;➤ &lt;a href="/blog/how-to-optimize-angular-app/" target="_blank"&gt;How to optimize an Angular app. 13 tips for front-end developers&lt;/a&gt;&lt;br /&gt;
➤ &lt;a href="/blog/8-useful-chrome-extensions-for-front-end-developers-and-a-bonus/" target="_blank"&gt;8 useful Chrome extensions for front-end developers&lt;/a&gt;&lt;br /&gt;
➤ &lt;a href="/blog/automating-repetitive-actions-with-selenium-webdriver-and-nodejs/" target="_blank"&gt;Automating repetitive actions with Selenium WebDriver and Node.js&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/weronikaszymanska/" target="_blank"&gt;Weronika Szymańska&lt;/a&gt; is a front-end developer at Angry Nerds – which means her job is to reconcile our designers’ unlimited imagination with equally unrestrained ideas of back-end devs. And she’s great at it! She has strong experience in JavaScript and Angular development and loves to share tips and tricks she uses in her daily work. When she's not coding, she can be found hiking in the mountains or reading crime stories. &lt;/p&gt;
</description>
      <pubDate>Mon, 07 Dec 2020 09:59:06 Z</pubDate>
      <a10:updated>2020-12-07T09:59:06Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3620</guid>
      <link>https://angrynerds.co/blog/chain-of-responsibility-design-pattern-with-examples/</link>
      <category>Development</category>
      <title>Chain of Responsibility design pattern – with examples</title>
      <description>&lt;p&gt;Design patterns can be divided into three groups: &lt;strong&gt;creational, structural, and behavioral.&lt;/strong&gt; Chain of Responsibility belongs to the behavioral one – which is a group of design patterns that help with better interaction between objects in your code. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;TIP:&lt;/b&gt; There is a classic book discussing this topic and describing 23
design patterns - &amp;quot;Design Patterns: Elements of Reusable
Object-Oriented Software&amp;quot;. You should definitely read it if you are
not familiar with the matter.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div align="center"&gt;
&lt;img alt="design patterns" src="https://i.pinimg.com/736x/26/8a/61/268a61596644fced06fd40f75f09e450.jpg"&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;Let's learn more about the Chain of Responsibility with some practical examples&lt;/h3&gt;
&lt;p&gt;The Chain of Responsibility pattern is used to replace statements like &lt;em&gt;if ... else if ... else&lt;/em&gt; with more object-oriented form. Let's consider calculating a tax amount that is different for each country. The first version of the method handling this calculation could look like this:&lt;/p&gt;
&lt;p&gt;&lt;script src="https://gist.github.com/angrynerds-marcin/5a7ae52dccd9469086dd3e0a7e2d5f6e.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;It does not look that complicated, but the code can easily become longer and more laborious with time. In the next version, the tax may be calculated differently for various types of products, we may also have more countries that we want to calculate tax for. Moreover, at some point in the future, the law may be changed and that will result in different formulas based on date. This is a perfect example to use the Chain of Responsibility pattern. Take a look at the tax calculation problem implemented with this pattern:&lt;/p&gt;
&lt;p&gt;&lt;script src="https://gist.github.com/angrynerds-marcin/786b79f41fe3db7433f96ffb17cc342e.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;In this version, we don't have five &lt;em&gt;if&lt;/em&gt; statements in one method and each type of tax is calculated by its own class. That way our code follows the Single Responsibility Principle, which is &lt;strong&gt;one of the most important rules in clean coding&lt;/strong&gt;. To use these new classes, we have to create an instance of each class and set value for &lt;code&gt;Next&lt;/code&gt; property. See an example here:&lt;/p&gt;
&lt;p&gt;&lt;script src="https://gist.github.com/angrynerds-marcin/404309e81f5e68a14aa48d7f35f339fd.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;If you had trouble with understanding how it works, I recommend you set a breakpoint and use a debugger to check which instructions are executed.
​&lt;br /&gt;&lt;br /&gt;
Here is another example – an algorithm that recommends you the next video to watch based on your age. This is a really simple example because it always returns the same video, but it fits nicely into the Chain of Responsibility pattern.&lt;/p&gt;
&lt;p&gt;&lt;script src="https://gist.github.com/angrynerds-marcin/3dd10dda361c43b576a6980d3654556b.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;And the third example – it's the code for an ATM that checks if it can dispense cash using a finite number of notes inside the machine. In this case, we will have just one implementation of an abstract class, but we will define a chain consisting of three links using that one class.&lt;/p&gt;
&lt;p&gt;&lt;script src="https://gist.github.com/angrynerds-marcin/9e3571ba29bf891d7d13ae4846fa05ec.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;Here is how we can use it:&lt;/p&gt;
&lt;p&gt;&lt;script src="https://gist.github.com/angrynerds-marcin/d3943e64c22ba097da86c04de8858585.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;​
By now, I think you have already grasped the concept of the Chain of Responsibility pattern. Here is a class diagram and a sequence diagram that presents it:&lt;/p&gt;
&lt;div style="display: block; width: 700px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2082/w3sdesign_chain_of_responsibility_design_pattern_uml.jpg"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;i&gt;Photo via &lt;a href="https://upload.wikimedia.org/wikipedia/commons/6/6a/W3sDesign_Chain_of_Responsibility_Design_Pattern_UML.jpg" target="_blank" rel="nofollow"&gt;Wikimedia Commons&lt;/a&gt;&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
​&lt;/p&gt;
&lt;h3&gt;Chain of Responsibility vs other patterns&lt;/h3&gt;
&lt;h4&gt;Chain of Responsibility vs Decorator&lt;/h4&gt;
&lt;p&gt;The Chain of Responsibility design pattern may appear similar to the Decorator design pattern but the key difference is that the former can be stopped at any part of the processing, and the latter executes all steps (assuming that passed data was valid and it didn't throw an exception). Decorator adds something with each step.
​&lt;/p&gt;
&lt;h4&gt;Chain of Responsibility vs Strategy&lt;/h4&gt;
&lt;p&gt;With the Chain of Responsibility pattern, each object is responsible for executing an action on the next object, whereas, with the Strategy pattern, the client of that code has to decide which implementation should be used.
​&lt;/p&gt;
&lt;h3&gt;What next?&lt;/h3&gt;
&lt;p&gt;I strongly recommend you to read the book mentioned in the intro: &lt;em&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/em&gt;. You can also watch a &lt;a href="https://www.pluralsight.com/paths/design-patterns-in-c"&gt;series of courses on Pluralsight&lt;/a&gt; in the design patterns path. There is also a fun experiment that you can check out on GitHub: &lt;a href="https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition"&gt;FizzBuzz Enterprise Edition&lt;/a&gt; is a no-nonsense implementation of FizzBuzz made by serious businessmen for serious business purposes.&lt;/p&gt;
&lt;h3&gt;Feel free to share your thoughts or questions in the comments!&lt;/h3&gt;
&lt;h4&gt;You may be also interested in:&lt;/h4&gt;
&lt;p&gt;➤ &lt;a href="/blog/11-extremely-useful-git-commands-every-developer-should-know/" target="_blank"&gt;11 extremely useful Git commands every developer should know&lt;/a&gt;&lt;br /&gt;
➤ &lt;a href="/blog/avoiding-anemic-domain-model/" target="_blank"&gt;Avoiding Anemic Domain Model&lt;/a&gt;&lt;br /&gt;
➤ &lt;a href="/blog/master-your-git-log-with-conventional-commits-in-6-steps/" target="_blank"&gt;Master your git log with Conventional Commits in 6 steps&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/marcin-zarebski/" target="_blank"&gt;Marcin Zarębski&lt;/a&gt; is an experienced back-end developer, specializing in. .NET platform. He has amazing skills in building complex backend solutions and infrastructure. Marcin is also interested in space exploration and the role of computer science in it. He likes to spend his free time in the mountains or playing board games. &lt;/p&gt;
</description>
      <pubDate>Mon, 31 Aug 2020 10:04:59 Z</pubDate>
      <a10:updated>2020-08-31T10:04:59Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3567</guid>
      <link>https://angrynerds.co/blog/avoiding-anemic-domain-model/</link>
      <category>Development</category>
      <title>Avoiding Anemic Domain Model</title>
      <description>&lt;p&gt;&lt;strong&gt;Anemic Domain Model&lt;/strong&gt; is a software pattern where classes representing domain objects contain only data and little or no logic in methods. Does it sound familiar? Maybe it is a consequence of using one of the most popular ways of organizing application logic into layers.
&lt;br&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;img src="https://angrynerds.co/media/2051/layers.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
You see the data layer and it may be quite natural to think of this as a table in a relational database. It is true that the objects from the data layer will be often used to preserve some data in a relational database but additional work is required to send data from those objects. The bottom line is that objects are not tables. 
&lt;br&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;img src="https://angrynerds.co/media/2052/meme.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
Using Anemic Domain Models is a direct violation of one of the core concepts in object-oriented programming. Having Anemic Domain Models leads to code duplication and a lack of encapsulation. Check out &lt;a href="https://martinfowler.com/bliki/AnemicDomainModel.html"&gt;this excellent blog post&lt;/a&gt; by Martin Fowler. Let's see some examples. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;All examples in this post are in C#.&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Company
{
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal ShareCapital { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
&lt;code&gt;Company&lt;/code&gt; class is used by a service layer to create/update new companies, and that service is injected in some API controller. &lt;code&gt;CompanyService&lt;/code&gt; class contains the necessary logic - here is a draft of that service. Let's omit the controller class as it is straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class CompanyService
{
    public void Create(CreateCompanyModel model)
    {
        if (!string.IsNullOrWhiteSpace(model.Name))
        {
            throw new Exception(&amp;quot;name is required&amp;quot;);
        }

        Company company = new Company
        {
            Id = ... //generate Id
            CreatedAt = DateTime.UtcNow,
            Name = model.Name
        };

        // save company in database
    }

    public void Update(UpdateCompanyModel model)
    {
        // validate model if necessary

        Company company = ... // get company from database
        company.Description = model.Description;
        company.ShareCapital = model.ShareCapital;

        // update company in database
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Potentially, there could be a couple of scenarios where new companies will be created or updated. Maybe we want to create a Business Corporation by following a different path than the path for General Partnership or a Limited Liability Company. This is something that will be defined by business needs. &lt;/p&gt;
&lt;p&gt;Right now, there is nothing in the &lt;code&gt;Company&lt;/code&gt; class that helps you understand what are the required properties and what are the optional properties. There are no validation rules included. Probably the &lt;code&gt;Name&lt;/code&gt; and &lt;code&gt;CreatedAt&lt;/code&gt; should be required - and it may be obvious to someone but when you have a model with 20 properties it may be harder to choose a subset of required properties. &lt;/p&gt;
&lt;p&gt;Moreover, sometimes properties' values could be automatically deduced when a new instance is created, e.g. &lt;code&gt;CreatedAt&lt;/code&gt; seems like something that could be set behind the scenes. If only we defined a constructor, we would make creating a company easier. We could replace the above code with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Company
{
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal ShareCapital { get; set; }

    public Company(string name)
    {
        if (!string.IsNullOrWhiteSpace(name))
        {
            throw new Exception(&amp;quot;name is required&amp;quot;);
        }

        Id = ... //generate Id
        Name = name;
        CreatedAt = DateTime.UtcNow;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Now our client can't create a new company using default constructor without &lt;code&gt;Name&lt;/code&gt; or &lt;code&gt;CreatedAt&lt;/code&gt; values. This is good because it is a business rule that we want to enforce in our domain. However, he can still update &lt;code&gt;Name&lt;/code&gt; or &lt;code&gt;CreatedAt&lt;/code&gt; date. Does it make sense? As always, it depends. Let's assume that business rule is that we should change neither &lt;code&gt;CreatedAt&lt;/code&gt; nor &lt;code&gt;Name&lt;/code&gt; values. To do that, we will replace public setters with private setters in &lt;code&gt;Company&lt;/code&gt; class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Company
{
    public int Id { get; private set; }
    public DateTime CreatedAt { get;  private set; }
    public string Name { get;  private set; }
    public string Description { get;  private set; }
    public decimal ShareCapital { get; private set; }

    public Company(string name)
    {
        if (!string.IsNullOrWhiteSpace(name))
        {
            throw new Exception(&amp;quot;name is required&amp;quot;);
        }

        Id = ... //generate Id
        Name = name;
        CreatedAt = DateTime.UtcNow;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
A new problem arose that has to be addressed. In this version, we cannot set value for optional properties &lt;code&gt;Description&lt;/code&gt; and &lt;code&gt;ShareCapital&lt;/code&gt;. To fix that, we will add new methods: &lt;code&gt;UpdateDescription&lt;/code&gt;, &lt;code&gt;UpdateShareCapital&lt;/code&gt;. The idea is that for specific scenarios we want to have separate methods that will act accordingly. In more complex scenarios such a method would do more than setting value for one property, e.g. set more values, like the last update date.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Company
{
    public int Id { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public string Name { get; private set; }
    public string Description { get; private set; }
    public decimal ShareCapital { get; private set; }

    public Company(string name)
    {
        if (!string.IsNullOrWhiteSpace(name))
        {
            throw new Exception(&amp;quot;name is required&amp;quot;);
        }

        Id = ... //generate Id
        Name = name;
        CreatedAt = DateTime.UtcNow;
    }

    public void UpdateDescription(string description)
    {
        Description = description;
    }

    public void UpdateShareCapital(decimal shareCapital)
    {
        ShareCapital = shareCapital;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Another advantage of this approach is discoverability - i.e. when you look at the object, you discover what you can do with that object. With an Anemic Domain Model, this is harder and potentially more confusing.&lt;/p&gt;
&lt;h3&gt;Value objects&lt;/h3&gt;
&lt;p&gt;We will define the concept of value objects that are useful building blocks in creating rich domain models. Eric Evans defines value objects this way: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An object that represents a descriptive aspect of the domain with no
conceptual identity is called a VALUE OBJECT. VALUE OBJECTS are
instantiated to represent elements of the design that we care about
only for what they are, not who or which they are.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;[Excerpt from &amp;quot;Domain-Driven Design: Tackling Complexity in the Heart of Software&amp;quot;, p. 59]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Examples of value objects are numbers, strings, money, addresses, colors, etc. When you think about it, there is quite a natural distinction between entities and value objects. For example, if you have a product that costs $100, it doesn't matter which $100 it is. When you design a value object, you have to make them immutable. Fulfilling the immutability requirement can be a little tedious. We will use value object implementation proposed by msdn (check &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/implement-value-objects"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public abstract class ValueObject
{
    protected static bool EqualOperator(ValueObject left, ValueObject right)
    {
        if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
        {
            return false;
        }
        return ReferenceEquals(left, null) || left.Equals(right);
    }

    protected static bool NotEqualOperator(ValueObject left, ValueObject right)
    {
        return !(EqualOperator(left, right));
    }

    protected abstract IEnumerable&amp;lt;object&amp;gt; GetAtomicValues();

    public override bool Equals(object obj)
    {
        if (obj == null || obj.GetType() != GetType())
        {
            return false;
        }

        ValueObject other = (ValueObject)obj;
        IEnumerator&amp;lt;object&amp;gt; thisValues = GetAtomicValues().GetEnumerator();
        IEnumerator&amp;lt;object&amp;gt; otherValues = other.GetAtomicValues().GetEnumerator();
        while (thisValues.MoveNext() &amp;amp;&amp;amp; otherValues.MoveNext())
        {
            if (ReferenceEquals(thisValues.Current, null) ^
                ReferenceEquals(otherValues.Current, null))
            {
                return false;
            }

            if (thisValues.Current != null &amp;amp;&amp;amp;
                !thisValues.Current.Equals(otherValues.Current))
            {
                return false;
            }
        }
        return !thisValues.MoveNext() &amp;amp;&amp;amp; !otherValues.MoveNext();
    }

    public override int GetHashCode()
    {
        return GetAtomicValues()
         .Select(x =&amp;gt; x != null ? x.GetHashCode() : 0)
         .Aggregate((x, y) =&amp;gt; x ^ y);
    }
    // Other utility methods
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
We can inherit from &lt;code&gt;ValueObject&lt;/code&gt; class to define &lt;code&gt;Money&lt;/code&gt; value object.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Money : ValueObject
{
    public string Currency { get; private set; }
    public decimal Value { get; private set; }

    private Money() { }

    public Money(string currency, string value)
    {
        Currency = currency;
        Value = value;
    }

    protected override IEnumerable&amp;lt;object&amp;gt; GetAtomicValues()
    {
        yield return Currency;
        yield return Value;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
A word of caution must be mentioned here. Initially, you may be tempted to use struct as a value object. Even though it may seem like a good idea, it has major disadvantages. Read &lt;a href="https://enterprisecraftsmanship.com/posts/net-value-type-ddd-value-object/"&gt;this blog post&lt;/a&gt; to learn why. We can use &lt;code&gt;Money&lt;/code&gt; class in &lt;code&gt;ShareCapital&lt;/code&gt; property of &lt;code&gt;Company&lt;/code&gt; class. With that change, we completed transforming an anemic model into a rich model. This is a new version of &lt;code&gt;Company&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Company
{
    public int Id { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public string Name { get; private set; }
    public string Description { get; private set; }
    public Money ShareCapital { get; private set; }

    public Company(string name)
    {
        if (!string.IsNullOrWhiteSpace(name))
        {
            throw new Exception(&amp;quot;name is required&amp;quot;);
        }

        Id = ... //generate Id
        Name = name;
        CreatedAt = DateTime.UtcNow;
    }

    public void UpdateDescription(string description)
    {
        Description = description;
    }

    public void UpdateShareCapital(Money shareCapital)
    {
        ShareCapital = shareCapital;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
We could benefit from using value objects instead of primitive types. The code will be well-organized and understandable, and it will help us avoid code duplication. There is even a term for the situation when your domain code relies heavily on primitive types - we call it a primitive obsession.&lt;/p&gt;
&lt;h3&gt;Refactor CompanyService&lt;/h3&gt;
&lt;p&gt;We can simplify &lt;code&gt;CompanyService&lt;/code&gt; by using a new version of &lt;code&gt;Company&lt;/code&gt; class and by removing company logic that is encapsulated inside &lt;code&gt;Company&lt;/code&gt; class. Here is the result of that change:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class CompanyService
{
    public void Create(CreateCompanyModel model)
    {
        Company company = new Company(model.Name);

        // save company in database
    }

    public void UpdateDescription(string description, int companyId)
    {
        Company company = ...// get company from database
        company.UpdateDescription(description);

        // update company in database
    }

    public void UpdateShareCapital(Money money, int companyId)
    {
        Company company = ...// get company from database
        company.UpdateShareCapital(money);

        // update company in database
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
This code is much cleaner than the original version, and more object-oriented. It is also more expressive.&lt;/p&gt;
&lt;h3&gt;Potential problems&lt;/h3&gt;
&lt;p&gt;▶ When you develop a small application, transforming it into rich models may not be worth it. &lt;br&gt;&lt;br&gt;
▶ Additional work has to be done to make it work with popular ORM frameworks, e.g. NHibernate or Entity Framework. It is possible but it is not out of the box support. &lt;br&gt;&lt;br&gt;
▶ The setup of your tests may become more complex. It can also be a good thing because your tests are closer to real-world scenarios. When you create your domain models in test, then you are forced to comply with all business rules that are implemented in your application. &lt;/p&gt;
&lt;p&gt;In general, I believe it is worth going the extra mile if you know that a project will be developed in a longer perspective.&lt;/p&gt;
&lt;h3&gt;Where to go next?&lt;/h3&gt;
&lt;p&gt;I highly recommend you a Pluralsight course &lt;i&gt;&lt;a href="https://www.pluralsight.com/courses/refactoring-anemic-domain-model"&gt;Refactoring from Anemic Domain Model Towards a Rich One&lt;/i&gt; by Vladimir Khorikov&lt;/a&gt;. You should also read &lt;a href="http://www.kamilgrzybek.com/"&gt;Kamil Grzybek's blog&lt;/a&gt;, especially posts related to Domain-Driven Design. If you want to learn more about Domain-Driven Design, you can start by reading the book &lt;em&gt;Implementing Domain-driven Design&lt;/em&gt; by Vaughn Vernon. &lt;/p&gt;
&lt;h4&gt;If you have any questions, feel free to leave us a comment!&lt;/h4&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/marcin-zarebski/" target="_blank"&gt;Marcin Zarębski&lt;/a&gt; is an experienced back-end developer, specializing in. .NET platform. He has amazing skills in building complex backend solutions and infrastructure. Marcin is also interested in space exploration and the role of computer science in it. He likes to spend his free time in the mountains or playing board games. &lt;/p&gt;
</description>
      <pubDate>Thu, 18 Jun 2020 10:16:11 Z</pubDate>
      <a10:updated>2020-06-18T10:16:11Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3509</guid>
      <link>https://angrynerds.co/blog/master-your-git-log-with-conventional-commits-in-6-steps/</link>
      <category>Development</category>
      <title>Master your git log with Conventional Commits in 6 steps</title>
      <description>&lt;p&gt;Such messages tell us absolutely nothing about the project, and soon turn following changes into hell. Sad reality of being a software developer? &lt;/p&gt;
&lt;div style="display: block; width: 500px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2034/gitcommit.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div align="center"&gt;

&lt;i&gt;Source: &lt;a href="https://xkcd.com/1296/" target="_blank"&gt;xkcd&lt;/a&gt;&lt;/i&gt;

&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Not anymore! We hope that after reading this article you will no longer have problems with self-discipline, and you will learn how to better document your work. We will also show you how to automate it all, avoid inappropriate commit message format and properly version the modules. &lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Semantic Versioning, Conventional Commits and related tools are powerful – and very easy to use! They’ll not only take your skills to the next level, but also speed up the development process. Their advantages are significant: &lt;/p&gt;
&lt;p&gt;→ generating changelogs and determining the next module version can be automated (based on commit messages), &lt;br&gt;
→ the whole process of building and publishing the module can be automated, &lt;br&gt;
→ contributing to your project is easier thanks to a more structured commit history.&lt;/p&gt;
&lt;p&gt;Before we start with Conventional Commits, we need to know what the Semantic Versioning is.&lt;/p&gt;
&lt;h2&gt;1. Semantic Versioning&lt;/h2&gt;
&lt;p&gt;You probably already use something similar to Semantic Versioning in your projects, but that's not enough, especially when the project is a complex one. At some point you might get stuck in a dependency hell – and you really wouldn’t like that:  
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;In the world of software management there exists a dreaded place
called &amp;quot;dependency hell&amp;quot;. The bigger your system grows and the more
packages you integrate into your software, the more likely you are to
find yourself, one day, in this pit of despair. In systems with many
dependencies, releasing new package versions can quickly become a
nightmare. If the dependency specifications are too tight, you are in
danger of version lock (the inability to upgrade a package without
having to release new versions of every dependent package). If
dependencies are specified too loosely, you will inevitably be bitten
by version promiscuity (assuming compatibility with more future
versions than is reasonable). &lt;strong&gt;Dependency hell is where you are when
version lock and/or version promiscuity prevent you from easily and
safely moving your project forward.&lt;/strong&gt;&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;i&gt;Source: &lt;a href="https://semver.org/" target="_blank"&gt;semver.org&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;So, what is Semantic Versioning?&lt;/p&gt;
&lt;div align="center"&gt;
&lt;img src="https://angrynerds.co/media/2035/semver.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
It's the way we version the project, and the main guidelines are the following:&lt;br&gt;
1.	Increment major version when you make incompatible API changes&lt;br&gt;
2.	Increment minor version when you add functionality in a backwards compatible manner&lt;br&gt;
3.	Increment patch version when you make backwards compatible bug fixes&lt;br&gt;
4.	Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format&lt;/p&gt;
&lt;p&gt;And that's it! Isn't it simple? You can learn more about Semantic Versioning at &lt;a href="https://semver.org/" target="_blank"&gt;semver.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;2. Conventional Commits&lt;/h2&gt;
&lt;p&gt;The big questions is: which version should we increment? Conventional Commits come to the rescue! This lightweight specification provides an easy set of rules for creating an explicit commit history. Features, fixes and breaking changes made in commit messages allow to determine which version should be released next.&lt;/p&gt;
&lt;div style="display: block; width: 550px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/2033/add-commit.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;The commit message should be structured as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type(optional scope): description
[blank line]
[optional body]
[blank line]
[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Types of commits:&lt;br&gt;
• fix: it patches a bug in your codebase (this correlates with PATCH in semantic versioning).&lt;br&gt;
• feat: it introduces a new feature to the codebase (this correlates with MINOR in semantic versioning).&lt;br&gt;
• BREAKING CHANGE: a commit that has a footer BREAKING CHANGE:, or appends a ! after the type/scope, introduces a breaking API change (correlating with MAJOR in semantic versioning). A BREAKING CHANGE can be part of commits of any type.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Types other than fix and feat are of course allowed - the Angular convention recommends: build, chore, ci, docs, style, refactor, perf, test, and others. Learn more here: &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" target="_blank"&gt;conventionalcommits.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;3. Lint commit messages&lt;/h2&gt;
&lt;p&gt;Once you know what Conventional Commits are, it's a good idea to be consistent and follow these rules, and preferably use a lint to keep a wrong commit message from passing on to the git history. With this tool, you will find out where you made a mistake when writing your message, and get tips on how to fix it.&lt;/p&gt;
&lt;p&gt;How to use it?&lt;/p&gt;
&lt;p&gt;Install commitlint dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev @commitlint/config-conventional @commitlint/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Create commitlint.config.js file with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {extends: ['@commitlint/config-conventional']};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Install husky:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install --save-dev husky
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Extend your package.json:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// package.json 
{
  &amp;quot;husky&amp;quot;:
    {
      &amp;quot;hooks&amp;quot;:
        {
          &amp;quot;commit-msg&amp;quot;: &amp;quot;commitlint -E HUSKY_GIT_PARAMS&amp;quot;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Test your latest commit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx commitlint --from HEAD~1 --to HEAD –verbose
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
This configuration is enough for a start, and if you want to learn more about the potential of this tool, have a look here: &lt;a href="https://commitlint.js.org/#/guides-local-setup" target="_blank"&gt;commitlint.js.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;4. Conventional Changelog&lt;/h2&gt;
&lt;p&gt;How to generate a changelog with Conventional Commits? There are several ways to do this, but the best one is &lt;code&gt;conventional-changelog-cli&lt;/code&gt;, which is a standardized cli tool.
How to use this tool?
Just install it globally using &lt;code&gt;npm install -g conventional-changelog-cli&lt;/code&gt;
If this is your first time using this tool, and you want to generate all previous changelogs, you could do it as follows: &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conventional-changelog -p angular -i CHANGELOG.md -s -r 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
You could use &lt;code&gt;conventional-changelog -p angular -i CHANGELOG.md -s&lt;/code&gt; to extend the changelog with the changes since the last version.
All available command line parameters can be listed using CLI: &lt;code&gt;conventional-changelog –help&lt;/code&gt;.
Get packages at &lt;a href="https://github.com/conventional-changelog/conventional-changelog" target="_blank"&gt;conventional-changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;5. npm version&lt;/h2&gt;
&lt;p&gt;Okay, we know how to generate a changelog, but how to automate it?
To do this, we will use the &lt;code&gt;npm version&lt;/code&gt; script and it's pretty easy to do, just take a look at this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm version [ | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid= ] | from-git]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
For example, you can use such combinations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm version major
npm version minor
npm version patch
npm version prerelease --preid=alpha
npm version prerelease --preid=beta
npm version prerelease --preid=rc
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
Once you know what the npm version command looks like, you can upgrade it with an additional changelog feature.
Just type into package.json scripts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;quot;version&amp;quot;: &amp;quot;conventional-changelog -p angular -i CHANGELOG.md -s &amp;amp;&amp;amp; git add CHANGELOG.md&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
This will extend &lt;code&gt;CHANGELOG.md&lt;/code&gt; file with a log of recent changes in the code, based on the commit messages.
You could also use preversion and postversion scripts to run tests before the version script, and push changes or publish package after that. Learn more here: &lt;a href="https://docs.npmjs.com/cli/version" target="_blank"&gt;docs.npmjs.com/cli/version&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;6. .npmrc&lt;/h2&gt;
&lt;p&gt;Can the process of versioning be even more automated? Sure!
By adding a &lt;code&gt;.npmrc&lt;/code&gt; file you could also automate your commit message and set your tag prefix.
To do this, simply create &lt;code&gt;.npmrc&lt;/code&gt; file or run the &lt;code&gt;npm config&lt;/code&gt; command with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tag-version-prefix=&amp;quot;&amp;quot;
message=&amp;quot;chore(release): %s :tada:&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
This way, every time a new version is called up, a new commit will be created with a Conventional Commit message. Learn more about the configuration here: &lt;a href="https://docs.npmjs.com/configuring-npm/npmrc.html" target="_blank"&gt;docs.npmjs.com/configuring-npm/npmrc&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;As you can see, a few easy steps can take your project management to a higher level, and help you stop treating commit messages like a burden. &lt;/p&gt;
&lt;p&gt;This article is also a good introduction to process automation in software development. What we have shown is only one of the possibilities! You have many conventions to choose from, you can expand your scripts with additional features and adapt them to each of your projects. &lt;/p&gt;
&lt;h3&gt;Don’t be afraid to commit – and enjoy the coding!&lt;/h3&gt;
&lt;p&gt;&lt;br /&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/aleksander-niedzwiedz/" target="_blank"&gt;Aleksander Niedźwiedź&lt;/a&gt; is an ambitious young lad who, despite only a few years of professional experience, has already proven to be a talented developer. At Angry Nerds, he specializes in front-end development, but he has also some skills in back-end technologies. He’s also up to date with the latest trends and best practices in software development. Aleksander likes to spend his free time in an active way, so you can spot him practicing various sports. &lt;/p&gt;
</description>
      <pubDate>Tue, 28 Apr 2020 10:27:32 Z</pubDate>
      <a10:updated>2020-04-28T10:27:32Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3459</guid>
      <link>https://angrynerds.co/blog/how-to-optimize-angular-app/</link>
      <category>Development</category>
      <title>How to optimize an Angular app. 13 tips for front-end developers</title>
      <description>&lt;p&gt;Optimization is a process, and it should start at the same time as the &lt;a href="/services/web-development/"&gt;app development&lt;/a&gt;. It’s really hard to optimize the application that already exists (though it’s still possible of course), so we should take care of it during the whole project. &lt;/p&gt;
&lt;p&gt;Here's a list of the best tips to help keep your code in line with good practices and make your Angular application faster. Enjoy and optimize!&lt;/p&gt;
&lt;h2&gt;1. Code minification&lt;/h2&gt;
&lt;p&gt;Trivial, but really important - each part of the application should be minified before deploying to the production stage. If you have ever used Webpack, you probably know plugins such as UglifyJS, MinifyCSS, etc. They remove every whitespace and every function that is never executed. Moreover, they change functions' and variables' names to shorter ones that make the code almost unreadable, but the size of the compiled bundle is smaller.
Fortunately, with Angular, we don’t have to remember to add Webpack scripts to minify the code. All we have to do is make a bundle using &lt;code&gt;ng build --prod&lt;/code&gt; command. It’s just good to know when and how it happens.&lt;/p&gt;
&lt;h2&gt;2. OnPush Change Detection&lt;/h2&gt;
&lt;p&gt;Each Angular component has its own Change Detector that is responsible for detecting when the component data has been changed, and automatically re-render the view to reflect the changes. Change Detector is called whenever DOM emits an event (button click, form submit, mouseover etc.), an HTTP request is executed, or there’s an asynchronous interaction such as setTimeout or setInterval. On every single event, the Change Detector will be triggered in the whole application tree (from the top to the bottom, starting with the root component).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1990/onpush1.png" /&gt;&lt;/p&gt;
&lt;p&gt;The numbers show the order of checking the changes by the Change Detectors after the event in the Component in the left bottom corner.
To change Detection Strategy for the component, the changeDetection in Component declaration should be set to ChangeDetectionStrategy.OnPush as below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Component({
   ...
   changeDetection: ChangeDetectionStrategy.OnPush
})
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
After that, the Change Detectors will work by comparing references to the inputs of the component. Inputs in this component are immutable and if values in these inputs have not changed, change detection skips the whole subtree of Change Detectors, as depicted below:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1988/onpush2.png" /&gt;&lt;/p&gt;
&lt;p&gt;Change detector for a component with OnPush Strategy will be triggered only when a value in @Input() has been changed, an event has been emitted by a template, an event has been triggered by Observable in this component or &lt;code&gt;this.changeDetector.markForCheck()&lt;/code&gt; has been called.&lt;/p&gt;
&lt;h2&gt;3. Pure pipes instead of functions/getters in templates&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;class foo {
   private _bar: boolean = false;
   get bar(): boolean {
      return this._bar;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
&lt;code&gt;get&lt;/code&gt; used in the view is nothing more than a function call. A better idea is to use pure pipes which will always return the same output, no matter how many times they will receive the same input. If the Change Detector reaches this view and pure in the pipe is set to true (default), the Change Detector will not check if that value has been changed because it knows that it will return exactly the same value.&lt;/p&gt;
&lt;h2&gt;4. Async pipe&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div&amp;gt;Time: {{ time | async }}&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
The async pipe allows subscribing to Observable directly from the template.
With async pipe, there's no need to bother about unsubscribing. What’s more, Change Detector will check if the value was changed only when Observable had changed itself.&lt;/p&gt;
&lt;h2&gt;5. Unsubscribing&lt;/h2&gt;
&lt;p&gt;When using RxJS, it’s really important not to forget about unsubscribing, otherwise there’s a risk to get memory leaks in our application. There are a few methods to unsubscribe a Subscription, but choosing the best one is probably a subject for another blog post - for now, just remember to do it. Here are the methods →&lt;/p&gt;
&lt;p&gt;1st method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let sub1: Subscription;
let sub2: Subscription;

ngOnInit() {
   this.sub1 = this.service.Subject1.subscribe(() =&amp;gt; {});
   this.sub2 = this.service.Subject2.subscribe(() =&amp;gt; {});
}

ngOnDestroy() {
   if (this.sub1) {
      this.sub1.unsubscribe();
   }
   if (this.sub2) {
      this.sub2.unsubscribe();
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
2nd method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let subs: Subscription[] = [];

ngOnInit() {
   this.subs.push(this.service.Subject1.subscribe(() =&amp;gt; {}));
   this.subs.push(this.service.Subject2.subscribe(() =&amp;gt; {}));
}

ngOnDestroy() {
   subs.forEach(sub =&amp;gt; sub.unsubscribe());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
3rd method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private subscriptions = new Subscription();

ngOnInit() {
   this.subscriptions.add(this.service.Subject1.subscribe(() =&amp;gt; {}));
   this.subscriptions.add(this.service.Subject2.subscribe(() =&amp;gt; {}));
}

ngOnDestroy() {
   this.subscriptions.unsubscribe();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
4th method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ngUnsubscribe = new Subject();

ngOnInit() {
   this.service.Subject1.pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(() =&amp;gt; {});
   this.service.Subject2.pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(() =&amp;gt; {});
}

ngOnDestroy() {
   this.ngUnsubscribe.next();
   this.ngUnsubscribe.complete();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;4. Track by function&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;*ngFor=&amp;quot;let item of items; trackBy: trackByFn&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
trackBy is a parameter that accepts a function that should return a unique value of each item of the list. Without using trackBy function, *ngFor will re-render each and every element of the list every time that list changes (each element will be removed from DOM and rendered once again). With trackBy function, only the values that have been changed will be re-rendered or deleted. &lt;/p&gt;
&lt;h2&gt;5. Webpack Bundle Analyzer&lt;/h2&gt;
&lt;p&gt;If you find out that your bundle’s size is too big, you can check what exactly is in the bundle and decide whether you need all the external libraries or not. You can use e.g. Webpack Bundle Analyzer. All you need to do is just provide a simple configuration based on your application and your needs, and analyze the output graph.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1989/graph.png" /&gt;&lt;/p&gt;
&lt;h2&gt;6. You probably don’t need external libraries&lt;/h2&gt;
&lt;p&gt;After generating a graph via Webpack Bundle Analyzer you probably know that you shouldn’t add the whole library to your project if you use only a small feature from it. Try to code the same function that you import from the library on your own. For example, a concat method from Lodash&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { concat } from 'lodash'
concat([1], 2, [3], [[4]])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
is nothing more than&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[1].concat(2, [3], [[4]])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
The more code you write on your own, the bigger control and understanding of how it works you have. Moreover, it’s easier to debug and maintain the code without unnecessary external libraries.
However, if you need to import something, choose modular library and &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { chunk } from “lodash”
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
instead of&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * from “lodash”  
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;7. Styles per component&lt;/h2&gt;
&lt;p&gt;No matter if you use SASS, LESS or pure CSS (is there anybody who still uses pure CSS? 😉) try to write as many styles per component as you can, instead of global ones.
In the files with global styles declare variables with colors, fonts, reusable components, like buttons, dropdowns, form inputs, but keep everything else divided into components.
Properties will be loaded only if the component is used in the rendered page, so it means better performance for the application. For you, as a front-end developer, it means that the SCSS is scoped and simplified, so you will be probably more productive during development. &lt;/p&gt;
&lt;h2&gt;8. Tree shaking&lt;/h2&gt;
&lt;p&gt;You can imagine that the application is a tree with green and brown leaves that refer respectively to used and unused parts of the code. When you try to shake that tree, the brown leaves (dead code) will fall down.
When using &lt;code&gt;ng build --prod&lt;/code&gt; to build, the Angular CLI will compile and bundle all components into the application.
When using &lt;code&gt;ng build --prod --build-optimizer&lt;/code&gt; to build, all of the unused components will be omitted.
&lt;code&gt;--build-optimizer&lt;/code&gt; activates tree shaking (a term commonly used for dead-code elimination in JavaScript context) on Webpack.
Unfortunately, this can cause some bugs, so be really careful while doing that and rather than excluding &lt;strong&gt;dead code,&lt;/strong&gt; try including &lt;strong&gt;living code&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;9. One-time string initialization&lt;/h2&gt;
&lt;p&gt;While binding properties between components check if: &lt;br /&gt;
• the target property accepts a string value,&lt;br /&gt;
• the string is a fixed value that you can put directly into the template,&lt;br /&gt;
• this initial value never changes. &lt;br /&gt;
&lt;i&gt;[Source: &lt;a href="https://angular.io/guide/template-syntax#one-time-string-initialization" target="_blank" rel="nofollow"&gt;Angular.io&lt;/a&gt;]&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;
If if the property covers all of these criteria omit the brackets and use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;label=&amp;quot;Save&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
instead of&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[label]=”’Save’”
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
This way the Change Detector will not check it while running in the component.&lt;/p&gt;
&lt;h2&gt;10. Dependencies between components&lt;/h2&gt;
&lt;p&gt;The next thing to consider are dependencies between components in the application. Are all of them really necessary? Do you want and need them all? Try to check it by generating and analyzing dependencies graph (for example NGD: Angular Dependencies Graph).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1991/dependencies.png" /&gt;&lt;/p&gt;
&lt;p&gt;It can be also helpful when you start working on an already existing project and want to have an overview of the architecture of the application.&lt;/p&gt;
&lt;h2&gt;11. CSS vs. JS animations&lt;/h2&gt;
&lt;p&gt;Remember to use the appropriate animations, depending on what you want to achieve. CSS animations are perfect for smaller, self-contained states for UI elements, e.g. a sidebar with menu appearing from the side, a tooltip showing on hover, while JavaScript gives more control over animations, e.g. possibility to stop, slow down, reverse or pause the animation.
CSS animations are smaller so use them every time you can, and only when they are not enough for you, choose JS ones.
A good practice is to use a CSS animation to make a global loader for the application - then, even if the JavaScript of the application doesn’t load properly, the user can see a nice, animated loader.&lt;/p&gt;
&lt;h2&gt;12. Lazy loading&lt;/h2&gt;
&lt;p&gt;Lazy loading loads only those modules and components that are necessary. If the user is not an admin, there is no need to load the entire AdminModule, and if the user is not signed into the application and uses it anonymously, there is no need to load the AccountModule, which allows to view and edit the profile. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const routes: Routes = [
          { path: 'account',
          loadChildren: () =&amp;gt; import('./account/account.module')
          .then(m =&amp;gt; m.AccountModule) },
          { path: admin,
          loadChildren: () =&amp;gt; import('./admin/admin.module')
          .then(m =&amp;gt; m.AdminModule) }
];
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
What's more, you can try lazy load for a bigger amount of images or longer content - load it on scroll.&lt;/p&gt;
&lt;h2&gt;13. Throw it away to the backend&lt;/h2&gt;
&lt;p&gt;Move as much application logic as possible to the backend. When the logic of the application relies little on the choices of the user, there is no need to perform huge calculations on the frontend side.&lt;/p&gt;
&lt;h3&gt;We hope these tips will help you with your next Angular project. If you have anything to add, feel free to share your thoughts in the comments!&lt;/h3&gt;
&lt;h4&gt;You may be also interested in:&lt;/h4&gt;
&lt;p&gt;➤ &lt;a href="/blog/css-tips-and-tricks-for-text-based-content/" target="_blank"&gt;CSS tips and tricks for text-based content&lt;/a&gt;&lt;br /&gt;
➤ &lt;a href="/blog/8-useful-chrome-extensions-for-front-end-developers-and-a-bonus/" target="_blank"&gt;8 useful Chrome extensions for front-end developers&lt;/a&gt;&lt;br /&gt;
➤ &lt;a href="https://www.toptal.com/front-end/how-to-hire" target="_blank"&gt;The most important skills you need to be a good front-end developer&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/weronikaszymanska/" target="_blank"&gt;Weronika Szymańska&lt;/a&gt; is a front-end developer at Angry Nerds – which means her job is to reconcile our designers’ unlimited imagination with equally unrestrained ideas of back-end devs. And she’s great at it! She has strong experience in JavaScript and Angular development and loves to share tips and tricks she uses in her daily work. When she's not coding, she can be found hiking in the mountains or reading crime stories. &lt;/p&gt;
</description>
      <pubDate>Wed, 18 Mar 2020 13:40:31 Z</pubDate>
      <a10:updated>2020-03-18T13:40:31Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3222</guid>
      <link>https://angrynerds.co/blog/11-extremely-useful-git-commands-every-developer-should-know/</link>
      <category>Development</category>
      <title>11 extremely useful Git commands every developer should know</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;Git is a free and open-source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To take advantage of this speed and efficiency you should learn some useful commands. In this blogpost, I'd like to share with you some of the most interesting Git commands - and my personal favorites. Let's explore them!&lt;/p&gt;
&lt;div style="display: block; width: 500px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1774/fire.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;1. git stash -u&lt;/h4&gt;
&lt;p&gt;You may have used git stash command (this command takes modified files in your working directory and saves them in a separate place) and you may have been annoyed that the new files were not stashed. By using -u option you can move your new files to the stash.&lt;/p&gt;
&lt;h4&gt;2. git filter-branch --force --index-filter \&lt;br&gt; 'git rm --cached --ignore-unmatch Filename' \&lt;br&gt; --prune-empty --tag-name-filter cat -- --all&lt;/h4&gt;
&lt;p&gt;Have you ever discovered that there's a big unnecessary file in your repository? You could just remove it from your local directory and push that change to the remote. However, there is one problem with this approach: the file still exists in the repository history. Good news - it's possible to remove such file permanently! See &lt;a href="https://help.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository" target="_blank"&gt;here&lt;/a&gt; for details.&lt;/p&gt;
&lt;h4&gt;3. git add --renormalize&lt;/h4&gt;
&lt;p&gt;Have you ever heard of the wall of pink? It is a situation when someone commited a small change to your repository, but all the files in this change have all the lines changed. In GUI tool, you may see all the lines pink (removed) and right below all the lines green (added). But how did it happen? The answer to this problem may be different line endings (CR LF vs LF). Read more about it &lt;a href="https://www.hanselman.com/blog/YoureJustAnotherCarriageReturnLineFeedInTheWall.aspx" target="_blank"&gt;here&lt;/a&gt; and &lt;a href="https://www.hanselman.com/blog/CarriageReturnsAndLineFeedsWillUltimatelyBiteYouSomeGitTips.aspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1779/1.jpg" /&gt;&lt;/p&gt;
&lt;h4&gt;4. git log --graph --decorate --abbrev-commit --all --format=format:&amp;quot;%C(magenta)%h%n%C(green)%t%n%C(yellow)%an%n%C(red)%ae%n%C(blue)%ad%n%C(cyan)%s&amp;quot;&lt;/h4&gt;
&lt;p&gt;Did you know that you can customize git log appearance? Read more about possible formatting options &lt;a href="https://git-scm.com/docs/pretty-formats" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;5. git shortlog -s -n --all --no-merges&lt;/h4&gt;
&lt;p&gt;This command will show how many commits you and your teammates pushed to the repository.&lt;/p&gt;
&lt;h4&gt;6. git push --force-with-lease&lt;/h4&gt;
&lt;p&gt;More polite version of git push --force. Remote branch won't be overwritten if someone pushed some changes to it.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1777/2.jpg" /&gt;&lt;/p&gt;
&lt;h4&gt;7. git branch --merged | egrep -v &amp;quot;(^\*|master|dev)&amp;quot; | xargs git branch -d&lt;/h4&gt;
&lt;p&gt;Delete branches that were merged to current branch, except for branches excluded in the filter (master and dev in this example).&lt;/p&gt;
&lt;h4&gt;8. git reflog&lt;/h4&gt;
&lt;p&gt;Using this command, you can find a log of what you did in the repository. You can use it for example to restore a commit from a branch that was deleted.&lt;/p&gt;
&lt;h4&gt;9. git commit --amend --no-edit&lt;/h4&gt;
&lt;p&gt;If you forgot to commit one extra change, you can use this command to edit your commit. Use it only if you &lt;strong&gt;did not&lt;/strong&gt; push your commit!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1778/3.jpg" alt="enter image description here" /&gt;&lt;/p&gt;
&lt;h4&gt;10. git-bisect&lt;/h4&gt;
&lt;p&gt;Imagine that you find a bug in the current version, and you know that this feature worked in some old commit. There are probably dozens of commits between the current version with the bug and the working one. If you have trouble with identifying what part of code and what commit is responsible for that bug, you can use git-bisect to identify the root cause of the issue. You start by marking two commits as bad and good, and use git-bisect to perform binary search in the repository history. More details can be found in &lt;a href="https://git-scm.com/docs/git-bisect" target="_blank"&gt;the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;11. git grep&lt;/h4&gt;
&lt;p&gt;You probably know that you can search your working directory with grep function. Did you know you can do the same in the repository history? If you remember some part of code that was deleted and you need it now, use git grep. Usage is similar to grep function. Find out more &lt;a href="https://git-scm.com/docs/git-grep" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;I hope you find these commands useful and they will make your daily work more efficient. If you want to learn more about Git and how it works, I highly recommend you this awesome presentation: &lt;a href="https://www.youtube.com/watch?v=fBP18-taaNw" target="_blank"&gt;Deep Dive into Git by Edward Thomson&lt;/a&gt;.&lt;/h4&gt;
&lt;h4&gt;Feel free to share your favorite Git commands in the comments!&lt;/h4&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/marcin-zarebski/" target="_blank"&gt;Marcin Zarębski&lt;/a&gt; is an experienced back-end developer, specializing in. .NET platform. He has amazing skills in building complex backend solutions and infrastructure. Marcin is also interested in space exploration and the role of computer science in it. He likes to spend his free time in the mountains or playing board games. &lt;/p&gt;
</description>
      <pubDate>Thu, 05 Dec 2019 15:25:55 Z</pubDate>
      <a10:updated>2019-12-05T15:25:55Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3221</guid>
      <link>https://angrynerds.co/blog/motionlayout-plus-android-studio-40/</link>
      <category>Development</category>
      <title>MotionLayout + Android Studio 4.0 = ❤</title>
      <description>&lt;p&gt;MotionLayout is out there since the release of &lt;code&gt;constraint-layout:2.0.0-alpha1&lt;/code&gt; (June 2018), and it has already caused quite a stir. When we first saw the example animations that can be done pretty easily using it, we were pretty impressed. However, as it turned out, using MotionLayout was time- and work-consuming, because there was a lot of code to write, and in order to test it we had to run our app on the device each time.&lt;/p&gt;
&lt;p&gt;These times are over!&lt;/p&gt;
&lt;p&gt;As for &lt;code&gt;constraint-layout:2.0.0-beta3&lt;/code&gt; and &lt;strong&gt;&lt;em&gt;Android Studio 4.0 Canary1&lt;/em&gt;&lt;/strong&gt; we can edit MotionLayout in the graphic design tool, and what’s even better, we can preview the effects of our work right in the Android Studio, with no need to run the app on the device ❤&lt;/p&gt;
&lt;p&gt;That sounds really awesome. Now, let’s see how it works.&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1731/keyframe2.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;

&lt;i&gt;A simple MotionLayout with changing position, color, rotation, and size of the view.&lt;/i&gt;

&lt;/div&gt;
&lt;h2&gt;MotionLayout&lt;/h2&gt;
&lt;p&gt;At the beginning, just a few words about the MotionLayout itself. &lt;/p&gt;
&lt;p&gt;&lt;code&gt;MotionLayout&lt;/code&gt; class extends &lt;code&gt;ConstraintLayout&lt;/code&gt;. That means you can seamlessly convert the latter to the first, and without any changes, it should work pretty much the same. That is really nice, because it enables us to experiment with MotionLayout, starting with any existing ConstraintLayout.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;
    xmlns:app=&amp;quot;http://schemas.android.com/apk/res-auto&amp;quot;
    android:layout_width=&amp;quot;match_parent&amp;quot;
    android:layout_height=&amp;quot;match_parent&amp;quot;&amp;gt;

    &amp;lt;View
        android:id=&amp;quot;@+id/sky&amp;quot;
        android:layout_width=&amp;quot;0dp&amp;quot;
        android:layout_height=&amp;quot;0dp&amp;quot;
        android:background=&amp;quot;@color/sky_morning&amp;quot;
        app:layout_constraintBottom_toTopOf=&amp;quot;@id/guideline&amp;quot;
        app:layout_constraintEnd_toEndOf=&amp;quot;parent&amp;quot;
        app:layout_constraintStart_toStartOf=&amp;quot;parent&amp;quot;
        app:layout_constraintTop_toTopOf=&amp;quot;parent&amp;quot; /&amp;gt;

    &amp;lt;View
        android:id=&amp;quot;@+id/ground&amp;quot;
        android:layout_width=&amp;quot;0dp&amp;quot;
        android:layout_height=&amp;quot;0dp&amp;quot;
        android:background=&amp;quot;@color/ground&amp;quot;
        app:layout_constraintBottom_toBottomOf=&amp;quot;parent&amp;quot;
        app:layout_constraintEnd_toEndOf=&amp;quot;parent&amp;quot;
        app:layout_constraintStart_toStartOf=&amp;quot;parent&amp;quot;
        app:layout_constraintTop_toBottomOf=&amp;quot;@id/guideline&amp;quot; /&amp;gt;

    &amp;lt;androidx.constraintlayout.widget.Guideline
        android:id=&amp;quot;@+id/guideline&amp;quot;
        android:layout_width=&amp;quot;wrap_content&amp;quot;
        android:layout_height=&amp;quot;wrap_content&amp;quot;
        android:orientation=&amp;quot;horizontal&amp;quot;
        app:layout_constraintGuide_percent=&amp;quot;0.5&amp;quot; /&amp;gt;

    &amp;lt;ImageView
        android:id=&amp;quot;@+id/biker&amp;quot;
        android:layout_width=&amp;quot;wrap_content&amp;quot;
        android:layout_height=&amp;quot;wrap_content&amp;quot;
        android:contentDescription=&amp;quot;@string/biker&amp;quot;
        android:src=&amp;quot;@drawable/ic_bike&amp;quot;
        app:layout_constraintBottom_toBottomOf=&amp;quot;@id/guideline&amp;quot;
        app:layout_constraintTop_toTopOf=&amp;quot;@id/guideline&amp;quot; /&amp;gt;

&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div align="center"&gt;

&lt;i&gt;Above: just a simple constraint layout that will be our starting point.&lt;/i&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
The real magic of MotionLayout lays in the MotionScene resource file, which contains all the constraints and attributes transitions that result in our layout animation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;MotionScene 
    xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;
    xmlns:motion=&amp;quot;http://schemas.android.com/apk/res-auto&amp;quot;&amp;gt;

    &amp;lt;Transition
        motion:constraintSetEnd=&amp;quot;@+id/end&amp;quot;
        motion:constraintSetStart=&amp;quot;@id/start&amp;quot;
        motion:duration=&amp;quot;1000&amp;quot;&amp;gt;
       &amp;lt;KeyFrameSet&amp;gt;
       &amp;lt;/KeyFrameSet&amp;gt;
    &amp;lt;/Transition&amp;gt;

    &amp;lt;ConstraintSet android:id=&amp;quot;@+id/start&amp;quot;&amp;gt;
    &amp;lt;/ConstraintSet&amp;gt;

    &amp;lt;ConstraintSet android:id=&amp;quot;@+id/end&amp;quot;&amp;gt;
    &amp;lt;/ConstraintSet&amp;gt;
&amp;lt;/MotionScene&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;div align="center"&gt;

&lt;i&gt;Above: an empty MotionScene file.&lt;/i&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
Each Transition has to have a start and end ConstraintSet, and a number of KeyFrames that enables us to achieve various interesting effects. You should remember, that &lt;u&gt;constraints set in the MotionScene always take precedence over these declared in the MotionLayout file.&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;If you want to know more about the MotionLayout itself, there is a great series of articles on the &lt;a href="https://medium.com/google-developers/introduction-to-motionlayout-part-i-29208674b10d" target="_blank"&gt;Google Developers Medium&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To use all the discussed below features you need to add a dependency to your &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;MotionEditor&lt;/h2&gt;
&lt;p&gt;Ok, so now that we know what MotionLayout is, let’s see what Android Studio 4.0 can do to make our work with it more enjoyable.&lt;/p&gt;
&lt;p&gt;First of all, in the layout design panel there is a tool to automatically convert our selected ConstraintLayout to the MotionLayout. &lt;/p&gt;
&lt;div style="display: block; width: 600px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1748/convert.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;What it really does is changing the root layout to MotionLayout, creating a new MotionScene xml file in the &lt;code&gt;resources/xml&lt;/code&gt; package and setting the &lt;code&gt;app:layoutDescription&lt;/code&gt; attribute of the new layout to the motion scene file. That’s it. But is also redirects us to the brand new MotionEditor view.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1739/start_motion.png" /&gt;&lt;/p&gt;
&lt;p&gt;There you can see a preview of our MotionLayout on the left, a panel with all the transitions and constraint sets in the middle, and attributes panel on the right.&lt;/p&gt;
&lt;p&gt;One thing to remember is that you can navigate between code, design, and split the screen using the three buttons on the top right corner of the view (not on the bottom left as it was before).&lt;/p&gt;
&lt;p&gt;Now, by navigating between the start and end states in the middle panel, we are able to add/change views constraints and attributes. E.g. we want the color of the sky to change from light to dark. All we need to do is to choose start state, click on &lt;code&gt;sky&lt;/code&gt; entry and add a new Custom Attribute (there is an autocomplete in the attributes popups ☺). Then repeat it for the end state. &lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1740/end_motion1.png" /&gt;&lt;/p&gt;
&lt;p&gt;MotionLayout will do the rest for us, and we get a nice simple sky animation.&lt;/p&gt;
&lt;p&gt;In a similar way, but by changing the start and end constraints of the &lt;code&gt;biker&lt;/code&gt; image, we are able to create a changing position animation. &lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1738/end_motion2.png" /&gt;&lt;/p&gt;
&lt;p&gt;By clicking on the grey arrow between the states, you open the Transition panel where you can play the current motion animation.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1737/transition_1.png" /&gt;&lt;/p&gt;
&lt;p&gt;To make it work on the device we need to start the motion somehow. We can either start/set the progress in code, or add an OnSwipe/OnClick MotionObject. In this example, we choose the second option, and by clicking the third button on top of the motion panel we add a SwipeHandler with an anchor at the biker.&lt;/p&gt;
&lt;div style="display: block; width: 250px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1735/motion_creation_icons.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1736/step1_1.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Now let’s add some sunshine to our animation ☺&lt;/p&gt;
&lt;p&gt;We add the sun image, and want it to move above the biker, but on the arc, so simply changing the constrains won’t be sufficient. We need to add also a KeyFrame. We can do it by choosing &lt;code&gt;KeyPosition&lt;/code&gt; from the Transition panel, and setting the &lt;code&gt;percentY&lt;/code&gt; position in a 50th frame (frames go from 0 to 100) to a negative value, and type do &lt;code&gt;pathRelative&lt;/code&gt;.&lt;/p&gt;
&lt;div style="display: block; width: 500px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1746/transition_0_1.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div style="display: block; width: 500px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1747/transition_2_1.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1732/transition_3.png" /&gt;&lt;/p&gt;
&lt;p&gt;Now our animation starts to gain some life.&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1744/step2_1.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;In a similar way, but using &lt;code&gt;KeyAttribute&lt;/code&gt; we can modify things like scale, rotation or alpha of our view.&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1749/key_attribute.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Let’s get nuts and add all of the above attributes! Making the sun do a 360 degrees rotation during the animation, scaling to 1.5 in the middle, and vanishing after the 60th frame.&lt;/p&gt;
&lt;div style="display: block; width: 600px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1734/sun_attributes.png"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;When we add a moon image with the same path as the sun image, and with alpha increasing after 60th, we’ll get a really nice transition.&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1733/step3_1.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;

&lt;i&gt;Here, I added also a backgroundColor frame for sky at the 60th frame.&lt;/i&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
Now you can use your imagination and add other views to the animation. Will you be able to recreate the one from below? ☺&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1741/step4_1.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;This kind of animation is a great example of how MotionLayout can be mixed with a &lt;code&gt;ViewPager&lt;/code&gt; for creating a really nice custom experience. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You can find the complete code of the example &lt;a href="https://github.com/aleksandra-majchrzak/motion-layout-examples" target="_blank"&gt;HERE&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1743/pager.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;It is also worth to mention that if you have a MotionLayout written with an older constraint-layout version and older Android Studio, you can still use it with the Android Studio 4.0, and MotionEditor will work just fine, no changes need to be done ✔&lt;/p&gt;
&lt;h2&gt;Problems&lt;/h2&gt;
&lt;p&gt;The tools that Android Studio 4.0 gives us to work with the MotionLayout are great, however we must remember that neither of them is stable yet, and definitely not production-ready. There still can occur some random crashes and other errors.&lt;/p&gt;
&lt;p&gt;Here are some problems I encountered while playing with the above example:&lt;br&gt;
• modifying constraints can sometimes cause big lags&lt;br&gt;
• there must be no errors or &lt;u&gt;warnings (!)&lt;/u&gt; in your xml code for MotionEditor to work&lt;br&gt;
• ‘showPaths’ option does not work when there are many views in the layout&lt;br&gt;
• MotionEditor does not work for your custom classes extending MotionLayout&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Now it’s time for your own experiments. MotionLayout gives us great abilities to create beautiful and meaningful animations. There are many other features that I haven’t discussed here, like multiple transitions in a single MotionScene, creating custom attributes, using MotionLayout progress, KeyCycles, or motion easing.&lt;/p&gt;
&lt;p&gt;The best place to start your adventure is definitely the &lt;a href="https://developer.android.com/training/constraint-layout/motionlayout/examples" target="_blank"&gt;documentation page&lt;/a&gt;, where you can find many examples.&lt;/p&gt;
&lt;h3&gt;If you have any questions regarding the article, or want to share your MotionLayout animations, feel free to leave a comment!&lt;/h3&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/aleksandra-a-krzemien/" target="_blank"&gt;Aleksandra Krzemień&lt;/a&gt; has profound experience in building all sorts of mobile apps, including those connected with external devices. She is a natural mentor and loves to share her knowledge. Throughout her career, she has been actively engaged in many mentoring programs and IT-related organizations, such as Women in Technology or Google Developers Group. She likes to spend her free time singing and playing board games.&lt;/p&gt;
</description>
      <pubDate>Fri, 15 Nov 2019 14:21:28 Z</pubDate>
      <a10:updated>2019-11-15T14:21:28Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3216</guid>
      <link>https://angrynerds.co/blog/8-useful-chrome-extensions-for-front-end-developers-and-a-bonus/</link>
      <category>Development</category>
      <title>8 useful Chrome extensions for front-end developers - and a bonus</title>
      <description>&lt;p&gt;We believe that the list will serve both experienced coders and beginners. Seniors can use it as an inspiration to refresh their toolbox. And as for juniors - we can't promise that the listed tools will make you a front-end superstar instantly, but we're quite sure they'll be helpful on the way!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1711/marc-mueller-lg8xtzjs6lg-unsplash_opt.jpg" alt="chrome plugins for developers" /&gt;&lt;/p&gt;
&lt;h2&gt;Quick JavaScript Switcher&lt;/h2&gt;
&lt;p&gt;This one allows you to &lt;a href="https://chrome.google.com/webstore/detail/quick-javascript-switcher/geddoclleiomckbhadiaipdggiiccfje?hl=en" target="_blank"&gt;disable or enable JavaScript&lt;/a&gt; on the fly by hostname and subdomain. It's really useful when you want to check how your page will look like when there's an error and your JavaScript code doesn't load properly. The reason isn't always an error though — there are some people who reportedly use this plugin as a default setting, in order to improve the speed of their browser. So as a front-end developer, you can test your work for such cases as well and make sure all the content is readable.&lt;/p&gt;
&lt;h2&gt;Dimensions, Page Ruler&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/dimensions/baocaagndhipibgklemoalmkljaimfdj?hl=en" target="_blank"&gt;Dimensions&lt;/a&gt; is a very useful extension when you want to make a pixel-perfect website - and you should always aim at making a pixel-perfect website! With this plugin, you can simply measure all the sizes and distances between elements, such as the sizes of inputs or the distances between images.
&lt;a href="https://chrome.google.com/webstore/detail/page-ruler/emliamioobfffbgcfdchabfibonehkme?hl=en" target="_blank"&gt;Page Ruler&lt;/a&gt; works the same way as Dimensions but you can select your own area to measure and check how big it is.&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1714/dim.png" alt="chrome ruler devtools"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1710/ruler.png" alt="page ruler chrome" /&gt;&lt;/p&gt;
&lt;h2&gt;PerfectPixel&lt;/h2&gt;
&lt;p&gt;Speaking of pixel-perfect websites... Have you ever heard from a designer that your page isn't exactly the same as his design? With this extension you can prove him wrong! &lt;a href="https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi?hl=en" target="_blank"&gt;PerfectPixel&lt;/a&gt; allows you to add a semi-transparent overlay with the design and check if there are any differences. And surely there are none!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1718/perfectpixel.png" alt="pixel perfect chrome" /&gt;&lt;/p&gt;
&lt;h2&gt;Window Resizer&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/window-resizer/kkelicaakdanhinjdeammmilcgefonfh?hl=en" target="_blank"&gt;Window Resizer&lt;/a&gt; can improve the way you test your website's layout on different devices. You can save presets with dimensions you most often need and simply change your browser's window size. It also allows you to swipe the orientation of the device from horizontal to vertical to emulate the behavior of smartphones. &lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1717/windowre.png" alt="window resizer chrome"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;React Developer Tools&lt;/h2&gt;
&lt;p&gt;This extension allows you to inspect hierarchies of components in your &lt;a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en" target="_blank"&gt;React&lt;/a&gt; application. It works only for React and you can find it as a new tab in DevTools (called React). You can also check the props and state of the selected component. The really good thing is that if you select any element in the &lt;em&gt;Elements&lt;/em&gt; tab in DevTools it will be also selected in the &lt;em&gt;React&lt;/em&gt; tab, so you don't have to waste time to look for it twice.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1716/react.png" alt="react developer tools" /&gt;&lt;/p&gt;
&lt;h2&gt;What font?&lt;/h2&gt;
&lt;p&gt;The name speaks for itself in this case! With &lt;a href="https://chrome.google.com/webstore/detail/whatfont/jabopobgcpjmedljpbcaablpmlmfcogm?hl=en" target="_blank"&gt;What font&lt;/a&gt; you can identify the font used on the page without checking it in DevTools. You can also see other details: size, line height, style, weight and color of a selected text. Saves lots of time!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1719/whatfont.png" alt="what font chrome" /&gt;&lt;/p&gt;
&lt;h2&gt;ColorZilla&lt;/h2&gt;
&lt;p&gt;The end of the color struggle! With &lt;a href="https://www.colorzilla.com/" target="_blank"&gt;ColorZilla&lt;/a&gt; you can check every color on your website and get its hex number using simple picker. Besides, there's complete information about class, id, tag name and size of the selected element. The extension also includes a link to the CSS gradient generator and the history of recently picked colors. &lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1720/colorzilla.png" alt="colorzilla chrome" /&gt;&lt;/p&gt;
&lt;h2&gt;Bonus! How to enable dark theme for DevTools?&lt;/h2&gt;
&lt;p&gt;Do you enjoy using dark theme for macOS system or your code editor? You can easily have it the same way in the Chrome browser DevTools. This time there's no extension needed - you can quickly enable it in the &lt;em&gt;Settings&lt;/em&gt;. Here's a &lt;a href="https://developers.google.com/web/tools/chrome-devtools/customize/dark-theme" target="_blank"&gt;step by step guide&lt;/a&gt;. Make your working environment classy!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1712/dark.png" alt="DevTools" /&gt;&lt;/p&gt;
&lt;h3&gt;Anything to add? Feel free to share your suggestions in the comments!&lt;/h3&gt;
&lt;p&gt;&lt;br /&gt; &lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/weronikaszymanska/" target="_blank"&gt;Weronika Szymańska&lt;/a&gt; is a front-end developer at Angry Nerds – which means her job is to reconcile our designers’ unlimited imagination with equally unrestrained ideas of back-end devs. And she’s great at it! She has strong experience in JavaScript and Angular development and loves to share tips and tricks she uses in her daily work. When she's not coding, she can be found hiking in the mountains or reading crime stories. &lt;/p&gt;
</description>
      <pubDate>Thu, 01 Aug 2019 12:15:05 Z</pubDate>
      <a10:updated>2019-08-01T12:15:05Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3211</guid>
      <link>https://angrynerds.co/blog/couchbase-lite-android-migration-from-14-to-2x/</link>
      <category>Development</category>
      <title>Couchbase Lite Android migration from 1.4 to 2.x</title>
      <description>&lt;p&gt;Couchbase Lite is out there for a while, but recently, with an update to version 2.0, it went through a big redesign. In this article, we’d like to point out some differences between versions 1.4 and 2.0, and help you with migrating your code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;[Note: this article does not cover migrating your data replication code.]&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;All examples you’ll see in this article are based on the official sample &lt;a href="https://github.com/couchbaselabs/mobile-training-todo/tree/feature/2.0" target="_blank"&gt;Android Couchbase Lite Todo app&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Internal database format&lt;/h2&gt;
&lt;p&gt;Couchbase Lite is a document database that stores data in JSON documents, however internally it uses an SQLite database. We will look into this database a few times in this article. The first two tables we’re interested in are &lt;strong&gt;&lt;em&gt;docs&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;revs&lt;/em&gt;&lt;/strong&gt;. The first one contains a list of all documents internal ids, and the ids you gave them:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1565/docs.png" /&gt;&lt;/p&gt;
&lt;p&gt;The second table contains info about all documents current revisions:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1564/revs.png" /&gt;&lt;/p&gt;
&lt;p&gt;Up to version 1.4 Couchbase Lite was using a map-reduce approach, which bases on creating &lt;strong&gt;views&lt;/strong&gt; (which work more or less like SQL indexes). It requires you to create a &lt;strong&gt;map&lt;/strong&gt; (and optional &lt;strong&gt;reduce&lt;/strong&gt;) function, which given a JSON document input emits a number of key-value pairs to be indexed in the view. In code it would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val view = db.getView(&amp;quot;list/listByName&amp;quot;)
view.setMap({ document, emitter -&amp;gt;
               if (document[&amp;quot;type&amp;quot;] == &amp;quot;task-list&amp;quot;) {
                   emitter.emit(document[&amp;quot;name&amp;quot;], null)
               }
           }, &amp;quot;1&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
Executing this code will result in inserting a new row in the internal database in &lt;strong&gt;&lt;em&gt;views&lt;/em&gt;&lt;/strong&gt; table:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1561/views1.png" /&gt;&lt;/p&gt;
&lt;p&gt;and creating a new table &lt;strong&gt;&lt;em&gt;maps_1&lt;/em&gt;&lt;/strong&gt; which will include all emitted values. In this case:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1567/maps1.png" /&gt;&lt;/p&gt;
&lt;p&gt;A new table &lt;strong&gt;&lt;em&gt;maps_x&lt;/em&gt;&lt;/strong&gt; will be created for every view.&lt;/p&gt;
&lt;p&gt;The first thing that changed in 2.0 version is the format of the internal SQLite database. Now the table we’re interested in is named &lt;strong&gt;&lt;em&gt;kv_default&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://angrynerds.co/media/1566/updated.png" /&gt;&lt;/p&gt;
&lt;p&gt;It contains all the info about the documents, but JSON body is stored in a binary form, so we’re no longer able to read it! The only way to read the data is to use an official &lt;a href="https://github.com/couchbase/couchbase-lite-core/wiki/The-'cblite'-Tool" target="_blank"&gt;cblite tool&lt;/a&gt;. More info about the new db schema can be found &lt;a href="https://github.com/couchbase/couchbase-lite-core/wiki/Database-Schema" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The important thing is that if in your app you have a database in version 1.4, when you update the library version in your code, your database will be automatically updated to the new format on the first open.&lt;/p&gt;
&lt;h2&gt;Database creation&lt;/h2&gt;
&lt;p&gt;After changing your gradle dependency from &lt;code&gt;implementation &amp;quot;com.couchbase.lite:couchbase-lite-android:1.4.*&amp;quot;&lt;/code&gt;
to &lt;code&gt;implementation &amp;quot;com.couchbase.lite:couchbase-lite-android:2.0.0&amp;quot;&lt;/code&gt; and compiling the project, your code will light up with dozens of error messages. Let’s try to fix some of them step by step.&lt;/p&gt;
&lt;p&gt;First things first. In 1.4 to create and open your database you probably used code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val manager = Manager(AndroidContext(context.applicationContext), Manager.DEFAULT_OPTIONS)
database = manager.getExistingDatabase(&amp;quot;dbName&amp;quot;)
if (database == null) {
   ZipUtils.unzip(context.assets.open(&amp;quot;dbName.zip&amp;quot;), context.filesDir)
   database = manager.getDatabase(&amp;quot;dbName&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;If you needed to have a preloaded database, you stored it in a zip file in assets and then unzipped it using ZipUtils, which was a utility class from the couchbase-lite library. Now you need to change it to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val config = DatabaseConfiguration(context.applicationContext)
if (!Database.exists(&amp;quot;dbName&amp;quot;, context.filesDir)) {
   ZipUtils.unzip(context.assets.open(&amp;quot;dbName.zip&amp;quot;), context.filesDir)
}
database = Database(&amp;quot;dbName&amp;quot;, config)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
and remember that &lt;strong&gt;&lt;em&gt;ZipUtils&lt;/em&gt;&lt;/strong&gt; class is no longer included in the library, so you need to write your own (or copy the old implementation from &lt;a href="https://docs.couchbase.com/couchbase-lite/2.1/java.html#loading-a-pre-built-database" target="_blank"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;CRUD operations&lt;/h2&gt;
&lt;p&gt;As in the 2.0 version Couchbase Lite changed data manipulation approach from map-reduce to N1QL-based Query API, the CRUD operations changed a lot. Say goodbye to &lt;strong&gt;&lt;em&gt;getView()&lt;/em&gt;&lt;/strong&gt; methods, and say hello to &lt;strong&gt;&lt;em&gt;QueryBuilder&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;Creating a single&lt;/u&gt; document didn’t change that much. From&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val docId = username + &amp;quot;.&amp;quot; + UUID.randomUUID()
val data = mapOf(&amp;quot;type&amp;quot; to &amp;quot;task-list&amp;quot;, &amp;quot;name&amp;quot; to title, &amp;quot;owner&amp;quot; to username)
val document = Document(db, docId)
document.putProperties(data)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
we get to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val docId = username + &amp;quot;.&amp;quot; + UUID.randomUUID()
val data = mapOf(&amp;quot;type&amp;quot; to &amp;quot;task-list&amp;quot;, &amp;quot;name&amp;quot; to title, &amp;quot;owner&amp;quot; to username)
val mDoc = MutableDocument(docId, data)
db.save(mDoc)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;u&gt;Updating&lt;/u&gt; existing document looks pretty much the same. You just need to set an existing document id. To create a &lt;code&gt;MutableDocument&lt;/code&gt; from &lt;code&gt;Document&lt;/code&gt; just call &lt;code&gt;document.toMutable()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;Reading&lt;/u&gt; a single document also looks the same&lt;/p&gt;
&lt;p&gt;&lt;code&gt;val document = db.getDocument(mDoc.id)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;but to get the properties from the document instead of calling &lt;code&gt;document.properties&lt;/code&gt; you need to call &lt;code&gt;document.toMap()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;Deleting&lt;/u&gt; a single document goes from&lt;/p&gt;
&lt;p&gt;&lt;code&gt;document.delete() or document.purge()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;p&gt;&lt;code&gt;db.delete(document) or db.purge()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The real fun begins when we need to create a query to the database. Instead of calling &lt;code&gt;db.getView(viewName).createQuery()&lt;/code&gt;, we build our query step by step using &lt;strong&gt;&lt;em&gt;QueryBuilder&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val query = db.getView(&amp;quot;list/listByName&amp;quot;).createQuery() 
query.isDescending = false
query.limit = limit

query.run().forEach { result -&amp;gt;
   val doc = result.document /* we can get document or properties */
   /* mapping and other stuff */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val query = QueryBuilder.select(SelectResult.expression(Meta.id),
                               SelectResult.all())
       .from(DataSource.database(db))
       .where(Expression.property(&amp;quot;type&amp;quot;).equalTo(Expression.string(&amp;quot;task-list&amp;quot;)))
       .orderBy(Ordering.property(&amp;quot;name&amp;quot;).ascending())
       .limit(Expression.intValue(limit))


query.execute().forEach { result -&amp;gt;
   val properties = result.toMap() /* we cannot access the document itself */
   /* mapping and other stuff */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;This may seem longer at first sight, but remember that in the first example we omitted creating the view.&lt;/p&gt;
&lt;p&gt;The semantics of the query builder is really easy to understand, as it reminds good old SQL &lt;code&gt;SELECT * FROM table_name WHERE id=id_number ORDER BY name ASC LIMIT limit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, there are a few things that need to be pointed out.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;select()&lt;/code&gt; method you’d probably use mostly these three expressions:&lt;/p&gt;
&lt;p&gt;• &lt;code&gt;SelectResult.expression(Meta.id)&lt;/code&gt; - which  will result in returning document id (&lt;em&gt;key&lt;/em&gt; from the database, not the id inside your JSON, if you have one)  &lt;u&gt;under the name id&lt;/u&gt;.&lt;/p&gt;
&lt;p&gt;• &lt;code&gt;SelectResult.all()&lt;/code&gt; - which will result in returning entire JSON document in a form of a Dictionary &lt;u&gt;under the name of your database&lt;/u&gt;.&lt;/p&gt;
&lt;p&gt;• &lt;code&gt;SelectResult.property(&amp;quot;name&amp;quot;)&lt;/code&gt; - which will result in returning a property name from your JSON document.&lt;/p&gt;
&lt;p&gt;Of course you can build more complex expressions using comparators like &lt;code&gt;Expression.greaterThan()&lt;/code&gt; or functions like &lt;code&gt;Function.count()&lt;/code&gt; etc.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Where&lt;/code&gt; expressions can be chained using operators like &lt;code&gt;Expression.and()&lt;/code&gt; or &lt;code&gt;Expression.or()&lt;/code&gt;. You can also chain QueryBuilder with &lt;code&gt;join()&lt;/code&gt; or &lt;code&gt;groupBy()&lt;/code&gt; components.&lt;/p&gt;
&lt;p&gt;For example, the above query will result in a structure like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
         &amp;quot;id&amp;quot;: &amp;quot;todo.123&amp;quot;,
         &amp;quot;todo&amp;quot;: {
               &amp;quot;name&amp;quot;: &amp;quot;Groceries&amp;quot;,
               &amp;quot;owner&amp;quot;: &amp;quot;todo&amp;quot;,
               &amp;quot;type&amp;quot;: &amp;quot;task-list&amp;quot;
         }
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br&gt;
One more confusing thing is how Couchbase Lite handles numbers now. If you want to maintain a Double field, it can be serialized (and as a result deserialized) to &lt;a href="https://github.com/couchbase/couchbase-lite-android/issues/1160" target="_blank"&gt;different data types&lt;/a&gt;. If the decimal part is zero, it will be deserialized as &lt;code&gt;Long&lt;/code&gt;. If a number fits in the &lt;code&gt;Float&lt;/code&gt; type, it will be deserialized as&lt;code&gt;Float&lt;/code&gt;. Therefore, if you need a &lt;code&gt;Double&lt;/code&gt;, it would be best to read it from the document map as &lt;code&gt;Number&lt;/code&gt; and then call &lt;code&gt;toDouble()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You also should note that there are no more options to run multiple operations in the transaction. Instead, you can use &lt;code&gt;db.inBatch()&lt;/code&gt; - although it works a bit differently.&lt;/p&gt;
&lt;p&gt;The last thing you need to take into account is that for today (May 2019) Couchbase Lite versions 2.x do not support devices with architecture x86_64. That means they won’t work on these devices, but it also means that you will not be able to write a unit test using eg. Robolectric to test your db code. Instrumentation test, however, will work fine.&lt;/p&gt;
&lt;p&gt;Now, hopefully, you will be able to migrate your database and CRUD operations from Couchbase Lite 1.4 to 2.0. For other examples and features you can look in the &lt;a href="https://docs.couchbase.com/couchbase-lite/2.0/java.html" target="_blank"&gt;official documentation&lt;/a&gt; and dive into some &lt;a href="https://docs.couchbase.com/tutorials/mobile-travel-sample/java/installation/travel-mobile-app.html" target="_blank"&gt;official tutorials&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;We hope you find this article useful, and as always: if you have any comments, feel free to let us know!&lt;/h3&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/aleksandra-a-krzemien/" target="_blank"&gt;Aleksandra Krzemień&lt;/a&gt; has profound experience in building all sorts of mobile apps, including those connected with external devices. She is a natural mentor and loves to share her knowledge. Throughout her career, she has been actively engaged in many mentoring programs and IT-related organizations, such as Women in Technology or Google Developers Group. She likes to spend her free time singing and playing board games.&lt;/p&gt;
</description>
      <pubDate>Thu, 23 May 2019 07:12:52 Z</pubDate>
      <a10:updated>2019-05-23T07:12:52Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3210</guid>
      <link>https://angrynerds.co/blog/black-holes-and-algorithms-how-computer-science-helped-us-see-a-black-hole-for-the-first-time/</link>
      <category>Development</category>
      <title>Black holes and algorithms. How computer science helped us see a black hole for the first time</title>
      <description>&lt;p&gt;Its image was not created like an ordinary image. In some articles, you may find misleading headlines saying it's &lt;em&gt;a photo&lt;/em&gt; of a black hole. If you think that people zoomed in an image from one of the telescopes, then you couldn't be further from the truth. To create this image large amount of observation data was collected from several telescopes performing parallel observations. Next, all the data were combined and used to reconstruct the image that we saw in the news. In this post, I will describe this process, showing the role of image processing algorithms in this experiment.&lt;/p&gt;
&lt;div style="display: block; width: 500px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1604/giphy.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post was written based on the article &lt;a href="https://iopscience.iop.org/article/10.3847/2041-8213/ab0e85" target="_blank"&gt;&amp;quot;First M87 Event Horizon Telescope Results. IV. Imaging the Central Supermassive Black Hole&amp;quot;&lt;/a&gt;. We only scratched the surface here, so if you want to go into depth you should read this paper (see sources at the end).&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;What is a black hole?&lt;/h2&gt;
&lt;p&gt;To fully appreciate this result we should remind ourselves what a black hole is exactly. A black hole is a region of space within which gravity pulls so much that nothing, not even light, can escape. This implies that black cannot be seen directly, though we can see gravity effects near the black hole. Strong gravity is a result of squeezing huge mass into a tiny space. To become a black hole, a star has to be massive (at least 20 times heavier than the Sun). There is a formula for calculating the radius of the created black hole. If hypothetically the Sun became a black hole, its radius would be reduced to 3 km. &lt;/p&gt;
&lt;p&gt;In 1916, Einstein completed his work where he described the general relativity theory. He characterized gravity using geometric concepts - geometric theory of gravitation. Einstein proposed that spacetime is curved around heavy objects. One of the consequences of Einstein's theory is that the time isn't the same in every place of the universe. One of the real-world application is the calculation of coordinates by navigation devices that communicate with GPS satellites. Amendment resulting from general relativity theory is crucial to obtain a precise result for coordinates calculations. If you want to explore black hole concepts further, I recommend you to watch this video - it's originally in Polish, but you can turn on English subtitles:&lt;/p&gt;
&lt;div align="center"&gt;&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/63qdJfWENNg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;/br&gt;&lt;/p&gt;
&lt;h2&gt;Observation description&lt;/h2&gt;
&lt;p&gt;To observe such distant object scientists came up with the idea of combining data from several telescopes distributed around the Earth. This array of telescopes is called the Event Horizon Telescope (EHT). Here is a list of all facilities that collaborated in the black hole observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the phased Atacama Large Millimeter/submillimeter Array (ALMA), &lt;/li&gt;
&lt;li&gt;Atacama Pathfinder Experiment telescope (APEX) in the Atacama Desert in Chile,&lt;/li&gt;
&lt;li&gt;the James Clerk Maxwell Telescope (JCMT),&lt;/li&gt;
&lt;li&gt;the phased Submillimeter Array (SMA) on Maunakea in Hawai'i, &lt;/li&gt;
&lt;li&gt;the Arizona Radio Observatory Sub-Millimeter Telescope (SMT) on Mt. Graham in Arizona, &lt;/li&gt;
&lt;li&gt;the IRAM 30 m (PV) telescope on Pico Veleta in Spain, &lt;/li&gt;
&lt;li&gt;the Large Millimeter Telescope Alfonso Serrano (LMT) on Sierra Negra in Mexico,&lt;/li&gt;
&lt;li&gt;the South Pole Telescope (SPT).&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="display: block; width: 800px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1600/focus_figure_2_resized_opt.jpg"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;i&gt;Photo via &lt;a href="https://iopscience.iop.org/article/10.3847/2041-8213/ab0e85" target="_blank" rel="nofollow"&gt;IOPscience&lt;/a&gt;&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;The biggest advantage of this virtual telescope is that its diameter is equal to the longest distance between the telescopes in array, i.e. distance between Spain and the South Pole. The biggest challenge is different weather conditions around the globe that could prevent you from gathering data from all places. EHT team decided that the best dates for observation were April 5, 6, 10, and 11 in 2017. On these days different target observations interleaved with black hole observation and results were later used for comparison. The number of scans on individual days is 18, 25, 7 and 22. A single scan is an observation between 4 and 7 minutes. Here is a picture in which you can see coverage for EHT observations of M87. &lt;/p&gt;
&lt;div style="display: block; width: 800px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1605/figure-1_opt.jpg"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;i&gt;Photo via &lt;a href="https://iopscience.iop.org/article/10.3847/2041-8213/ab0c96" target="_blank" rel="nofollow"&gt;IOPscience&lt;/a&gt;&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;If the EHT team put telescopes all around the Earth, they would record data for every point, and then it would be relatively easy to make an image using known image processing algorithms, e.g. Fourier transformation. But since they only have telescopes at several places they only get a scarce number of measurements. Earth rotation helped us to expand observation coverage. Team working at each facility recorded petabytes of data. At some point, all this data had to be transported to one location. Sending it over the Internet network would take longer than moving it physically. Then the data analysis could begin. &lt;/p&gt;
&lt;h2&gt;How computer science was applied to generate the image?&lt;/h2&gt;
&lt;p&gt;Due to a limited set of samples in the visibility domain, we cannot reconstruct the image accurately. The team had to enforce constraints that were not implied by the measurements. That's how you may see different images that were reconstructed at different steps.&lt;/p&gt;
&lt;p&gt;In the first step, the team worked on correlating data from observation and replacing a weak signal by a stronger one hidden in that correlated data. This reduced data size from petabytes to terabytes. Observed data can be expressed by convolution formula f = g * h. In other words, we know that observed image f is equal to actual image g convoluted with factors that deformed observed image h, i.e. f = g * h, where f, g, h are functions and * stands for convolution. Factors that deformed black hole observed data are mainly caused by the atmosphere (different weather conditions among observatories) and calibration errors. We know f, more or less h and we have to solve this equation for g.&lt;/p&gt;
&lt;p&gt;In the second step, four teams were formed and they worked independently using different algorithms to produce the black hole image. Imaging algorithms can be generally divided into two categories: forward modeling and inverse modeling. In forward modeling, you take the current state of some object and you run your algorithm to see how your object changes in the future. Inverse modeling is the opposite of forward modeling, i.e. your model is in some state and you want to calculate what state can produce the initial state. The team used algorithms based on CLEAN for inverse modeling and RML - regularized maximum likelihood for forward modeling. Both are image reconstruction techniques that reverse the result effects of convolution on observed data. To learn more about these algorithms you can see &lt;a href="https://www.cv.nrao.edu/~abridle/deconvol/node1.html" target="_blank"&gt;this website&lt;/a&gt;. 
Here is a comparison of the images reconstructed by each team:&lt;/p&gt;
&lt;div style="display: block; width: 800px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1603/figure-4_opt.jpg"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;i&gt;Photo via &lt;a href="https://iopscience.iop.org/article/10.3847/2041-8213/ab0e85" target="_blank" rel="nofollow"&gt;IOPscience&lt;/a&gt;&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;In the third step, the team worked on choosing imaging parameters that produce in some sense the best picture. Among other things they tested different parameter values for synthetic images and restored images using those parameters. They selected geometric models that are similar to those observed in M87, e.g. ring, crescent, disk. See the image below for comparison of different algorithms that were run with the best-selected parameters. The last step was the final image validation. The team performed additional tests to assess the reliability of the created image.&lt;/p&gt;
&lt;div style="display: block; width: 800px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerds.co/media/1602/figure-10_opt.jpg"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div align="center"&gt;
&lt;i&gt;Photo via &lt;a href="https://iopscience.iop.org/article/10.3847/2041-8213/ab0e85" target="_blank" rel="nofollow"&gt;IOPscience&lt;/a&gt;&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;This procedure took almost two years to complete it. The final image is a result of a joint effort of &lt;a href="https://twitter.com/APSphysics/status/1116697842280693762" target="_blank"&gt;more than 200 researchers&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;If you want to see the black hole image in original size 7416 x 4320 px, follow &lt;a href="https://www.eso.org/public/images/eso1907a" target="_blank"&gt;this link&lt;/a&gt;. In the future, we can expect more detailed images as more telescopes are added to EHT array. Perhaps space telescopes could be used to enhance this image and maybe record video. The future is going to be exciting!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt;&lt;/br&gt;
1. &lt;a href="https://iopscience.iop.org/article/10.3847/2041-8213/ab0e85" target="_blank"&gt;The Event Horizon Telescope Collaboration et al 2019 ApJL 875 L4&lt;/a&gt;&lt;/br&gt;
2. Katie Bouman - &lt;a href="https://www.youtube.com/watch?v=UGL_OL3OrCE" target="_blank"&gt;Imaging a Black Hole with the Event Horizon Telescope&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;br /&gt; 
&lt;a href="https://www.linkedin.com/in/marcin-zarebski/" target="_blank"&gt;Marcin Zarębski&lt;/a&gt; is an experienced back-end developer, specializing in. .NET platform. He never ceases to amaze us with his skills in building complex backend solutions and infrastructure. Marcin is also interested in space exploration and the role of computer science in it. He likes to spend his free time in the mountains or playing board games. &lt;/p&gt;
</description>
      <pubDate>Thu, 09 May 2019 08:09:05 Z</pubDate>
      <a10:updated>2019-05-09T08:09:05Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">3199</guid>
      <link>https://angrynerds.co/blog/using-signalr-to-create-real-time-mobile-app/</link>
      <category>Development</category>
      <title>Using SignalR to create real-time mobile app</title>
      <description>&lt;p&gt;Let's imagine an app helping friends locate themselves. Every minute the app collects the current user location and sends it to the server, which resends this location to other connected users. In this blog post, we will show you how to setup SingalR on both server-side and mobile app.&lt;/p&gt;
&lt;h2&gt;What is SignalR?&lt;/h2&gt;
&lt;p&gt;SignalR is a &lt;a href="/services/net-development/" target="_blank"&gt;.NET&lt;/a&gt; library to create real-time applications. Opposite to regular HTTP communication, SignalR allows pushing messages from server-side to connected clients without any previous request. Thanks to bi-directional communication the mobile app does not have to ask the server to be up to date with the server content.&lt;/p&gt;
&lt;div align="center"&gt; 
&lt;img src="https://media.giphy.com/media/12NUbkX6p4xOO4/giphy.gif"&gt; 
&lt;/div&gt; 
&lt;p&gt;&lt;br /&gt;
SignalR frees developer of selecting transport type, by selecting the best available transport given by client and server side. &lt;code&gt;Websockets&lt;/code&gt; are not supported by the server? No problem, let's talk with &lt;code&gt;Long Pooling&lt;/code&gt;, or &lt;code&gt;Server Sent Events&lt;/code&gt;. SignalR provides an API that makes selected transport transparent.&lt;/p&gt;
&lt;h2&gt;Setup SignalR server&lt;/h2&gt;
&lt;p&gt;All SignalR server-side code is contained in a Hub which contains methods that can be called similarly to MVC Controllers. To be able to use those fully one need to register it in Startup.Configure as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.UseSignalR(route =&amp;gt;
{
    route.MapHub&amp;lt;SomeFancyNameHub&amp;gt;(&amp;quot;/FancyHub&amp;quot;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
Due to inheritance from SignalR Hub &lt;code&gt;SomeFancyNameHub: Hub&lt;/code&gt; you already have access to &lt;code&gt;Context&lt;/code&gt;, &lt;code&gt;Clients&lt;/code&gt; and &lt;code&gt;Groups&lt;/code&gt; properties.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; public abstract class Hub : IDisposable
    {
        protected Hub();

        public IHubCallerClients Clients { get; set; }
        public HubCallerContext Context { get; set; }
        public IGroupManager Groups { get; set; }

        public void Dispose();
        public virtual Task OnConnectedAsync();
        public virtual Task OnDisconnectedAsync(Exception exception);
        protected virtual void Dispose(bool disposing);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;This means for example that by overriding OnConnectedAsync() method for each connected client you can get it's connectionId from Context.ConnectionId, put it in one of the group from Groups using Groups.AddToGroupAsync() and notify all other Clients that a new one just joined the &lt;s&gt;club&lt;/s&gt; Hub!
From now till the hub is disposed server can access all those connections and notify clients whenever there is a need.  The only thing that limits you is your&lt;/p&gt;
&lt;div style="display: block; width: 400px; margin: 0 auto;"&gt; 
&lt;img src="https://media.giphy.com/media/QIiqoufLNmWo8/giphy.gif"&gt; 
&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;In our case, there is a mobile app that displays team member location on a map. The teams are defined earlier so backend knows how many members there are, which ones are active and while they are, what is their location.
Hub starts when first team member joins and based on his team name he is already grouped with.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Groups.AddToGroupAsync(Context.ConnectionId, usersTeamName);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
From now on all team members joining will be assigned to this group. And when they do, those methods would be invoked:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;await Clients.Caller.SendAsync(&amp;quot;TeamJoined&amp;quot;, JsonConvert.SerializeObject(teammates));

await Clients.OthersInGroup(usersTeamName).SendAsync(&amp;quot;TeammateJoined&amp;quot;, JsonConvert.SerializeObject(teammember));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
where &lt;code&gt;TeamMates&lt;/code&gt; is a collection of &lt;code&gt;TeamMember&lt;/code&gt;s and &lt;code&gt;TeamJoined&lt;/code&gt; along with &lt;code&gt;TeammateJoined&lt;/code&gt; are messages/methods our iOS client listenes to.&lt;/p&gt;
&lt;p&gt;So when a new team member joins the group, his name, profile picture and location is sent to other team members. This gives us the possibility to draw his avatar on a map in a precise location so his teammates could know where he currently is. At the same time, the team member gets the same info about his mates to draw on his map.&lt;/p&gt;
&lt;p&gt;To keep hub alive and to stop it from being disposed each team member sends its location once in a while. This updated location is then being sent to other teammates so the map could refresh.&lt;/p&gt;
&lt;p&gt;Thanks to SignalR hub we can have as many Groups as we like and keep the communication flow within that group (or team in our case).&lt;/p&gt;
&lt;h2&gt;Setup SignalR iOS client&lt;/h2&gt;
&lt;p&gt;To setup iOS client we will use &lt;a href="https://github.com/moozzyk/SignalR-Client-Swift"&gt;mooozyk/SignalR-Client-Swift&lt;/a&gt; github repository.&lt;/p&gt;
&lt;p&gt;Let's begin with initialization of Hub instance. In order to do that use &lt;code&gt;HubConnectionBuilder&lt;/code&gt; class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let hubConnection = HubConnectionBuilder(url: URL(string: &amp;quot;https://angrynerds.pl/stream&amp;quot;)!).build()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HubConnectionBuilder&lt;/code&gt; allows us to customize connection options, by setting custom HTTP headers, or append authorization token.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let hubConnection = HubConnectionBuilder(url: URL(string: &amp;quot;https://angrynerds.pl/stream&amp;quot;)!)
    .withHttpConnectionOptions { options in
        options.headers = [&amp;quot;foo&amp;quot;: &amp;quot;bar&amp;quot;]
        options.accessTokenProvider = {
            return userProvider.token
        }
}.build()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
After invoking &lt;code&gt;build()&lt;/code&gt; method we are ready to begin conversation with the server. To start connection call &lt;code&gt;start()&lt;/code&gt; on &lt;code&gt;HubConnection&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;SignalR API provides 2 basic methods to communicate - one to send the message, and the other to listen to any.&lt;/p&gt;
&lt;p&gt;In our example, we will notify the server about the current user location. To do it, we need to call &lt;code&gt;invoke(method: String, arguments: [Any?], invocationDidComplete: (Error?) -&amp;gt; Void)&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;method: String&lt;/code&gt; - method server is listening to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arguments: [Any?]&lt;/code&gt; - array of objects we want to send&lt;/li&gt;
&lt;li&gt;&lt;code&gt;invocationDidComplete: (Error?) -&amp;gt; Void)&lt;/code&gt; - completion handler after completed invocation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hub.invoke(method: &amp;quot;updateLocation&amp;quot;, arguments: [email, latitude, longitude], invocationDidComplete: nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
To be notified on each player location update we will use &lt;code&gt;hub.on(method: String, callback: ([Any?], TypeConverter) -&amp;gt; Void)&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;method: String&lt;/code&gt; - method server is listening to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;callback: ([Any?], TypeConverter) -&amp;gt; Void)&lt;/code&gt; - callback method with 2 parameters, arguments and converter object, which helps us decode arguments to desired type&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are expecting json data as the only parameter in the server message. JSON should contain a list of connected users with their current location.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hub.on(method: method.rawValue, callback: { (args, typeConverter) in    
    guard let jsonString = try? typeConverter.convertFromWireType(obj: args[0], targetType: String.self),
      let data = jsonString?.data(using: .utf8),
      let users = try? JSONDecoder().decode([User].self, for: data)
      else { return }
    self.updateUI(with: users)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;
If we need to be up to date with connection status we can implement &lt;code&gt;HubConnectionDelegate&lt;/code&gt; methods.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func connectionDidOpen(hubConnection: HubConnection!)
func connectionDidFailToOpen(error: Error)
func connectionDidClose(error: Error?)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div style="display: block; width: 300px; margin: 0 auto;"&gt;
&lt;img src="https://angrynerdsweb.blob.core.windows.net/media/1671/signalr_opt.gif"&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;Want to know more about the magic you can do with SignalR? Let us know if there's a specific topic you'd like us to cover!&lt;br /&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;About the Authors&lt;/strong&gt;&lt;br /&gt;
&lt;a href="https://www.linkedin.com/in/%C5%82ukasz-lech-528219ab/" target="_blank"&gt;Łukasz Lech&lt;/a&gt; is an iOS developer at Angry Nerds - and one of the main creators of our iconic &lt;a href="https://angrynerds.co/projects/cats-and-dogs-the-weather-app/" target="_blank"&gt;Cats and Dogs app&lt;/a&gt;! He’s a Swift enthusiast and he likes to explore this language’s potential as a backend technology. Łukasz is always up to date with all things Apple and he’s also interested in UX/UI design for mobile apps. &lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/jakub-tomalski-a57596bb/" target="_blank"&gt;Jakub Tomalski&lt;/a&gt; is one of our most experienced .NET developers. As he says himself, he is fascinated by the power of API, so backend was the only career path he could choose! He specializes in backend development for mobile apps, but he has also hands-on experience working with web solutions. &lt;/p&gt;
</description>
      <pubDate>Wed, 21 Nov 2018 10:28:27 Z</pubDate>
      <a10:updated>2018-11-21T10:28:27Z</a10:updated>
    </item>
  </channel>
</rss>