Em um projeto recente, fui encarregado de refatorar grandes partes de um sistema web. Está escrito em C#. Com o tempo, alguns dos arquivos code-behind cresceram para 4000 linhas. O objetivo era reduzir esse número para um nível mais mantível.
Nos próximos posts, peguei trechos de código que refatorei e vou explicar meus pensamentos e como cheguei à solução.
O primeiro trecho de código:
string tmp = Request.QueryString["st"];
_varStartRecNum = tmp;
if ((tmp != null) & (!Page.IsPostBack))
{
_varStartRecNum = tmp;
postBack = true;
}
tmp = Request.QueryString["det"];
if ((tmp != null) & (!Page.IsPostBack))
{
_varDetailsRecNum = tmp;
postBack = true;
}
tmp = Request.QueryString["return"];
if ((tmp != null) & (!Page.IsPostBack))
{
postBack = true;
}
tmp = Request.QueryString["searchnow"];
if ((tmp != null) & (!Page.IsPostBack))
{
Session["selectedTab"] = "mtf";
Session["sessionDSProviders"] = null;
Session["mtfs"] = null;
}
tmp = Request.QueryString["displaywalking"];
if (tmp == "true")
{
dispMtf = false;
postBack = true;
}
tmp = Request.QueryString["sb"];
if ((tmp != null) & (!Page.IsPostBack))
{
_varSortBy = tmp;
postBack = true;
switch (_varSortBy)
{
case "Distance":
case "Drive time":
ddlSortBy.SelectedIndex = 0;
break;
case "Name":
ddlSortBy.SelectedIndex = 1;
break;
case "Gender":
ddlSortBy.SelectedIndex = 2;
break;
case "Clinic":
ddlSortBy.SelectedIndex = 3;
break;
case "City":
ddlSortBy.SelectedIndex = 4;
break;
case "Description":
ddlSortBy.SelectedIndex = 5;
break;
}
}
O trecho de código acima é uma coleção de instruções if, que são uma avaliação e uma execução. Na minha primeira tentativa, tentei usar a mesma avaliação para todas as instruções if, mas então percebi que uma era diferente. Não entendendo a intenção do código, sou forçado a preservar a lógica literalmente.
Avaliação if diferente:
tmp = Request.QueryString["displaywalking"];
if (tmp == "true")
{
dispMtf = false;
postBack = true;
}
A instrução switch me preocupou. A condição para entrar na instrução switch é a mesma que as outras. Decidi prosseguir e me preocupar com a instrução switch depois.
O código usa a mesma variável, a variável ‘tmp’, para recuperar diferentes valores de consulta. O valor é sobrescrito com cada recuperação de valor de consulta. Para maior clareza, criei uma variável para cada valor de consulta:
string st = Request.QueryString["st"];
string det = Request.QueryString["det"];
string @return = Request.QueryString["return"];
string searchNow = Request.QueryString["searchnow"];
string displayWaling = Request.QueryString["displaywalking"];
string sb = Request.QueryString["sb"];
O próximo passo foi isolar a avaliação e a expressão, mantendo-as associadas uma à outra. Se uma avaliação for verdadeira, quero executar sua expressão correspondente. Criei uma classe que representava a associação.
private class Evaluate
{
public Func Evaluation { get; set; }
public Action Expression { get; set; }
}
Agora posso criar uma avaliação e, se for verdadeira, posso executar sua expressão.
O próximo problema era como usar a classe acima com todas as instruções if. Eu estava preocupado que as expressões pudessem ficar difíceis de lidar em uma coleção. O objetivo inteiro era criar uma solução concisa e escalável. A solução existente não era nenhuma das duas.
var eval = new[]
{
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(st) && !IsPostBack), Expression = () => { _varStartRecNum = st;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(det) && !IsPostBack), Expression = () => { _varStartRecNum = det;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(@return) && !IsPostBack), Expression = () => {postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(searchNow) && !IsPostBack), Expression = () => {Session["selectedTab"] = "mtf";Session["sessionDSProviders"] = null; Session["mtfs"] = null;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(displayWaling)), Expression = () => {dispMtf = false; postBack = true;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(sb) && !IsPostBack), Expression = () => {_varSortBy = sb;postBack = true; SetSort(_varSortBy);}},
};
Funcionou melhor do que eu esperava. Uma desvantagem da minha solução é que, se você não souber como usar delegados, terá dificuldades em manter o código acima.
O último obstáculo foi a instrução switch. Não se encaixaria graciosamente em minha coleção anônima, mas então não precisava:
private void SetSort(string sortBy)
{
switch (sortBy)
{
case "Distance":
case "Drive time":
ddlSortBy.SelectedIndex = 0;
break;
case "Name":
ddlSortBy.SelectedIndex = 1;
break;
case "Gender":
ddlSortBy.SelectedIndex = 2;
break;
case "Clinic":
ddlSortBy.SelectedIndex = 3;
break;
case "City":
ddlSortBy.SelectedIndex = 4;
break;
case "Description":
ddlSortBy.SelectedIndex = 5;
break;
}
}
Ao encapsulá-la em um método, consegui referenciar o método na expressão. Funcionou muito bem.
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(sb) && !IsPostBack), Expression = () => {_varSortBy = sb;postBack = true; SetSort(_varSortBy);}
O último componente é iterar sobre a coleção:
foreach (var evaluate in eval.Where(evaluate => evaluate.Evaluation()))
{
evaluate.Expression();
}
A solução completa:
private class Evaluate
{
public Func Evaluation { get; set; }
public Action Expression { get; set; }
}
private void SetSort(string sortBy)
{
switch (sortBy)
{
case "Distance":
case "Drive time":
ddlSortBy.SelectedIndex = 0;
break;
case "Name":
ddlSortBy.SelectedIndex = 1;
break;
case "Gender":
ddlSortBy.SelectedIndex = 2;
break;
case "Clinic":
ddlSortBy.SelectedIndex = 3;
break;
case "City":
ddlSortBy.SelectedIndex = 4;
break;
case "Description":
ddlSortBy.SelectedIndex = 5;
break;
}
}
private void EvaluateQueryParameters()
{
string st = Request.QueryString["st"];
string det = Request.QueryString["det"];
string @return = Request.QueryString["return"];
string searchNow = Request.QueryString["searchnow"];
string displayWaling = Request.QueryString["displaywalking"];
string sb = Request.QueryString["sb"];
var eval = new[]
{
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(st) && !IsPostBack), Expression = () => { _varStartRecNum = st;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(det) && !IsPostBack), Expression = () => { _varStartRecNum = det;postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(@return) && !IsPostBack), Expression = () => {postBack = true; }},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(searchNow) && !IsPostBack), Expression = () => {Session["selectedTab"] = "mtf";Session["sessionDSProviders"] = null; Session["mtfs"] = null;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(displayWaling)), Expression = () => {dispMtf = false; postBack = true;}},
new Evaluate {Evaluation = () => (!string.IsNullOrEmpty(sb) && !IsPostBack), Expression = () => {_varSortBy = sb;postBack = true; SetSort(_varSortBy);}},
};
foreach (var evaluate in eval.Where(evaluate => evaluate.Evaluation()))
{
evaluate.Expression();
}
}
No final, gosto mais dessa solução do que da original. Uma das desvantagens é o nível em que está escrita. Eu queria criar uma solução mais simples que qualquer desenvolvedor pudesse manter. Não há nada difícil no código acima; estou criando uma coleção e iterando sobre ela. A confusão vem com a avaliação e as expressões. Não é um tópico para iniciantes.
Autor: Chuck Conway é um Engenheiro de IA com quase 30 anos de experiência em engenharia de software. Ele constrói sistemas de IA práticos—pipelines de conteúdo, agentes de infraestrutura e ferramentas que resolvem problemas reais—e compartilha o que está aprendendo ao longo do caminho. Conecte-se com ele nas redes sociais: X (@chuckconway) ou visite-o no YouTube e no SubStack.