Para efetuar este teste, algumas escolhas foram puramente direcionadas à demostração da impe=lementação de técnicas e experiências em programação.
Por exemplo, a não utilização de Dependency Injection, que hoje é extremamente comum em .Net, é uma opção para implementar outros conceitos e padrões. Ainda, a não utilização dos controles de validação do Asp.Net MVC, é também uma opção para implementar rotinas em Javascript/JQuery, e demonstrar o domínio sobre a linguagem.
Postas essas questões, seguimos!
Para melhor avaliar este teste, execute a aplicação e acompanhe as intruções na Página Inicial.
- DDD
- Micro Services
- N-tier
- Generics
- Facade
- Singleton
- Encapsulamento
- Reutilização de código: extração de rotinas e Extension Methods
- Regras de legibilidade / manutenibilidade de código 1 Regras de programação segura
- Asp.Net Core
- Web Api (REST)
- Asp.Net MVC
- Razor
- Entity Framework
- PostgreSQL
- User registration
- Sem utilizar o MS-Identity:
O Uso de Session é muito comum para quem programa na plataforma MS por pelo menos 15 anos.
Porém, o uso de Session em Net Core está atrelado ao controller, dificultando a implementação do Pattern Facade (ver 2 Bugs em Runtime para key/value pair). Essa implementação ficou muito nebulosa, com configuração muito complicada, com entendimento complexo, apresentando muitos erros, e sem garantias de que conseguiria fazê-lo em tempo.
Quando você cria um projeto web sem se preparar para utilizar o Identity, incluir depois é bem complicado e com muitos passos.
Não existe a opção de alterar a autenticação, então seria necessário remover todo o projeto, refazê-lo, importar tudo que já havia sido feito.
Ainda que o package do Identity gere bastante código, diminuindo o esforço (menos programação, alguma customização), a opção por registrar sem MS-Identity com cookies acabou ficando muito mais leve e objetiva.
- Sem utilizar o MS-Identity:
- Bootstrap
- JQuery
- Font-awesome
- Toastr
- Criar users (superuser) / databases
- Execute o arquivo "/SQL/Users.sql"
{
"DataBaseConfiguration":
{
"Host": "localhost",
"Port": 2021,
"Database": "BenFatto-FrontEnd",
"Username": "BenFattoUsr-FrontEnd",
"Password": "B3nF4tt0#2021"
}
}
{
"DataBaseConfiguration":
{
"Host": "localhost",
"Port": 2021,
"Database": "BenFatto-CLF",
"Username": "BenFattoUsr-CLF",
"Password": "B3nF4tt0#2021"
}
}
- Criar Tabelas
- Execute os arquivos "/SQL/Api-schema.sql" & "/SQL/App-schema.sql"
- Inserir "bogus data"
- Restaure os pacotes NUGET
- Inicie uma instância de "HandyMan" console application;
- Ao ser prompted, digite o comando "file" (case insensitive)
- Se desejar, acompanhe o processo por Debug
- Ao completar, uma mensagem será exibida, e 5 arquivos foram devidamente criados, importados (com linhas válidas e inválidas) e persistidos.
- Se desejar, repita a operação para alimentar o DB com mais massa de dados.
- Incluir um usuário no sistema
- Em uma instancia de "HandyMan" console application, digite o comando "User".
- Siga as instruções do programa.
- O Usuário de acesso ao sistema está criado e disponível para acessar a aplicação.
- Iniciar a aplicação
- Acesse o item "Files"
- Cada linha representa um arquivo importado ("File").
- Não é possível Editar ou Excluir "Files" manualmente.
- Novos "Files" são incluídos somente mediante Importação.
- Aplique os filtros (não exclusivos mutuamente)
- Ações:
- Ver detalhes do "File"
- Acesse os detalhes de um "File" qualquer.
- Ver inconsistências na importação
- Acesse as inconsistências de um arquivo qualquer.
- Aplique os filtros (não exclusivos mutuamente)
- Exclua uma inconsistência ("Row with error")
- Altere uma inconsistência
- Note que apenas é possível alterar a linha originalmente contida no arquivo.
- Caso a alteração seja sufuciente para que a linha se torne um registro, isso ocorrerá automaticamente.
- Acesse as inconsistências de um arquivo qualquer.
- Ver linhas importadas com sucesso
- Acesse as linhas importadas de um arquivo qualquer
- Aplique os filtros (não exclusivos mutuamente)
- Exclua uma linha ("Row")
- Altere uma linha
- Inclua uma linha válida
- Inclua uma linha com inconsistência
- Acesse as linhas importadas de um arquivo qualquer
- Ver detalhes do "File"
- Implementar OAuth no API para previnir DOS Attacks, Melhorar a segurança e restringir acesso
- Implementar as APIs de outros tipos de arquivos (fixed lenght / Char-separated)
- Implementar telas de gerenciamento dos outros tipos de arquivo
Em algumas linguagens não tipadas (javascript, por exemplo) ou fracamente tipadas (VB.Net sem Option Explicid e Option Strict), ao fazer uma condicional baseada numa comparação, podemos fazer uma condicional paseada numa atribuição.
var strTxt = "It's me! Mario!";
if(strTxt = "It's me! Luigi!") {
window.alert("It was, indeed, Luigi!");
}
Uma vez que você não consegue atribuir à uma constante, ou um readonly attribute, a identificação do bug fica mais simples. A situação com variáveis booleanas é mais fácil de vislumbrar o problema na prática.
string any = "";
bool isTheSame = (string.empty = any); // a static readonly field cannot be assigned to
A utilização de blocos Try/Catch proporcionam tratamentos de erro de uma forma tipada, previsível e extremamente robusta.
Entretanto, a má utilização desse recurso pode levar a diversos problemas e práticas tenebrosas. Dentre os inúmeros problemas, os principais que gostaria de apontar são:
- Exception Swalloing: quando o programa acaba "ocultando" uma excessão disparada em blocos de try/catch aninhados.
- Large resource consumption: um bloco try/catch é muito mais custoso em termos de processamento e memória que uma consulta / verificação prévia.
- Stacktrace loss: o stacktrace da Exception original é perdido quando se usa Catch(Exception ex) { throw ex; }
- Exceptions are not business logic: Excessões devem ser utilizadas para previnir encerramento abrupto de um programa, e não para programar regras de negócio.
- Dealing with specific Exceptions: No processo de criação de um arquivo texto, por exemplo, temos uma Exception se parte do caminho não existe. Se não há espaço em disco disponível, temos outra Exception. Se não há permissão de escrita, outra Exception. Tratar da mesma forma todas as diferentes situações pode gerar um bug de difícil identificação.
Leitura interessante sobre o assunto: Exception-Handling-Best-Practices-in-NET
Considere que em certa rotina de um programa, você atribui à um cookie, chamado "UsuarioLogado", um valor inteiro.
Context.Response.Cookies["UsuarioLogado"] = 1;
Em outra parte do programa, você tenta acessar este conteúdo, mas por um erro de digitação, consome o cookie "UsuaroLogado".
int usrLgd = ParseInt(Context.Response.Cookies["UsuaroLogado"].Value.ToString()); //<<< NullReferenceException thrown here
Esse bug só seria "identificado" em runtime. O dev identificaria o NullReferenceException, com algum esforço perceberia a ausência do I, corrigiria e pronto!
Porém, se o typo está no caso da atribuição, e a Exception é disparada na leitura, e a identificação e correção do Bug se tornam, consequentemente, mais complexas numa escala geométrica.
Agora considere, por exemplo, uma lista qualquer sendo armazenada numa Sessão "FirstList"; Nela estão armazenados os primeiros requests do usuário ao ingressar, nessa ocasião, no sistema.
Existe também, contudo, uma lista de Primeiros colocados em alguns concursos. O desenvolvedor dessa feature, sem conhecer a outra feature, chamou a sessão que vai armazenar essa lista de "FirstList". Como a atribuição e a leitura acontecem em requests diferentes, a exception disparada é sobre a conversão dos objetos. É necessário identificar a origem do bug e corrigi-lo... Boa sorte para o dev.
Facade (lê-se "Fássêid": fəˈsɑːd) é um pattern de encapsulamento de funcionalidades de 1 ou vários subsistemas para simplificar o acesso e consumo deste sistema em sua complexidade. O corpo humano, por exemplo, apresenta diversos exemplos desse pattern: O Sistema Digestivo tem como facade a boca e o ânus. Os olhos são facades para conversões de radiação em sinapses para a interpretação e armazenamento em memória pelo cérebro. (...) Na aplicação para a questão do Key/Value pair, é uma simplificação deste. Com o pattern, é possivel aplicar encapsulamento, tipagem, unicidade, entre outros. É possível, inclusive, mensurar o tamanho em bytes que estes objetos estão / deverão ocupar em memória.
(https://marketplace.visualstudio.com/items?itemName=RojanskyS.NpgsqlPostgreSQLIntegration)
(https://www.newtonsoft.com/json/help/html/PreserveReferencesHandlingObject.htm)
(https://www.newtonsoft.com/json/help/html/ReferenceLoopHandlingIgnore.htm)
(https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)
(https://www.webtrainingroom.com/aspnetcore/connection-string-ef-core)
(https://dotnetcoretutorials.com/2020/01/31/using-swagger-in-net-core-3/)
(https://dotnetcoretutorials.com/2019/12/19/using-newtonsoft-json-in-net-core-3-projects/)
(https://kenhaggerty.com/articles/article/aspnet-core-31-users-without-identity)
(https://github.com/CodeSeven/toastr)
(https://getbootstrap.com/docs/4.0/)
(https://fontawesome.com/v4.7.0/icons/)
(https://github.com/jmosbech/StickyTableHeaders)
(https://docs.microsoft.com/pt-br/aspnet/core/security/cors?view=aspnetcore-5.0)
(https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core)
Default JSON serialization to PascalCase, Newton! yep, my friend! that's dot net!!!