<?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: Bruno Silva</title>
    <description>The latest articles on DEV Community by Bruno Silva (@brunosilvadev).</description>
    <link>https://dev.to/brunosilvadev</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%2F845906%2F8615450d-eb8a-4f7f-8231-d17eb970850f.png</url>
      <title>DEV Community: Bruno Silva</title>
      <link>https://dev.to/brunosilvadev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brunosilvadev"/>
    <language>en</language>
    <item>
      <title>Fullstack app buildalong!</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Sun, 27 Aug 2023 00:13:57 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/fullstack-app-buildalong-deb</link>
      <guid>https://dev.to/brunosilvadev/fullstack-app-buildalong-deb</guid>
      <description>&lt;p&gt;Today I'm starting a new series here: let's build a full stack app together! I'm going to document all the development steps of a fully functional web app and share the decisions I make along the way, the tools I'm using and the thought process as the general idea evolves.&lt;/p&gt;

&lt;p&gt;The goal is not to come up with something revolutionary, but to showcase every layer in a stack of programming technologies, working together. If you're a newbie it will work as a series of examples of several different pieces being weaved together for something larger. If you're an experienced developer, this may be a chance to see some of the new stuff that's coming out, or better yet, make suggestions!&lt;/p&gt;

&lt;p&gt;Every now and then I'll post a pull request here for the community to provide feedback on.&lt;/p&gt;

&lt;p&gt;The very basic functionality of the app is going to be: frontend layer, backend layer and relational database. The interface is going to present the user with flashcards containing helpful information and the user will have the chance to add pre-created flashcards to their collection, or build flashcards from scratch.&lt;/p&gt;

&lt;p&gt;I've picked some technologies I'm very familiar with and others that I wanted to have an opportunity to play with. Here's the stack as of today:&lt;/p&gt;

