<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Valentin Prugnaud 🦊</title>
    <description>The latest articles on DEV Community by Valentin Prugnaud 🦊 (@valentinprgnd).</description>
    <link>https://dev.to/valentinprgnd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F245967%2F2a0543d7-7363-4e50-8d96-61e003395085.png</url>
      <title>DEV Community: Valentin Prugnaud 🦊</title>
      <link>https://dev.to/valentinprgnd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/valentinprgnd"/>
    <language>en</language>
    <item>
      <title>AI Content Creation: a Challenge or Opportunity for Publishing Platforms?</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Fri, 09 Jun 2023 18:00:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/ai-content-creation-a-challenge-or-opportunity-for-publishing-platforms-43ff</link>
      <guid>https://dev.to/valentinprgnd/ai-content-creation-a-challenge-or-opportunity-for-publishing-platforms-43ff</guid>
      <description>&lt;p&gt;As AI is gaining in traction and democratizes content creation, it presents both challenges and opportunities for publishing platforms. Shall they fight it or embrace it?&lt;/p&gt;

&lt;p&gt;In the age of digital revolution, artificial intelligence (AI) has been pivotal, altering the landscape of many sectors, including content creation. As AI technology, particularly large language models, becomes more accessible to everyday users, we are witnessing an unprecedented democratization of content creation. However, this paradigm shift raises pertinent questions: Should publishing platforms take notice, and if so, should they resist or embrace this change?&lt;/p&gt;

&lt;p&gt;There are a few reason why AI could actually benefit publishing platforms and assist a lot of folks to share their ideas more effectively. &lt;/p&gt;

&lt;h2&gt;
  
  
  Human-AI Collaboration
&lt;/h2&gt;

&lt;p&gt;Historically, busy individuals and companies have often employed ghostwriters to produce content. Now, in the AI era, these ghostwriters are increasingly being replaced by algorithms. The time-saving potential of AI is significant. It's like having a personal writing assistant who never tires, always available at your beck and call.&lt;/p&gt;

&lt;p&gt;Now, this isn’t necessarily a bad thing. A lot of folks would love to share their ideas, but simply don’t have the time or get struck with writer’s block. Using ChatGPT or similar to help you organize your thoughts and guide you in the outline process, even generate some basic paragraphs to help you get started is a good thing.  &lt;/p&gt;

&lt;p&gt;AI doesn't generate content from nothingness. Large language models require human prompts to guide their outputs. Humans are still very much in the driver's seat, providing the creative direction and oversight. &lt;/p&gt;

&lt;h2&gt;
  
  
  AI as a Language Equalizer
&lt;/h2&gt;

&lt;p&gt;AI in content creation also holds promise as a language equalizer. Non-native English speakers can greatly benefit from AI models that help redact their ideas into coherent, well-written articles. &lt;/p&gt;

&lt;p&gt;However, some platforms are imposing a mandatory disclosure of AI assistance. This could inadvertently discriminate against these individuals. Readers will see the “AI-assisted” tag or footnote and automatically disregard the article, even if AI played only a small part in it.&lt;/p&gt;

&lt;p&gt;The debate over AI-assistance disclosure is a complex one and far from settled, but we should keep in mind that a lot of folks are using AI-assistance to write content in good faith and should not be penalized for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of Publishing Platforms in the AI era
&lt;/h2&gt;

&lt;p&gt;Publishing platforms face a crossroads: to resist or embrace AI-written or AI-assisted content. Different platforms may choose different strategies, depending on their goals and audiences. &lt;/p&gt;

&lt;p&gt;However, considering the advantages of AI in content creation, it may be wise to adapt and integrate AI-assisted writing rather than fighting it. Publishing platforms are also, in most cases, promoting and facilitating freedom of expression. That should include the right to express your opinions and ideas, whichever way you choose, AI-assisted or not.&lt;/p&gt;




&lt;p&gt;The rise of AI in content creation presents both challenges and opportunities. As AI technology continues to evolve, so too will its role in content generation and our discussions around it. Perhaps the most vital thing, whether we are readers, writers, or publishers, is to stay engaged in this conversation, ready to adapt and evolve with the changing landscape of AI and writing.&lt;/p&gt;

&lt;p&gt;Originally published on: &lt;a href="https://whatdafox.substack.com/p/ai-content-creation-a-challenge-or"&gt;https://whatdafox.substack.com/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Navigating Developer-Led Projects: Characteristics, Benefits, and Challenges</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Mon, 05 Jun 2023 07:00:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/navigating-developer-led-projects-characteristics-benefits-and-challenges-ak3</link>
      <guid>https://dev.to/valentinprgnd/navigating-developer-led-projects-characteristics-benefits-and-challenges-ak3</guid>
      <description>&lt;p&gt;Today's business landscape is marked by constant change and innovation, driven by a fast-paced digital environment that demands agility, adaptability, and creativity. In this context, traditional project management models may no longer be sufficient to keep up with the pace of technological advancements and the evolving needs of customers and end-users.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;developer-led projects&lt;/strong&gt;, a new approach to project management that empowers developers to take ownership of projects and drive innovation from the front lines.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the characteristics, benefits, and challenges of developer-led projects and provide practical tips for navigating this exciting new terrain.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are developer-led projects?
&lt;/h2&gt;

&lt;p&gt;Developer-led projects are a new approach to project management that puts developers in charge of the project's direction and execution. In this model, developers are given a high degree of autonomy and responsibility to lead the project from start to finish.&lt;/p&gt;