&lt;p&gt;Frontend: Angular (TypeScript)&lt;br&gt;
Backend: .NET 8 (C#)&lt;br&gt;
Database: MySQL&lt;br&gt;
Hosting: Azure&lt;br&gt;
CI/CD: Github Actions&lt;/p&gt;

&lt;p&gt;The repo for the frontend code is:&lt;br&gt;
&lt;a href="https://github.com/brunosilvadev/hon"&gt;https://github.com/brunosilvadev/hon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backend can be found at:&lt;br&gt;
&lt;a href="https://github.com/brunosilvadev/hon-api"&gt;https://github.com/brunosilvadev/hon-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow along as it takes shape from the bare bones of boiler plates to a fully featured app. We'll add auth providers,tweak the pipelines, refactor the database architecture as the application evolves and listen to feedback from the users.&lt;/p&gt;

&lt;p&gt;For the newbies in web development, I'll be happy to answer your questions and explain the logic as we progress.&lt;/p&gt;

&lt;p&gt;On the next episode, I'll describe the initial architecture and the different bits of the boilerplate that's already in place.&lt;/p&gt;

&lt;p&gt;Let's build it together?&lt;/p&gt;

</description>
      <category>programming</category>
      <category>dotnet</category>
      <category>angular</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A verdadeira faixa salarial como dev nos EUA (ou o andar de baixo)</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Wed, 02 Aug 2023 22:15:36 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/a-verdadeira-faixa-salarial-como-dev-nos-eua-30bd</link>
      <guid>https://dev.to/brunosilvadev/a-verdadeira-faixa-salarial-como-dev-nos-eua-30bd</guid>
      <description>&lt;p&gt;Esse é um tema que mexe muito comigo. A minha intenção é esclarecer um tópico um pouco turvo, que eu vejo muito sendo mal representado ou com informações muito superficiais. O Lucas Montano fez &lt;a href="https://www.youtube.com/watch?v=OILOgpjsY-Q" rel="noopener noreferrer"&gt;um ótimo vídeo sobre o tema&lt;/a&gt;. O que eu escrevo aqui é um complemento. Recomendo assistir o vídeo dele primeiro e depois voltar aqui.&lt;br&gt;
 &lt;br&gt;
A forma como eu descrevo é a sensação de ter chegado em um monumento ou ponto turístico para admirar, mas eu cheguei pelo lado de trás e entrei pela porta dos fundos. Fiquei admirado, sim. Mas depois de um tempo eu percebi que na verdade estava vendo o lado de trás do monumento, enquanto todo mundo conhece a perspectiva principal. Muitos nem sabem que esse lado de trás existe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4pz5x88mo3anx5dryos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4pz5x88mo3anx5dryos.png" alt="Alegoria da Caverna de Platão faz sentido aqui"&gt;&lt;/a&gt;Alegoria da Caverna de Platão faz sentido aqui&lt;/p&gt;

&lt;p&gt;Calma que vai fazer sentido.&lt;br&gt;
 &lt;br&gt;
Eu e a minha esposa chegamos nos EUA em 2014, com uma mala contendo um monitor 24 polegadas e uma máquina de café espresso. Depois de um processo muito doido (que envolveu muita sorte), eu tinha recebido uma oferta para ser transferido para a matriz da empresa onde eu já trabalhava em São Paulo. Eu receberia o visto L1 e me mudaria para Kansas City, que fica bem no meio do mapa dos EUA continental.&lt;br&gt;
 &lt;br&gt;
Obviamente eu estava empolgadíssimo com a mudança. Hoje em dia existem milhares de histórias de pessoas que saíram do Brasil para trabalhar com tecnologia no exterior. Mas 10 anos atrás isso não era tão comum. Trabalho remoto, então, era coisa de ficção.&lt;br&gt;
 &lt;br&gt;
A minha história com essa empresa foi longa: depois de ter tido o green card negado uma vez, eu finalmente obtive a permissão para trabalhar, que é o documento que antecede a autorização de residência permanente. Depois de 6 anos na mesma empresa, no mesmo cargo, eu podia pensar em procurar outra oportunidade.&lt;/p&gt;

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

&lt;p&gt;Foi só nesse momento que eu comecei a me interessar em faixas salariais e quanto as empresas estavam pagando na área de tecnologia. Foi um choque muito grande quando eu conversei com uma recrutadora, que me perguntou a pretensão salarial, e eu disse um valor que deixou ela surpresa. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Esse valor é muito abaixo do mercado. Não faz nem sentido. Vamos passar a sua pretensão salarial como tanto&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um pequeno parênteses com relação aos níveis: pelo menos aqui na minha região, pouquíssimas empresas têm um cargo "Junior Engineer". Basicamente a pessoa é desenvolvedor ou desenvolvedor sênior. Mas a maioria é sênior. Nas 3 empresas onde eu trabalhei nos últimos 10 anos, a divisão do time de dev sempre foi assim: 80%+ era sênior. O restante era "pleno", embora não exista termo equivalente aqui. Nenhum Júnior. Característica aqui da região.&lt;/p&gt;

&lt;p&gt;Bom, foi a partir da conversa com aquela recrutadora que eu fui pesquisar mais sobre faixas salariais. Como eu disse no parágrafo inicial, esse foi o momento que eu consegui dar a volta no monumento para poder vê-lo de frente. E o que vem a seguir são as conclusões que eu consegui tirar desde aquele processo até hoje.&lt;br&gt;
 &lt;br&gt;
&lt;strong&gt;Meu primeiro salário como dev nos EUA (2014): $60k anual.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Já era abaixo da média na época. Existe um salário mínimo para contratação do visto H1B (o da loteria, muito comum na área tech). Acredito que a empresa na época quis equiparar a oferta L1 com ofertas H1B. &lt;/p&gt;

&lt;p&gt;Esse é um ponto importante de frisar: muitas empresas abertamente oferecem salários abaixo do mercado para profissionais que dependem do visto, exatamente porque para um funcionário assim, é muito mais difícil sair da empresa.&lt;br&gt;
 &lt;br&gt;
&lt;strong&gt;Meu salário depois de 5 anos atuando como dev nos EUA (2019): $84k anual.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aqui o meu salário era criminalmente baixíssimo para o meu tempo de experiência. Eu tocava projetos sozinho, liderava um time offshore. Mas vocês sabem como empresas são para dar aumento. Foi mais ou menos nessa época que eu quis sair dessa empresa (e tive que pagar uma multa cujo valor era maior que um carro 0km, mas essa história eu conto em outro post).&lt;/p&gt;

&lt;p&gt;Depois de ir terrivelmente mal na primeira entrevista técnica  (eu não me dei ao trabalho de me preparar, porque achava que não precisava), eu fui atrás de mais informações. Foi quando encontrei vários fóruns e repositórios de informações valiosas, como o subreddit CSCareerQuestions, que frequento até hoje. Também o perfil e o blog do Gergely Orosz, que fala muito sobre mercado de trabalho em tecnologia Europa-EUA. Conheci o levels.fyi, o Blind e o leetcode. Não vou me aprofundar muito nessas referências, mas é muito fácil de achar uma tonelada de informação sobre eleas.&lt;br&gt;
 &lt;br&gt;
&lt;strong&gt;Meu "salário total" como Senior Engineer na segunda empresa: ~$150k anual.&lt;/strong&gt;&lt;br&gt;
 &lt;br&gt;
Eu uso o termo "salário total" (ou total compensation) para incluir o salário, ações e bônus anuais no mesmo pacote.&lt;/p&gt;

&lt;p&gt;Fiz um comentário uma vez nesse subreddit, fazendo menção ao valor do meu salário. A resposta que eu recebi está na minha barra de favoritos do navegador até hoje: "150 mil para um dev sênior me parece meio baixo, mesmo numa cidade com baixo custo de vida". Então eu mostrei para a pessoa links com a página da minha cidade no levels.fyi, algumas vagas de LinkedIn, apenas constatando que esses 150k são na verdade bem acima da média aqui onde eu moro. &lt;br&gt;
 &lt;br&gt;
Acontece que as pessoas que sempre trabalharam nas big tech ou nos hubs de tecnologia, tipo Vale do Silício, nem sabem disso. Nesses casos, a remuneração nunca é apenas em dinheiro: normalmente as empresas oferecem um salário em cash, adicionado de uma parte em ações da empresa e talvez mais um bônus anual.&lt;br&gt;
 &lt;br&gt;
Na mesma época eu salvei também &lt;a href="https://twitter.com/hugaomarques/status/1504298080715218945" rel="noopener noreferrer"&gt;este tweet&lt;/a&gt; do grande Hugo Marques, em que ele basicamente diz &lt;em&gt;"menos de 200k é salário de Junior. Pleno ou Sênior chega a 250k-350k fácil"&lt;/em&gt;. A palavra &lt;em&gt;"fácil"&lt;/em&gt; nessa frase me causa mal estar até hoje. &lt;br&gt;
 &lt;br&gt;
Depois da onda de layoffs e do mercado ter ficado mais morno, eu finalmente voltei a receber mensagens de recrutadores pelo LinkedIn. Semana passada me convidaram para candidatar a uma vaga de tech lead em uma rede de cinemas (cuja sede fica aqui em Kansas City). O salário: $120k anual, sem bônus. Só.&lt;br&gt;
 &lt;br&gt;
Essa é a realidade da maior parte das pessoas que trabalham com desenvolvimento nos EUA. Quantas empresas podem pagar um salário acima de $200k anual para um programador só? Fora as grandes como Netflix, Meta, Uber, Apple, Google etc, será que mais umas 100 empresas, talvez um pouco mais? As faculdades e bootcamps estão formando milhares de pessoas todo ano e essas pessoas estão indo parar nas empresas de seguros, nos bancos, na logística, no varejo, na indústria. Todo mundo precisa de um app e quase toda empresa a partir de certo tamanho precisa de um departamento interno de desenvolvimento, nem que seja para manter os sistemas internos.&lt;br&gt;
 &lt;br&gt;
&lt;strong&gt;Meu salário total, agora como tech lead numa empresa pequena de tecnologia: ~$165k anual.&lt;/strong&gt;&lt;br&gt;
 &lt;br&gt;
Eu não tenho ações nem nenhum tipo de equity como parte do salário. Nunca vi uma empresa local oferecer isso. Com a onda forte de retorno ao presencial, tem sido cada vez mais difícil encontrar empresas de tecnologia (dentro daquelas 100 ou mais) que oferecem vagas remotas. E se você me perguntar, eu já contemplei sim a possibilidade de me realocar para outra região em busca de salários maiores. Mas essa é uma questão muito maior e mais complexa do que apenas o salário das vagas, então vou deixar para outro momento.&lt;br&gt;
 &lt;br&gt;
Foi urgente, para mim, escrever esse artigo, porque eu sinto que esse “andar de baixo” das vagas de TI nos EUA é muito mal representado, e muitas vezes completamente ignorado. Assim como na thread do Reddit que eu contei meu salário e disse que era comum na minha região, alguém respondeu &lt;em&gt;“cara, isso é terrível”&lt;/em&gt;, pelo menos agora eu tenho uma noção muito melhor do abismo que existe entre as faixas salariais daqui e as do “andar de cima”. E eu vou continuar buscando o elevador ou escada que vai me levar ao piso superior.&lt;br&gt;
 &lt;br&gt;
Não é do meu costume escrever posts em português, essa foi uma exceção. Me siga no &lt;a href="https://www.linkedin.com/in/brunosilvadev/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; para acompanhar os conteúdos que eu posto lá. Abraço!&lt;br&gt;
 &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Turn your Chromebook into a .Net developer machine!</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Sun, 23 Jul 2023 23:34:07 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/turn-your-chromebook-into-a-net-developer-machine-2bk6</link>
      <guid>https://dev.to/brunosilvadev/turn-your-chromebook-into-a-net-developer-machine-2bk6</guid>
      <description>&lt;p&gt;If you'd like to skip the intro and head straight to the step by step, click here.&lt;/p&gt;

&lt;p&gt;Did you know Chromebooks are present in more than half schools in the US? I'm not making that up: according to CNBC, the lightweight laptops have overtaken Apple and Windows based computers. &lt;a href="https://www.cnbc.com/2019/03/20/apple-google-microsoft-are-battling-for-dominance-in-education.html#:~:text=In%202018%2C%20Chromebooks%20made%20up,to%20data%20from%20Futuresource%20Consulting." rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what's a Chromebook anyway? It's a generally modest laptop that runs ChromeOS, a Linux based operating system that bases itself on the Google Chrome browser. Most applications run on the browser and the UI is very similar to Chrome itself.&lt;/p&gt;

&lt;p&gt;Modest, you say? So could it possibly be used as a developer machine? The answer is &lt;strong&gt;yes&lt;/strong&gt;! We're going to cover here the steps in order to setup a dev environment and start coding with a simple Chromebook!&lt;/p&gt;

&lt;p&gt;But why would one do that, you ask. There are many reasons: maybe you've wanted to start studying software development but has been putting it off because you don't have a good computer. Maybe you have a friend or family member who wants to learn how to code but they don't have access to the latest tech. And maybe you have a Chromebook laying around anyway.&lt;/p&gt;

&lt;p&gt;As a #dotnet developer, obviously I'm going to focus on setting up a C# development environment. But wait a minute, isn't dotnet a Windows-only endeavor??? No! And it hasn't been for quite a while. The .NET ecosystem is free, cross platform and open source. For the last decade it's been possible to build .NET apps using C# on Mac and Linux, not just on Windows.&lt;/p&gt;

&lt;p&gt;And I'm not even getting into the job opportunities for C# developers. In a market saturated with JavaScript aspirers, there's a world of .Net systems that will continue to need developers for the foreseeable future. As usual, one of my target audiences for my articles here is the older C# developers who have been through the .Net Framework 3.5 days and may not be aware of all the new things the ecosystem has to offer these days. So come along and let's get set up!&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The first thing you'll need is to enable Linux in your ChromeOS. This is a really nice feature that's available to most Chromebooks made these days.  go to Settings, expand the “Advanced” menu and go to “Developers”. Then click “Turn on” to enable Linux. More details here: &lt;a href="https://chromeos.dev/en/linux/setup" rel="noopener noreferrer"&gt;https://chromeos.dev/en/linux/setup&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;It'll give you access to the Linux terminal. If you've worked in a Linux based environment before, you'll feel right at home. My favorite code editor is VSCode, so let's hop over to &lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;this page&lt;/a&gt; and download the deb version. ChromeOS's Linux subsystem is based on the Debian system.&lt;/p&gt;

&lt;p&gt;After it's installed, either click the icon or just type &lt;code&gt;code&lt;/code&gt; in the terminal. We're almost there! Next, I'm going to install the dotnet runtime. This is necessary in order to run our C# applications. On &lt;a href="https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian" rel="noopener noreferrer"&gt;this page&lt;/a&gt; there's all the steps, but basically we'll need to add the Microsoft package source for apt-get and run a &lt;code&gt;sudo apt-get install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It should be as simple as running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update &amp;amp;&amp;amp; \
  sudo apt-get install -y dotnet-sdk-7.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is working fine, you should be able to run dotnet new and create your first application on the Chromebook! It's really that simple. If you're new to the dotnet CLI, head over to my other article. I focused on older C# developers who have relied on Visual Studio and Windows for years (which was my case a few years ago) but it will be helpful for newcomers as well.&lt;/p&gt;

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

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

&lt;p&gt;As always, follow me here or on &lt;a href="https://www.linkedin.com/in/brunosilvadev/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; for more tips. And let's build cool stuff!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>chromeos</category>
      <category>programming</category>
    </item>
    <item>
      <title>Step by step: How to host your dotnet projects on Azure for free</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Fri, 09 Dec 2022 22:55:30 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/step-by-step-how-to-host-your-dotnet-projects-on-azure-for-free-56hg</link>
      <guid>https://dev.to/brunosilvadev/step-by-step-how-to-host-your-dotnet-projects-on-azure-for-free-56hg</guid>
      <description>&lt;p&gt;Have you started working on side projects to improve your skills and explore new technologies? Fantastic! But how to host your web apps so that you can show them to other people? Luckily there's a free tier in the Microsoft cloud service Azure that lets you do just that: host small scale apps for development and study purposes. &lt;/p&gt;

&lt;p&gt;Don't think it's important? I was interviewing for an engineering position at a Startup last month and had the opportunity to mention my &lt;a href="https://croupier.azurewebsites.net/" rel="noopener noreferrer"&gt;Croupier API&lt;/a&gt;, which basically serves cards from a common playing deck. The interviewer was impressed that I could tell him the URL to open so he could play with it. &lt;/p&gt;

&lt;p&gt;Cool, huh? It's not that complicated. Follow along and we'll do it together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;gt; Disclaimer that needs to be made: I am giving these tips so that you can find the way to do it. If the configuration is not done correctly there is a chance you may get charged for services. Always double check with Microsoft’s support to make sure you’re using the free services and only that. Your mileage may vary but I was asked to provide a phone number and credit card number for identification.&lt;/strong&gt;&lt;br&gt;
 &lt;br&gt;
To make it even more fun, I’ll do it from a Mac computer (so no Visual Studio available) to show you that it can be done on any kind of device. Dotnet really is multi-platform. So we begin typing in the following command in the terminal (that’s assuming you already have dotnet installed):&lt;br&gt;
 &lt;br&gt;
&lt;code&gt;dotnet new webapp -n Sidegig&lt;/code&gt;&lt;br&gt;
 &lt;br&gt;
Here’s the terminal output.&lt;/p&gt;

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

&lt;p&gt;I chose Sidegig as a catchy name but feel free to choose a name for your project. I’m going WebApp but you can do MVC, WebAPI, anything that will have an HTTP interface and can be accessed via web browser. To see what it looks like just open the terminal inside the Sidegig folder and run&lt;br&gt;
 &lt;br&gt;
&lt;code&gt;dotnet run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv55vf9c72xpyg1zlos67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv55vf9c72xpyg1zlos67.png" alt="Basic ASP.Net Core app"&gt;&lt;/a&gt;&lt;br&gt;
Not too shabby, huh?&lt;/p&gt;

&lt;p&gt;Now we’re going to hop on to Github. I’m hoping you already have a Github account but feel free to create one if you don’t. I’m going to click “Create a new repository”. This is what the screen is going to look like:&lt;/p&gt;

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

&lt;p&gt;I’m naming the repo sidegig-app, but really anything works here. &lt;br&gt;
 &lt;br&gt;
Then I’m going to clone that repo to my computer. I’m using the command &lt;code&gt;git clone&lt;/code&gt; but you can use the Github CLI or a GUI git program for that. &lt;/p&gt;

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

&lt;p&gt;After copying the files I’ll open the folder in VSCode to check in the changes.&lt;/p&gt;

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

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

&lt;p&gt;Browsing the repository at Github.com to make sure that everything is there and looking good.&lt;/p&gt;

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

&lt;p&gt;Now on to the hairy part. Go to &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;portal.azure.com&lt;/a&gt; and log in with your Microsoft account.&lt;br&gt;
 &lt;br&gt;
I created a new Microsoft account just for the purpose of this tutorial, so your experience should be similar to mine. You’ll search for the Free Trial option. It’ll take you to a separate webpage outside of the azure.com domain. &lt;strong&gt;I was asked to provide a phone number and credit card number for identification purposes&lt;/strong&gt;. They tried to sell me a premium support service, which I declined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;gt; Again, always make sure to choose the Free Trial, Free Tier option. In case of doubt, reach out to Microsoft support. I am not responsible if you accidentally sign up for a paid service.&lt;/strong&gt;&lt;br&gt;
 &lt;br&gt;
After that was completed, I was taken back to the Azure portal with some commonly used features highlighted. Go ahead and click Create inside the Azure Web Apps block.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8e22umwjg7vr51yakdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8e22umwjg7vr51yakdw.png" alt="Create Azure Web App"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;br&gt;
The next projects you post to Azure are going to be very similar from this point on. The next thing we need to do is create a Resource Group. These are like entities that group the services you get into chunks of consumption for billing purposes. I’m going to name it sidegig-app-resource-group for simplicity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2wzfx1krmhsbf32z1m1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2wzfx1krmhsbf32z1m1.png" alt="Resource Group creation"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;br&gt;
Then you get to choose the URL. I’m going with &lt;a href="https://sidegig.azurewebsites.net/" rel="noopener noreferrer"&gt;sidegig.azurewebsites.net&lt;/a&gt;.&lt;br&gt;
 &lt;br&gt;
Choose to Publish your Code (first option). Runtime stack is the dotnet version you’re going to use. You need to choose Windows for the free tier.&lt;/p&gt;

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

&lt;p&gt;Now comes the most important part: &lt;strong&gt;open the Pricing Plan and choose the Dev/Test tab. From there choose F1, the one that says Free&lt;/strong&gt;. The computing is far more than enough for this exercise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdenrrcdrybn7xqvgecr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdenrrcdrybn7xqvgecr.png" alt="Azure free tier"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;br&gt;
Next step is the most fun of all. Switch the Github Actions setting to Enabled and link your Github account. You’ll see that it shows your profile as an organization. From there choose your repository and branch. I’m picking the repo sidegig-app. You’re now ready to click Review + create.&lt;/p&gt;

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

&lt;p&gt;It’ll take a moment to download your code from Github, build and publish it.&lt;/p&gt;

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

&lt;p&gt;After it’s completed, click at &lt;em&gt;Go to Resource&lt;/em&gt; and, from there, click Browse. Or simply navigate to the URL you had chosen previously to see your app there, running on the cloud. And for free.&lt;br&gt;
 &lt;br&gt;
Pat yourself on the back. Your little project is out there for the world to see.&lt;br&gt;
 &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82k7zhxr3y59dcwjdjuk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82k7zhxr3y59dcwjdjuk.png" alt="Live website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also make sure to go back to your repo at Github and click the Actions tab, to see some of the stuff that happened behind the scenes.&lt;/p&gt;

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

&lt;p&gt;Now the magic is all set up. Any change you make and publish to the main branch will trigger this Github Action, which in turn will update your app on Azure. All automated, instantly and for free!&lt;br&gt;
 &lt;br&gt;
Thanks for the read! If you’ve liked this step-by-step guide, make sure to give me a follow here or at my &lt;a href="https://www.linkedin.com/in/brunosilvadev/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. Hope you have a great day!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>azure</category>
      <category>programming</category>
    </item>
    <item>
      <title>Minimal API endpoints getting messy? Let's get organized</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Fri, 11 Nov 2022 20:08:20 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/minimal-api-endpoints-getting-messy-lets-get-organized-4hek</link>
      <guid>https://dev.to/brunosilvadev/minimal-api-endpoints-getting-messy-lets-get-organized-4hek</guid>
      <description>&lt;p&gt;I was a loud advocate and early adopter of dotnet's Minimal API framework for managing endpoints. It solves the problem of Controllers being verbose and cluttered, heavily geared for the MVC architecture and frequently being responsible for returning a fully rendered view from the backend. While also provides a much more flexible structure for your Rest methods. If you don't know what I'm talking about, make sure to check &lt;a href="https://dev.to/brunosilvadev/still-writing-controllers-in-dotnet-give-minimal-apis-a-try-5e4i"&gt;my other article&lt;/a&gt;, which should help you switch from dotnet controllers to endpoints.&lt;/p&gt;

&lt;p&gt;We went from this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;sandboxing.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;sandboxing.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HomeController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Index&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="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Privacy&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="nf"&gt;View&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="nf"&gt;ResponseCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResponseCacheLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NoStore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Error&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="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ErrorViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;RequestId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceIdentifier&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I've been hearing people complain that it gets cluttered and messy once you start having more than a few routes to specify. You don't want to be touching your Program.cs all the time and nobody wants to clutter a critical file with 100 lines that look more or less the same. I personally know the pain, as one of the microservices in the app we're building at my job has over 100 endpoints. It's easy to get lost, but there's ways to work around the mess.&lt;/p&gt;

&lt;p&gt;Here's the solution we came up with: create an interface, separate each logical domain into a different file with its own routes and each of these files implements the interface. Then during the application startup, we iterate through every single implementation to get the routes registered.&lt;/p&gt;

&lt;p&gt;Sounds tricky? Check this example and you'll see it's pretty straightforward.&lt;/p&gt;

&lt;p&gt;First, the interface with the RegisterRoutes signature, that receives an IEndpointRouteBuilder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IEndpoint&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;RegisterRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEndpointRouteBuilder&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you had separate controllers in the past, now you should have separate endpoints with a group of routes. The implementation will be much closer to the bare bones of Minimal APIs than with old school MVC Controllers.&lt;/p&gt;

&lt;p&gt;This is a part of DeckEndpoint, one of the endpoints in my playing cards API Croupier (&lt;a href="https://github.com/brunosilvadev/Croupier"&gt;check it on my Github&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeckEndpoint&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEndpoint&lt;/span&gt;    
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;RegisterRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEndpointRouteBuilder&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/new-game"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NewSession&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/draw-card"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DrawCard&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/see-deck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SeeDeck&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/shuffle-deck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ShuffleDeck&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 second parameter in the MapGet method is a delegate. NewSession, DrawCard, SeeDeck and ShuffleDeck are the methods in that endpoint class.&lt;/p&gt;

&lt;p&gt;Okay, now we just need to make sure every single instance of RegisterRoutes function is being called during the program startup. For that you'll need to add a line for each new endpoint in your dependency inversion definition, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DeckEndpoint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TestEndpoint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also achieve the same result using Reflection! But it's a little more tricky so I'll save that for another time.&lt;/p&gt;

&lt;p&gt;Now that our endpoints are registered, we just need to iterate through the implementations of IEndpoint from the DI provider and make sure the RegisterRoutes method is called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;endpoints&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetServices&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEndpoint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;endpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we're done! Functionality-wise, every route from multiple endpoints is registered as if they were all listed in Program.cs. For reference, this is what my Program class looks like in the Croupier API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDIServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseOpenApi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseEndpoints&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slim!&lt;/p&gt;

&lt;p&gt;I hope this helps you decide to let go of old Controller ways and embrace the new dotnet features. Drop a question if you feel like so, check out the &lt;a href="https://github.com/brunosilvadev/Croupier"&gt;Croupier API&lt;/a&gt; on my Github and make sure to follow me here and on my &lt;a href="https://www.linkedin.com/in/brunosilvadev/"&gt;LinkedIn&lt;/a&gt;. Thanks and have a good one.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>api</category>
      <category>programming</category>
    </item>
    <item>
      <title>Still writing Controllers in dotNet? Give Minimal APIs a try!</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Mon, 19 Sep 2022 17:13:00 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/still-writing-controllers-in-dotnet-give-minimal-apis-a-try-5e4i</link>
      <guid>https://dev.to/brunosilvadev/still-writing-controllers-in-dotnet-give-minimal-apis-a-try-5e4i</guid>
      <description>&lt;p&gt;If you’ve been working with .NET development for a while, you’re probably used to a lot of the quirks and idiosyncrasies from the beginning of the framework time, especially before the big transition to .NET Core. Verbose would be an understatement for the traditional Web APIs and IIS-ready apps. Wow! Remember when you needed a full-fledged Windows Server system to run your dotNet apps? Thankfully the ecosystem has evolved gigantically since then.&lt;/p&gt;

&lt;p&gt;So your typical C# web API with Program.cs, Startup.cs and a plethora of Controllers inheriting from ControllerBase there used to be lots of naming conventions and rigid structure. Code used to look more or less like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;sandboxing.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;sandboxing.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HomeController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Index&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="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Privacy&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="nf"&gt;View&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="nf"&gt;ResponseCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResponseCacheLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NoStore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Error&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="nf"&gt;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ErrorViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;RequestId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceIdentifier&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fun fact: you can type &lt;code&gt;dotnet new mvc&lt;/code&gt; to build a MVC style web app, if that’s still your thing. The code above is the HomeController you get from this command. You can modify your Index.cshtml to contain only a string &lt;code&gt;“Hello World, I guess?”&lt;/code&gt; and send it back to the browser via the controller &lt;code&gt;Index()&lt;/code&gt; method. When you browse to that route, the app loads the string from the controller (plus a header and footer that I really didn’t ask for).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6LhpdCMq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x81m8txassuc03fzwj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6LhpdCMq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x81m8txassuc03fzwj2.png" alt="Image description" width="538" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty simple, right? Well, what if could be actually simple?&lt;/p&gt;

&lt;p&gt;With dotNet 6, Microsoft introduced the Minimal APIs paradigm, which greatly simplifies this structure and brings the C# development closer to the trendy technologies like NodeJS and Express (apparently, we’re okay with running Javascript on the backend these days).&lt;/p&gt;

&lt;p&gt;Part of that effort has been the complete elimination of Startup.cs, which simplifies the basic boilerplate structure of Web APIs. Go ahead and type &lt;code&gt;dotnet new web&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is what your Program.cs is going to look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. Four lines in a single file. The app.MapGet line assigns the anonymous function “string() { return “Hello World!”; }” to the “/” route. You browse to that route; you get the return from the function. All running from a terminal application (IIS who?) that you can easily host on your server, on the cloud, on linux or Windows, wherever.&lt;/p&gt;

&lt;p&gt;As you can see, the verbose days of dotnet apps are past. If you haven’t given C# a try in a while, this is the best time ever to get onboard and build lean apps that perform well and can be installed on any hardware. Check Microsoft's &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0"&gt;official documentation&lt;/a&gt; to learn more (I swear their doc is pretty good). Long live Minimal APIs!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Using EFCore's InMemoryDatabase as an automated testing tool</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Fri, 19 Aug 2022 18:27:00 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/using-efcores-inmemorydatabase-as-an-automated-testing-tool-on0</link>
      <guid>https://dev.to/brunosilvadev/using-efcores-inmemorydatabase-as-an-automated-testing-tool-on0</guid>
      <description>&lt;p&gt;Hello #dotnet friends! &lt;/p&gt;

&lt;p&gt;We've all been there: you have your data access layer, your API handles all CRUD operations and your unit tests use mocks to simulate the interactions between each object. That's the moment you ask yourself: am I really testing anything? Since every object interacts with a mocked, simplified version of its dependencies, we're only validating the very basic functionality of the data manipulation classes. &lt;/p&gt;

&lt;p&gt;Implementing integration tests would solve that, right? The issue is that it's not always feasible to touch the database for manipulation. What if you have a mass delete operation or something that will cause all kinds of trouble if you have to run it in production? Your test engine probably won't (and it really shouldn't) have production database access. For that scenario there's a tool that finds a middle ground between the convenience of automation with a safe, flexible and closer-to-real-data approach of a full integration test, which is to virtualize the DB. If you already use EntityFramework Core the whole process can be quite simple!&lt;/p&gt;

&lt;p&gt;Let's say you have a database context that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SampleContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SampleContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you probably inject that database context into your services DI provider. It will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SampleContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyConnectionString"&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all very typical code for EFCore and .NETCore web APIs. If you have something similar, you're in luck! I normally prefer xUnit but if you use NUnit or any other testing framework, it should look more or less the same. In your startup phase or constructor you can simply instance the DatabaseContext object in a virtualized way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;SampleContext&lt;/span&gt; &lt;span class="n"&gt;_virtualContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SampleTests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;_virtualContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SampleContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DbContextOptionsBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SampleContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SampleDb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&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;And it's pretty much it! Now you can add data relevant to your tests and let your test methods go to town, delete, truncate, explode the database that everything will be gone once the execution is complete. Here's a basic data initializer function for the example above (using the same _virtualcontext and the Product record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ProductName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"TestProduct"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ProductName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"AnotherTestProduct"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_virtualContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;_virtualContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can write tests that call the Controllers/Endpoints and validate the outputs, along with the data manipulations. Once the test manager starts up the API, &lt;strong&gt;it'll instance the virtualized DB and the underlying code will be agnostic to it&lt;/strong&gt;. Nothing quite like fooling your own code, right?&lt;/p&gt;

&lt;p&gt;Let me know if it's been helpful and follow me on &lt;a href="https://www.linkedin.com/in/brunosilvadev/"&gt;LinkedIn&lt;/a&gt;. Thanks for the read!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>testing</category>
      <category>database</category>
    </item>
    <item>
      <title>Mentoria dotnet + angular para pessoas periféricas</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Fri, 12 Aug 2022 14:54:03 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/mentoria-dotnet-angular-para-pessoas-perifericas-17ef</link>
      <guid>https://dev.to/brunosilvadev/mentoria-dotnet-angular-para-pessoas-perifericas-17ef</guid>
      <description>&lt;p&gt;Eu cresci na periferia de São Paulo, estudei a vida toda em escola pública e trabalhar com TI possibilitou que eu alavancasse o meu potencial e tivesse a oportunidade de oferecer para a minha família um padrão de vida que eu jamais sonhei.&lt;/p&gt;

&lt;p&gt;Por isso eu estive pensando em alguma forma de retribuir e passar adiante essa oportunidade. A minha ideia é liderar um pequeno projeto de desenvolvimento de software, com um time que seria composto de um ou dois programadores iniciantes. É a primeira vez que eu faço isso, então seria algo bem piloto mesmo. A minha estimativa inicial é de algumas semanas, mas não tenho certeza com relação ao prazo.&lt;/p&gt;

&lt;p&gt;Para esse fim, o processo de desenvolvimento será mais importante do que o resultado. Por esse motivo, a stack foi definida como aquela em que eu tenho mais experiência e, portanto, posso ensinar melhor. Existem muitas linguagens e tecnologias por aí, mas eu sugiro ao principiante começar focando em apenas uma.&lt;/p&gt;

&lt;p&gt;Eu nunca ofereci esse tipo de mentoria. No meu trabalho atual não tem nenhum desenvolvedor Jr e eu sinto falta de compartilhar e tirar dúvidas. Ao mesmo tempo, para quem está iniciando nessa carreira, poder demonstrar que já trabalhou num projeto em equipe, com scrum, com versionamento, com entrega. São habilidades que podem fazer o seu currículo mais atrativo enquanto você busca a primeira oportunidade como desenvolvedor.&lt;/p&gt;

&lt;p&gt;Exatamente por isso eu digo que o processo será mais importante do que o resultado. No fim do processo, todos nós (incluindo eu) teremos capacidades novas para incluir no currículo e oferecer ao mercado. O maior objetivo desta iniciativa é de fomentar e exercitar as seguintes habilidades:&lt;/p&gt;

&lt;p&gt;• Colaboração em desenvolvimento&lt;br&gt;
• Compreensão de requisitos&lt;br&gt;
• Code review e solução de conflitos&lt;br&gt;
• Saber pesquisar, saber perguntar&lt;br&gt;
• Entender escopo de tarefas e qualidade de entrega&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A stack:&lt;/strong&gt;&lt;br&gt;
Front end Angular. Back end dotnet 6. Banco de dados MS-SQL&lt;br&gt;
Como dito anteriormente, eu até já mexi com outras linguagens e frameworks, mas essa combinação é a que eu tenho mais anos de experiência.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requisitos:&lt;/strong&gt;&lt;br&gt;
• Ter pouca ou nenhuma experiência profissional como desenvolvedor(a) (o foco é criar um produto que você vai poder colocar no seu currículo)&lt;br&gt;
• Que tenha algum conhecimento de lógica de programação, banco de dados relacional, de preferência que já tenha feito algum projeto simples como calculadora, álbum de fotos, consumir API de previsão do tempo etc.&lt;br&gt;
• Tenha um computador (Windows, Linux ou Mac, tanto faz)&lt;br&gt;
• Algumas horas por semana. Eu mesmo tenho bem pouco tempo livre, não vou exigir de ninguém muitas horas de dedicação, até porque a pessoa iniciante já tem muita coisa para estudar&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Software, que se você já tiver instalado é um adianto:&lt;/strong&gt;&lt;br&gt;
• Microsoft Teams&lt;br&gt;
• Visual Studio Code&lt;br&gt;
• Azure Data Studio&lt;br&gt;
• Github Desktop&lt;br&gt;
• Node js&lt;br&gt;
• Trello&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como vai funcionar:&lt;/strong&gt;&lt;br&gt;
Primeiro eu vou conversar com as pessoas para gente se apresentar, alinhar as expectativas e tirar dúvidas iniciais. Quando o time estiver fechado eu vou definir qual será o escopo do projeto e vamos analisar juntos as features que precisam ser implementadas e quebrar essas implementações em tarefas. Todos nós vamos organizar as tarefas da forma que fizer mais sentido e atuar nelas. A ideia é que a gente possa tirar dúvidas uns dos outros. Conforme formos progredindo, vamos incluir testes automatizados, continuous integration, responsividade, para dar mais polimento e maturidade para a aplicação.&lt;/p&gt;

&lt;p&gt;A comunicação será feita quase exclusivamente pelo Teams. Reuniões que eventualmente forem realizadas por áudio e vídeo serão por lá também. Estou pensando num formato para uma daily stand up assíncrona. Ou seja, haveria atualização de status frequente, mas sem que necessariamente os participantes tenham que se reunir no mesmo horário.&lt;/p&gt;

&lt;p&gt;Voltando a enfatizar que o objetivo dessa mentoria não é o produto final, mas sim a oportunidade de adquirir uma experiência que se aproxima do dia a dia em um time de desenvolvimento de software. Reforçando também que eu não sou nenhum guru, coach ou referência de mercado nem da comunidade. Eu só tenho alguns anos de experiência. &lt;/p&gt;

&lt;p&gt;Se você acha que seria legal e acha que se enquadra, manda um e-mail contando o que representaria para você trabalhar com TI. O endereço é &lt;a href="mailto:bruno@brunosilva.cc"&gt;bruno@brunosilva.cc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mentoria</category>
    </item>
    <item>
      <title>Don’t sleep on dotnet command line!</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Wed, 20 Jul 2022 18:44:58 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/dont-sleep-on-dotnet-command-line-5fb6</link>
      <guid>https://dev.to/brunosilvadev/dont-sleep-on-dotnet-command-line-5fb6</guid>
      <description>&lt;p&gt;If, like me, you’ve been developing Web APIs in .NET since the days of version 3.5 (or 2, or even 1.1!), then you’ve probably ran into the scenario of having to run multiple instances of Visual Studio to debug a multi-tiered or distributed application. If you’re still doing it to this day, there’s a trick to make life easier on us and on our poor laptops memory: run .NET Core apps from the terminal, even Web APIs!&lt;/p&gt;

&lt;p&gt;Open a new terminal and browse to the project folder. From there, just do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; dotnet run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Yes, simple like that. It triggers a build if the binaries are not present and starts up the application at the preconfigured endpoints. And if you're building .NET apps in Linux or Mac OS (you know you can do that, right?), it works just as well in the Unix terminal.&lt;/p&gt;

&lt;p&gt;Bonus tip: If you haven’t tried the new Windows Terminal with tabs and customizable themes, check it out from Microsoft’s &lt;a href="https://github.com/microsoft/terminal"&gt;official Github page or from the Windows Store&lt;/a&gt;. It supports Windows Command Prompt, PowerShell, WSL, Azure and Visual Studio command line APIs.&lt;/p&gt;

&lt;p&gt;It’s great to have multiple projects running locally while you work on an issue in one of the application layers. And great for not having to startup the entire Visual Studio suite several times.&lt;/p&gt;

&lt;p&gt;What was the highest number of Visual Studio instances you had running on your machine at the same time?&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>programming</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Quick list of small project ideas</title>
      <dc:creator>Bruno Silva</dc:creator>
      <pubDate>Mon, 11 Apr 2022 21:24:48 +0000</pubDate>
      <link>https://dev.to/brunosilvadev/quick-list-of-small-project-ideas-2m75</link>
      <guid>https://dev.to/brunosilvadev/quick-list-of-small-project-ideas-2m75</guid>
      <description>&lt;p&gt;This is a small compilation of ideas for simple apps one can build in order to enhance their skills and practice. It's mostly targeted for beginners. Suggestions welcome. Credits to @EngineerRabbit on Twitter, she published this list originally. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Games&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Tic tac toe&lt;/li&gt;
&lt;li&gt;Snake&lt;/li&gt;
&lt;li&gt;Scrabble or some other word game&lt;/li&gt;
&lt;li&gt;Matching Pairs&lt;/li&gt;
&lt;li&gt;Simon Says&lt;/li&gt;
&lt;li&gt;Trivia&lt;/li&gt;
&lt;li&gt;Virtual Pet/Idle game&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scavenging hunt (it can be static or you can implement an interface for the user to build their own)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Static&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Picture album&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Job/internship board&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fancy interactive resumé&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Product catalog&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Language learning portal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;List of travel destinations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A simple wiki for a topic you enjoy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Management&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple task manager&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Calorie count&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exercise or habit tracker&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;URL shortener&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Donation/free stuff board&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embeds and APIs&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advice from api.adviceslip.com&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chuck Norris (because why not) api.chucknorris.io&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dogs docs.thedogapi.com&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spotify charts developer.spotify.com&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Magic the Gathering database (research APIs available)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>ideas</category>
    </item>
  </channel>
</rss>