&lt;p&gt;Developer-led projects can bring a strong sense of ownership and accountability for developers. In this model, developers are not simply responsible for writing code, but they are also expected to take an active role in defining project goals, making strategic decisions, and ensuring that the project is successful. This sense of ownership can lead to a higher level of motivation and engagement among developers, as they feel empowered to take ownership of their work and see the impact of their contributions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the benefits?
&lt;/h2&gt;

&lt;p&gt;Developer-led projects offer a number of benefits over traditional, top-down project management models. Here are a few of the key benefits of developer-led projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Improved collaboration and teamwork: In developer-led projects, developers are empowered to take ownership of the project and work closely with other stakeholders to achieve project goals. This fosters a culture of collaboration and teamwork, as developers are encouraged to share ideas, ask questions, and work together to solve problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Greater innovation and creativity: By giving developers a high degree of autonomy and responsibility, developer-led projects can foster a culture of innovation and creativity. Developers are encouraged to experiment, take risks, and try out new ideas, which can lead to breakthroughs and new approaches to problem-solving.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased agility and flexibility: Developer-led projects are often associated with agile methodologies, which prioritize flexibility and adaptability. This means that developers can make decisions on the fly, iterate quickly based on feedback, and adjust the project's direction as needed to ensure that it meets customer needs and strategic goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved quality: By putting developers in charge of the project, organizations can tap into their technical expertise and attention to detail to ensure that the project meets high quality standards. Developers are often better positioned than other stakeholders to identify potential technical issues and ensure that the code is clean, efficient, and well-documented.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Higher level of developer engagement: When developers are given a high degree of autonomy and responsibility, they are more likely to feel engaged and motivated in their work. This can lead to higher levels of job satisfaction, reduced turnover, and improved overall performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, developer-led projects represent a new approach to project management that can offer a range of benefits over traditional top-down models. By empowering developers to take ownership of the project and work closely with other stakeholders, organizations can tap into their creativity, problem-solving skills, and technical expertise to drive innovation and improve the quality of the final product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the challenges?
&lt;/h2&gt;

&lt;p&gt;While developer-led projects offer a number of benefits, they can also present some unique challenges. Here are a few of the key challenges that organizations may face when implementing a developer-led approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Lack of project management expertise: Developers may not have the same level of experience or expertise in project management as traditional project managers, which can lead to difficulties in areas such as planning, scheduling, and resource allocation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of alignment with business objectives: In some cases, developers may be more focused on technical excellence than on meeting business objectives or customer needs. This can lead to a misalignment between the project goals and the overall strategic direction of the organization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Potential for scope creep: Developer-led projects can be more flexible and agile than traditional top-down approaches, but this can also lead to scope creep if developers are not careful. Without clear direction and guidance, developers may be tempted to add features or functionality that are not essential to the project's success, leading to delays, cost overruns, and other issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Difficulty in managing stakeholder expectations: In developer-led projects, developers are often the primary point of contact for stakeholders such as business leaders, customers, and end-users. This can lead to difficulties in managing stakeholder expectations and ensuring that the project meets the needs of all parties involved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Challenges in team dynamics: Developer-led projects can be highly collaborative and team-oriented, but they can also present challenges in team dynamics if developers are not used to working closely with other stakeholders or developers from other teams. It is important to establish clear communication channels, roles and responsibilities, and decision-making processes to ensure that everyone is working together effectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, while developer-led projects can offer many benefits, they require careful planning and management to ensure that they are successful. In the next section, we’ll go over a few strategies for overcoming these challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to overcome/mitigate them?
&lt;/h2&gt;

&lt;p&gt;Developer-led projects aren’t a silver bullet and always a replacement for traditional project-management approaches. However, many challenges can be avoided with a few strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ensure that everyone on the team understands the project goals and how they align with the overall strategic direction of the organization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clearly define the project scope, timeline, and deliverables, to avoid scope creep and ensure that everyone is working towards the same goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Establish clear communication channels and protocols, to ensure that everyone is kept informed and up-to-date on project progress and issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hold regular team meetings and status updates, to ensure that everyone is aligned and working towards the same goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Establish a process for identifying and mitigating risks, and ensure that everyone on the team is aware of their roles and responsibilities in managing risks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encourage open communication about potential issues and challenges, and work collaboratively to address them as soon as they arise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regularly review project processes and practices, and look for ways to optimize and streamline them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Document every decision and encourage every developer to do so.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When should you consider developer-led projects?
&lt;/h2&gt;

&lt;p&gt;Developer-led projects can be a good fit in many situations, but there are some scenarios where they are particularly effective. Here are a few situations where a developer-led approach may be the right choice:&lt;/p&gt;

&lt;h3&gt;
  
  
  When the project is highly technical
&lt;/h3&gt;

&lt;p&gt;For highly technical projects, a developer-led approach can be particularly effective because developers are often best equipped to understand and solve complex technical problems.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Adopting a new architecture for applications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Breaking down a monolithic application to microservices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing infrastructure changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moving to another cloud provider&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Migrating to new CI/CD tooling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When there is a need for innovation
&lt;/h3&gt;

&lt;p&gt;Innovation is often driven by experimentation and creativity, which are qualities that many developers possess. By putting developers in charge of a project, organizations can encourage a culture of innovation and experimentation, which can lead to new and innovative solutions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Experimenting with new technologies (AI, Blockchain, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exploring a new product idea&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Attempting to reduce toil&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When speed is critical
&lt;/h3&gt;

&lt;p&gt;When speed is critical, a developer-led project can be an effective way to accelerate the project timeline. Developers are often able to work more quickly and efficiently than traditional project managers, and they are better equipped to handle the technical challenges that may arise during the project. In addition, a developer-led approach can be more agile and flexible, allowing developers to adapt to changing requirements or unexpected challenges more quickly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Paying tech-debt&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Refactoring an application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reducing dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improving performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When collaboration is important
&lt;/h3&gt;

&lt;p&gt;Collaboration is a key factor in the success of many projects, and a developer-led approach can be particularly effective for fostering collaboration and teamwork. When an initiative impacts the work of multiple teams, it might be worth creating a dedicated “task-force” to iterate on the ideal solution.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Choosing and implementing a feature flagging solution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choosing and implementing an analytics pipeline&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choosing and implementing observability tooling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;etc.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Ultimately, the success of any project depends on a range of factors, including the project team's skills and expertise, the project's goals and objectives, and the organization's culture and values. But by embracing a developer-led approach for some projects, organizations can tap into the power of technology and innovation to drive growth, innovation, and success.&lt;/p&gt;





&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://whatdafox.substack.com/p/navigating-developer-led-projects" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--lSgSrbSN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://substackcdn.com/image/fetch/w_1200%2Ch_600%2Cc_fill%2Cf_jpg%2Cq_auto:good%2Cfl_progressive:steep%2Cg_auto/https%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F2013c006-0008-4d65-bf4b-ecc96af283ce_1024x1024.png" height="469" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://whatdafox.substack.com/p/navigating-developer-led-projects" rel="noopener noreferrer" class="c-link"&gt;
          Navigating Developer-Led Projects: Characteristics, Benefits, and Challenges
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Developer-led projects are a new approach to project management that empowers developers to take ownership of projects and drive innovation.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--haMrxdI9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://substackcdn.com/image/fetch/f_auto%2Cq_auto:good%2Cfl_progressive:steep/https%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F8ba8e60d-a573-40b5-83c9-0346337fef54%252Ffavicon.ico" width="64" height="64"&gt;
        whatdafox.substack.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>The Importance of Developer Experience</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Sat, 03 Jun 2023 20:50:35 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/the-importance-of-developer-experience-3ime</link>
      <guid>https://dev.to/valentinprgnd/the-importance-of-developer-experience-3ime</guid>
      <description>&lt;p&gt;Developer Experience, or DX, is a critical aspect of software development in the modern enterprise. It encompasses the tools, processes, and environment that developers use to build, test, and deploy software. In recent years, there has been growing recognition of the importance of DX and its impact on developer productivity and mental health. In this article, we'll explore why DX matters and what enterprises can do to improve the experience of their developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developer Experience Matters
&lt;/h2&gt;

&lt;p&gt;The development experience has a direct impact on the quality of the software produced and the productivity of the developers themselves. Poor DX can lead to increased frustration, decreased motivation, and lower productivity among developers. On the other hand, a positive DX can lead to higher job satisfaction, increased motivation, and improved productivity.&lt;/p&gt;

&lt;p&gt;One of the key benefits of improving developer experience is that it helps to reduce the stress and burnout that can come from working in a fast-paced, complex environment. When developers are given the tools and processes they need to get their work done efficiently, they are more likely to feel in control and less stressed. Additionally, a positive development environment can help to build trust and foster collaboration among team members, which can lead to more effective problem-solving and faster resolution of technical issues.&lt;/p&gt;

&lt;p&gt;Another important benefit of improving DX is increased productivity. Developers who are able to work more efficiently are able to focus on high-value tasks and get more done in less time. This, in turn, can help to improve the speed of software delivery and reduce the time-to-market for new features and products. Additionally, by improving the development process and reducing the time and effort required to complete tasks, enterprises can help to reduce the risk of burnout among their developers and increase the long-term sustainability of their development teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving Developer Experience
&lt;/h2&gt;

&lt;p&gt;So, how can enterprises improve the developer experience for their teams? There are a number of key steps that they can take, including:&lt;/p&gt;

&lt;p&gt;Invest in the right tools and technologies. This includes not just software development tools, but also other technologies that can help to streamline the development process, such as project management and collaboration tools, version control systems, and testing and deployment tools.&lt;/p&gt;

&lt;p&gt;Foster a positive work environment. This includes creating an inclusive and supportive work environment that values diversity and fosters collaboration. It also includes providing developers with the resources and support they need to be successful, such as mentorship and training programs, flexible work arrangements, and access to mental health resources.&lt;/p&gt;

&lt;p&gt;Encourage a culture of continuous improvement. This includes encouraging developers to share their feedback and ideas for improvement, and to participate in hackathons, code sprints, and other collaborative initiatives that can help to improve the development process.&lt;/p&gt;

&lt;p&gt;Provide clear communication and expectations. This includes establishing clear expectations for development work, such as timelines, deliverables, and project goals, as well as providing regular feedback and recognition to developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, the development experience is a critical aspect of software development that has a significant impact on both developer productivity and mental health. By investing in the right tools and technologies, fostering a positive work environment, encouraging a culture of continuous improvement, and providing clear communication and expectations, enterprises can improve the experience of their developers and achieve better outcomes for their development teams and their businesses as a whole.&lt;/p&gt;





&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://whatdafox.substack.com/embed" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--WyZA8ss3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://substackcdn.com/image/fetch/f_auto%2Cq_auto:best%2Cfl_progressive:steep/https%253A%252F%252Fwhatdafox.substack.com%252Ftwitter%252Fsubscribe-card.jpg%253Fv%253D-1551491128%2526version%253D9" height="417" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://whatdafox.substack.com/embed" rel="noopener noreferrer" class="c-link"&gt;
          WhatDaFox | Valentin Prugnaud | Substack
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Thoughts on technology, developer experience, mental health, and more... Click to read WhatDaFox, by Valentin Prugnaud, a Substack publication. Launched 8 months ago.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--haMrxdI9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://substackcdn.com/image/fetch/f_auto%2Cq_auto:good%2Cfl_progressive:steep/https%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F8ba8e60d-a573-40b5-83c9-0346337fef54%252Ffavicon.ico" width="64" height="64"&gt;
        whatdafox.substack.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Custom v-model with Vue.js: Update</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Thu, 11 Aug 2022 20:25:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/custom-v-model-with-vuejs-update-3han</link>
      <guid>https://dev.to/valentinprgnd/custom-v-model-with-vuejs-update-3han</guid>
      <description>&lt;p&gt;A while back, in 2019, I wrote an article demonstrating how to create a custom Vue component, and handle the &lt;code&gt;v-model&lt;/code&gt; capabilities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/valentinprgnd/wrap-a-text-field-in-a-component-with-vue-js-gak"&gt;https://dev.to/valentinprgnd/wrap-a-text-field-in-a-component-with-vue-js-gak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently discovered an alternative way to do it, which does not require a watcher, thus making the code much faster and less resource heavy.&lt;/p&gt;

&lt;p&gt;The original post suggested this method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"custom-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"localValue"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TextField&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="c1"&gt;// 1. Receives the value as a prop&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;localValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 2. Copy the value in a local value variable&lt;/span&gt;

    &lt;span class="c1"&gt;// Set a watcher to emit the changes to the parent component&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localValue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While functional, the use of a watcher here can be really resource heavy (particularly if you create a lot of such components). &lt;/p&gt;

&lt;p&gt;A better approach would be to use a computed property, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"custom-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"localValue"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TextField&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="c1"&gt;// 1. Receives the value as a prop&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;localValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only it reduces the boilerplate code, but it also avoids the use of a watcher, making your component faster and less resource heavy 🎉&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Moderate posts automatically with the Perspective API</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Fri, 10 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/moderate-posts-automatically-with-the-perspective-api-3ph0</link>
      <guid>https://dev.to/valentinprgnd/moderate-posts-automatically-with-the-perspective-api-3ph0</guid>
      <description>&lt;p&gt;We all know the Internet we know and love isn't always a safe place, but there are innovations that we can easily &lt;br&gt;
leverage to make it a better place.&lt;/p&gt;

&lt;p&gt;Recently, amid this whole COVID–19 situation, my co-founders and I decided to create a platform, for Canadians to thank&lt;br&gt;
all the workers working on the front lines, risking their lives, for us while we stay at home: &lt;a href="https://togethernorth.ca"&gt;Together North&lt;/a&gt;. The whole country and many other places in the world started clapping and cheering at a dedicated time every day to show their gratitude. &lt;br&gt;
But we thought it would be a good idea to have a dedicated place where people could leave their gratitude messages, share it directly with &lt;br&gt;
the people they are cheering for and keep it online as a reminder.&lt;/p&gt;

&lt;p&gt;And it was a good idea. The only problem was: some people don't go on the Internet to share love and compassion, but to write mean comments&lt;br&gt;
and spread hate instead. And Together North was a perfect target: we are a small team and it is an open text message. There is room for abuse and we can't monitor every message manually.&lt;/p&gt;

&lt;p&gt;Here comes the &lt;a href="https://www.perspectiveapi.com/"&gt;Perspective API&lt;/a&gt;. I decided to use this API to evaluate every incoming message&lt;br&gt;
and decide whether or not that message should be published, or if it should be flagged and evaluated by a human.&lt;/p&gt;

&lt;p&gt;Let's dive into how it works.&lt;/p&gt;
&lt;h2&gt;
  
  
  Concept
&lt;/h2&gt;

&lt;p&gt;The concept is simple: create a Firebase Function to evaluate any incoming message upon creation, run it through the Perspective API and based on the "Toxicity" result, decide whether or not we should display it or not.&lt;/p&gt;

&lt;p&gt;After running a few manual tests with carefully chosen words, I decided to use a threshold of 25% toxicity. Anything above 25% would be flagged as "toxic", unpublished and forwarded to us in a dedicated Slack channel for human evaluation. Anything below 25% would automatically be approved, published on the platform but also forwarded into our Slack channel for good measure and proofreading just in case.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We already have a "messages" collection on Firestore where we store all of our incoming messages. To decide whether or not we should display the message, we updated every document with a "published" flag. If true, it is displayed on the platform, if not, it is hidden until further notice.&lt;/p&gt;

&lt;p&gt;Then, we created the Firebase Function with the code to evaluate the message and send the alerts. This function is triggered every time a message is created in the collection on Firestore.&lt;/p&gt;

&lt;p&gt;Let's take a look at the code, shall we?&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Here is the code we used for the Firebase Function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Perspective&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;perspective-api-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get-value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@slack/web-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;perspective&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Perspective&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;perspective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api_key&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;moderateMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages/{message}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Evaluate toxicity of the message via the Perspective API&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;perspective&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toxicity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;attributeScores.TOXICITY.summaryScore.value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toxicity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Message is safe, approve it&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@channel A safe message has been published on Together North! https://togethernorth.ca/m/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@channel A safe message has been published on Together North! https://togethernorth.ca/m/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fields&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`*ID*: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`*Message*:\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}],&lt;/span&gt;
            &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#together-north&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;moderationScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toxicity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 

    &lt;span class="c1"&gt;// Message is not safe, send a message to Slack&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;slack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@channel A suspicious message has been blocked on Together North!`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;section&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@channel A suspicious message has been blocked on Together North!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fields&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`*ID*: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mrkdwn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`*Message*:\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#together-north&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firestore&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;moderationScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toxicity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;published&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The logic is fairly simple: when a message is created, run the message through the Perspective API, if the toxicity level&lt;br&gt;
is below 25%, share it in our Slack channel with the URL for easy reference and mark it as published. We store the toxicity&lt;br&gt;
report from the API as well out of curiosity. &lt;/p&gt;

&lt;p&gt;However, if the message has a toxicity level higher than 25%, then we send a different Slack notification to our Slack channel,&lt;br&gt;
mark the document as unpublished and store the toxicity report as well for easy review by our team.&lt;/p&gt;

&lt;p&gt;If you are curious about using Firebase, the Perspective API or the Slack API, get in touch with me &lt;a href="https://twitter.com/valentinprgnd"&gt;on Twitter&lt;/a&gt; or in the comments.&lt;/p&gt;




&lt;p&gt;PS: If you live in Canada or just want to share the love, leave a message on &lt;a href="https://togethernorth.ca"&gt;Together North&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>productivity</category>
      <category>firebase</category>
      <category>node</category>
    </item>
    <item>
      <title>Unit Testing with Nuxt.js</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Fri, 06 Mar 2020 08:21:01 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/unit-testing-with-nuxt-js-37fj</link>
      <guid>https://dev.to/valentinprgnd/unit-testing-with-nuxt-js-37fj</guid>
      <description>&lt;p&gt;I’m currently working on an app built with Nuxt.js. I have written a couple tests, but they only test component mounting and its template against a snapshot, but it doesn’t test much and it doesn’t seem scalable.&lt;/p&gt;

&lt;p&gt;I’m more of a backend dev initially, so I am not familiar with the best practices to write unit tests with Nuxt/Vue.js.&lt;/p&gt;

&lt;p&gt;Any tips or best practices to run unit tests with Nuxt/Vue at scale? What is your experience with it?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>vue</category>
    </item>
    <item>
      <title>Productivity Pixel - Automate everything</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Fri, 28 Feb 2020 22:28:18 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/productivity-pixel-automate-everything-doa</link>
      <guid>https://dev.to/valentinprgnd/productivity-pixel-automate-everything-doa</guid>
      <description>&lt;h2&gt;
  
  
  1 - CI/CD tools
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zxgiiKD4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/2s63bk2ydnaus33xnc9n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zxgiiKD4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/2s63bk2ydnaus33xnc9n.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitLab CI, GitHub Actions, Travis CI, Circle CI… you name it! Take advantage of these amazing tools to automate your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Command Line
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8vCfocDw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vij9xslqik4gjswhbepq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8vCfocDw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vij9xslqik4gjswhbepq.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Often overlooked, the command line is also an amazing tool. You can write small apps or scripts to automate part of your workflow or even the whole thing!&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Slack
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D3MfU5L2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/mwss7q6lt3wvan850zto.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D3MfU5L2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/mwss7q6lt3wvan850zto.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;“ChatOps” are all the rage these days, and for a good reason: it’s convenient and easy to share with your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 - Pub/Sub &amp;amp; Cloud Functions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1eb5oBpa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8bsimle1f0luy68dyxae.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1eb5oBpa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8bsimle1f0luy68dyxae.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This combo requires a bit more work, but leveraging a Pub/Sub topic with a few Cloud Functions can do wonders!&lt;/p&gt;




&lt;p&gt;You can also find these pixels on my Instagram: &lt;a href="https://instagram.com/valentinprgnd"&gt;https://instagram.com/valentinprgnd&lt;/a&gt;. I will publish Pixels every Monday, Wednesday, and Friday about career development in tech, code, mental health and health for developers. Follow me for more tips @valentinprngd and check out my podcast &lt;a href="https://rebased.whatdafox.com"&gt;https://rebased.whatdafox.com&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Code Pixel - Write better documentation</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Thu, 27 Feb 2020 00:39:35 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/code-pixel-write-better-documentation-3cp8</link>
      <guid>https://dev.to/valentinprgnd/code-pixel-write-better-documentation-3cp8</guid>
      <description>&lt;h2&gt;
  
  
  1 - Stay simple
&lt;/h2&gt;

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

&lt;p&gt;We all want to add every single detail in our documentation. But sometimes, less is more. Get straight to the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Avoid patronizing vocabulary
&lt;/h2&gt;

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

&lt;p&gt;“It’s super easy”… Yet, if your users are struggling to follow the steps in your documentation, that can make them feel bad and give up. Avoid patronizing language in your documentation as much as you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Make it searchable
&lt;/h2&gt;

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

&lt;p&gt;If your documentation is a standalone site, make it searchable. Tools like Algolia allow you to implement a search engine on your site with a few steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 - Be polyglot
&lt;/h2&gt;

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

&lt;p&gt;If you can, display the code snippets in multiple languages, relevant to your users.&lt;/p&gt;




&lt;p&gt;You can also find these pixels on my Instagram: &lt;a href="https://instagram.com/valentinprgnd" rel="noopener noreferrer"&gt;https://instagram.com/valentinprgnd&lt;/a&gt;. I will publish Pixels every Monday, Wednesday, and Friday about career development in tech, code, mental health and health for developers. Follow me for more tips @valentinprngd and check out my podcast &lt;a href="https://rebased.whatdafox.com" rel="noopener noreferrer"&gt;https://rebased.whatdafox.com&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Career Pixel - Be a better programmer</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Tue, 25 Feb 2020 08:25:47 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/career-pixel-be-a-better-programmer-2hng</link>
      <guid>https://dev.to/valentinprgnd/career-pixel-be-a-better-programmer-2hng</guid>
      <description>&lt;h2&gt;
  
  
  1 - Be nice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PcLyq9FN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cu999j1lqbux1d3mmcm4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PcLyq9FN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cu999j1lqbux1d3mmcm4.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be nice to your co-workers, clients, you name it. Listen closely and help them whenever you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Be empathetic
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P0NIcdSe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cmh15nibpxv5pamwkfze.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P0NIcdSe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cmh15nibpxv5pamwkfze.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To me, empathy is the most important skill a programmer should have. Make a conscious effort to understand your co-workers' point of view, your users' point of view. Try your best to understand where they are coming from.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Be organized
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kH7FmKGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/ivd08p8lt5uqqpqmaoi7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kH7FmKGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/ivd08p8lt5uqqpqmaoi7.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep track of your tasks. find your rhythm and habits, and be consistent. Document EVERYTHING.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 - Be a mentor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aKrmQKQf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/zsipvnqreki0wu47ddnx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aKrmQKQf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/zsipvnqreki0wu47ddnx.jpg" alt="Alt Text" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s one thing I believe in: you never truly know something until you can successfully teach it. Mentor or help others with their projects or even a simple task. Not only it’s a nice thing to do, but it will also improve your skills in the process.&lt;/p&gt;




&lt;p&gt;You can also find these pixels on my Instagram: &lt;a href="https://instagram.com/valentinprgnd"&gt;https://instagram.com/valentinprgnd&lt;/a&gt;. I will publish Pixels every Monday, Wednesday, and Friday about career development in tech, code, mental health and health for developers. Follow me for more tips @valentinprngd and check out my podcast &lt;a href="https://rebased.whatdafox.com"&gt;https://rebased.whatdafox.com&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy Vue.js on Google Cloud Run</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Tue, 25 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/deploy-vue-js-on-google-cloud-run-ddn</link>
      <guid>https://dev.to/valentinprgnd/deploy-vue-js-on-google-cloud-run-ddn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Repository: &lt;a href="https://github.com/WhatDaFox/vuejs-cloud-run-poc"&gt;WhatDaFox/vuejs-cloud-run-poc&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Configure Google Cloud
&lt;/h2&gt;

&lt;p&gt;To be able to build and deploy, you will need a Google Cloud project, with a billing account set up, as well as&lt;br&gt;
the &lt;a href="https://cloud.google.com/sdk/gcloud"&gt;Google Cloud CLI&lt;/a&gt; installed.&lt;/p&gt;

&lt;p&gt;Then you will need to create a configuration for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud config configurations create cloud-run
&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud auth login &lt;span class="c"&gt;# and follow the steps&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project YOUR_PROJECT_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @vue/cli
&lt;span class="nv"&gt;$ &lt;/span&gt;vue create cloud-run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue CLI creates a Single Page Application type of project, so I needed to install &lt;code&gt;serve&lt;/code&gt; to serve the project after the build. &lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;serve&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had to update the &lt;code&gt;package.json&lt;/code&gt; file with the "start" script, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serve -p $PORT dist/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to create the &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Dockerfile
&lt;/h2&gt;

&lt;p&gt;Now we can build the app and run the &lt;code&gt;start&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use the official lightweight Node.js 12 image.&lt;/span&gt;
&lt;span class="c"&gt;# https://hub.docker.com/_/node&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12-alpine&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PORT=8080&lt;/span&gt;

&lt;span class="c"&gt;# Create and change to the app directory.&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-ex&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser node root &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;chmod &lt;/span&gt;g+w /app &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apk add &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;      g++ make python &lt;span class="se"&gt;\
&lt;/span&gt;      openjdk8-jre

&lt;span class="c"&gt;# Copy application dependency manifests to the container image.&lt;/span&gt;
&lt;span class="c"&gt;# A wildcard is used to ensure both package.json AND package-lock.json are copied.&lt;/span&gt;
&lt;span class="c"&gt;# Copying this separately prevents re-running npm install on every code change.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install production dependencies.&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci

&lt;span class="c"&gt;# Copy local code to the container image.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Run the web service on container startup.&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "npm", "run", "start" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build &amp;amp; Deploy
&lt;/h2&gt;

&lt;p&gt;Now, we can use Cloud Build to build our docker image. Cloud Build will automatically detect our &lt;code&gt;Dockerfile&lt;/code&gt;, build, &lt;br&gt;
and push our image in Google Container Registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; gcr.io/YOUR_PROJECT/helloworld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done, we can run the following command to deploy our new revision to Cloud Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud run deploy &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/YOUR_PROJECT/helloworld &lt;span class="nt"&gt;--platform&lt;/span&gt; managed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benchmark
&lt;/h2&gt;

&lt;p&gt;When testing, I ran a small (to avoid crazy costs) benchmark with Apache Benchmark. &lt;/p&gt;

&lt;p&gt;Here is the command I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ab &lt;span class="nt"&gt;-n&lt;/span&gt; 1000 &lt;span class="nt"&gt;-c&lt;/span&gt; 80 https://cloud-run-url/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 1843412 $&amp;gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking helloworld-2fjcn3qpbq-uw.a.run.app (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Google
Server Hostname:        helloworld-2fjcn3qpbq-uw.a.run.app
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-CHACHA20-POLY1305,2048,256
Server Temp Key:        ECDH X25519 253 bits
TLS Server Name:        helloworld-2fjcn3qpbq-uw.a.run.app

Document Path:          /
Document Length:        746 bytes

Concurrency Level:      80
Time taken for tests:   8.671 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      1272004 bytes
HTML transferred:       746000 bytes
Requests per second:    115.33 [#/sec] (mean)
Time per request:       693.656 [ms] (mean)
Time per request:       8.671 [ms] (mean, across all concurrent requests)
Transfer rate:          143.26 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       49  391 156.9    370     888
Processing:    32  252 106.9    285     878
Waiting:       28  198 101.0    185     876
Total:        313  643 204.8    620    1398

Percentage of the requests served within a certain time (ms)
  50%    620
  66%    703
  75%    734
  80%    790
  90%    898
  95%   1054
  98%   1136
  99%   1194
 100%   1398 (longest request)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Really easy to deploy VueJS on Cloud Run and the performances aren't bad, even with a cold start.&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>devops</category>
      <category>tutorials</category>
      <category>vue</category>
    </item>
    <item>
      <title>Deploy NestJS with Fastify on Google Cloud Run</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Thu, 20 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/deploy-nestjs-with-fastify-on-google-cloud-run-1gl7</link>
      <guid>https://dev.to/valentinprgnd/deploy-nestjs-with-fastify-on-google-cloud-run-1gl7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Repository: &lt;a href="https://github.com/WhatDaFox/nestjs-fastify-cloud-run-poc"&gt;WhatDaFox/nestjs-fastify-cloud-run-poc&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Configure Google Cloud
&lt;/h2&gt;

&lt;p&gt;To be able to build and deploy, you will need a Google Cloud project, with a billing account set up, as well as&lt;br&gt;
the &lt;a href="https://cloud.google.com/sdk/gcloud"&gt;Google Cloud CLI&lt;/a&gt; installed.&lt;/p&gt;

&lt;p&gt;Then you will need to create a configuration for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud config configurations create cloud-run
&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud auth login &lt;span class="c"&gt;# and follow the steps&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project YOUR_PROJECT_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the project
&lt;/h2&gt;

&lt;p&gt;For this proof of concept, I will only use the default NestJS application, that contains a single endpoint &lt;code&gt;/&lt;/code&gt;&lt;br&gt;
returning &lt;code&gt;Hello world!&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @nestjs/cli
&lt;span class="nv"&gt;$ &lt;/span&gt;nest new cloud-run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Fastify driver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;--save&lt;/span&gt; @nestjs/platform-fastify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to update &lt;code&gt;main.ts&lt;/code&gt; to make use of the Fastify driver. Also, Cloud Run will decide the port of our application, so we have to update the &lt;code&gt;main.ts&lt;/code&gt; file to reference&lt;br&gt;
 the &lt;code&gt;PORT&lt;/code&gt; environment variable, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FastifyAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NestFastifyApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/platform-fastify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NestFastifyApplication&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FastifyAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableCors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to create the &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Dockerfile
&lt;/h2&gt;

&lt;p&gt;We need to containerize our application to be able to run on Cloud Run. Create a Dockerfile at the root of your project&lt;br&gt;
and copy/paste the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For better performance, I decided to build the app before hand and run the &lt;code&gt;start:prod&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use the official lightweight Node.js 12 image.&lt;/span&gt;
&lt;span class="c"&gt;# https://hub.docker.com/_/node&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Create and change to the app directory.&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Copy application dependency manifests to the container image.&lt;/span&gt;
&lt;span class="c"&gt;# A wildcard is used to ensure both package.json AND package-lock.json are copied.&lt;/span&gt;
&lt;span class="c"&gt;# Copying this separately prevents re-running npm install on every code change.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy local code to the container image.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./&lt;/span&gt;

&lt;span class="c"&gt;# Build the application&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Run the web service on container startup.&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "npm", "run", "start:prod" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build &amp;amp; Deploy
&lt;/h2&gt;

&lt;p&gt;Now, we can use Cloud Build to build our docker image. Cloud Build will automatically detect our &lt;code&gt;Dockerfile&lt;/code&gt;, build, &lt;br&gt;
and push our image in Google Container Registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; gcr.io/YOUR_PROJECT/helloworld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done, we can run the following command to deploy our new revision to Cloud Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud run deploy &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/YOUR_PROJECT/helloworld &lt;span class="nt"&gt;--platform&lt;/span&gt; managed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benchmark
&lt;/h2&gt;

&lt;p&gt;When testing, I ran a small (to avoid crazy costs) benchmark with Apache Benchmark. &lt;/p&gt;

&lt;p&gt;Here is the command I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ab &lt;span class="nt"&gt;-n&lt;/span&gt; 1000 &lt;span class="nt"&gt;-c&lt;/span&gt; 80 https://cloud-run-url/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 1843412 $&amp;gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking cloud-run-url (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Google
Server Hostname:        cloud-run-url
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-CHACHA20-POLY1305,2048,256
Server Temp Key:        ECDH X25519 253 bits
TLS Server Name:        cloud-run-url

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      80
Time taken for tests:   9.300 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      437004 bytes
HTML transferred:       12000 bytes
Requests per second:    107.53 [#/sec] (mean)
Time per request:       743.985 [ms] (mean)
Time per request:       9.300 [ms] (mean, across all concurrent requests)
Transfer rate:          45.89 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       79  461 213.7    430    2633
Processing:    37  208 118.9    200     506
Waiting:       22  163 105.3    139     501
Total:        129  669 220.7    626    2739

Percentage of the requests served within a certain time (ms)
  50%    626
  66%    702
  75%    768
  80%    772
  90%    862
  95%   1161
  98%   1371
  99%   1576
 100%   2739 (longest request)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Compared to my previous experiment with the default installation of NestJS, I didn't observe any improvement in response time.&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>devops</category>
      <category>tutorials</category>
    </item>
    <item>
      <title>Deploy NestJS on Google Cloud Run</title>
      <dc:creator>Valentin Prugnaud 🦊</dc:creator>
      <pubDate>Tue, 18 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/valentinprgnd/deploy-nestjs-on-google-cloud-run-4cnj</link>
      <guid>https://dev.to/valentinprgnd/deploy-nestjs-on-google-cloud-run-4cnj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Repository: &lt;a href="https://github.com/WhatDaFox/nestjs-cloud-run-poc"&gt;WhatDaFox/nestjs-cloud-run-poc&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Configure Google Cloud
&lt;/h2&gt;

&lt;p&gt;To be able to build and deploy, you will need a Google Cloud project, with a billing account set up, as well as&lt;br&gt;
the &lt;a href="https://cloud.google.com/sdk/gcloud"&gt;Google Cloud CLI&lt;/a&gt; installed.&lt;/p&gt;

&lt;p&gt;Then you will need to create a configuration for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud config configurations create cloud-run
&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud auth login &lt;span class="c"&gt;# and follow the steps&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project YOUR_PROJECT_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the project
&lt;/h2&gt;

&lt;p&gt;For this proof of concept, I will only use the default NestJS application, that contains a single endpoint &lt;code&gt;/&lt;/code&gt; returning &lt;code&gt;Hello world!&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @nestjs/cli
&lt;span class="nv"&gt;$ &lt;/span&gt;nest new cloud-run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cloud Run will decide the port of our application, so we have to update the &lt;code&gt;main.ts&lt;/code&gt; file to reference the &lt;code&gt;PORT&lt;/code&gt; environment variable, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableCors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to create the &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Dockerfile
&lt;/h2&gt;

&lt;p&gt;We need to containerize our application to be able to run on Cloud Run. Create a Dockerfile at the root of your project and copy/paste the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For better performance, I decided to build the app beforehand and run the &lt;code&gt;start:prod&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use the official lightweight Node.js 12 image.&lt;/span&gt;
&lt;span class="c"&gt;# https://hub.docker.com/_/node&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:12-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Create and change to the app directory.&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Copy application dependency manifests in the container image.&lt;/span&gt;
&lt;span class="c"&gt;# A wildcard is used to ensure both package.json AND package-lock.json are copied.&lt;/span&gt;
&lt;span class="c"&gt;# Copying this separately prevents re-running npm install on every code change.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy local code to the container image.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./&lt;/span&gt;

&lt;span class="c"&gt;# Build the application&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Run the web service on container startup.&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "npm", "run", "start:prod" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build &amp;amp; Deploy
&lt;/h2&gt;

&lt;p&gt;Now, we can use Cloud Build to build our docker image. Cloud Build will automatically detect our &lt;code&gt;Dockerfile&lt;/code&gt;, build, &lt;br&gt;
and push our image in Google Container Registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud builds submit &lt;span class="nt"&gt;--tag&lt;/span&gt; gcr.io/YOUR_PROJECT/helloworld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done, we can run the following command to deploy our new revision to Cloud Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gcloud run deploy &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/YOUR_PROJECT/helloworld &lt;span class="nt"&gt;--platform&lt;/span&gt; managed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benchmark
&lt;/h2&gt;

&lt;p&gt;When testing, I ran a small (to avoid crazy costs) benchmark with Apache Benchmark. &lt;/p&gt;

&lt;p&gt;Here is the command I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ab &lt;span class="nt"&gt;-n&lt;/span&gt; 1000 &lt;span class="nt"&gt;-c&lt;/span&gt; 80 https://cloud-run-url/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 1843412 $&amp;gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking cloud-run-url (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Google
Server Hostname:        cloud-run-url
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-CHACHA20-POLY1305,2048,256
Server Temp Key:        ECDH X25519 253 bits
TLS Server Name:        cloud-run-url

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      80
Time taken for tests:   8.624 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      486004 bytes
HTML transferred:       12000 bytes
Requests per second:    115.95 [#/sec] (mean)
Time per request:       689.939 [ms] (mean)
Time per request:       8.624 [ms] (mean, across all concurrent requests)
Transfer rate:          55.03 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       61  402 219.1    375    2652
Processing:    29  207 117.5    192    1328
Waiting:       24  168 114.6    146    1279
Total:        163  609 236.4    567    2819

Percentage of the requests served within a certain time (ms)
  50%    567
  66%    622
  75%    681
  80%    714
  90%    804
  95%    920
  98%   1221
  99%   1754
 100%   2819 (longest request)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It is pretty straightforward to build and deploy a container to Cloud Run. The response time can sometimes be pretty slow, &lt;br&gt;
but overall, if the container is small and quick to start, it should run pretty smoothly.&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>devops</category>
      <category>tutorials</category>
    </item>
  </channel>
</rss>
