Organização e facilidade em ler um código

1. Organização e facilidade em ler um código

Lucas Veríssimo de Oliveira
donutLukke

(usa Outra)

Enviado em 26/02/2023 - 19:18h

Boa noite pessoal, tenho uma dúvida a respeito de organização e facilidade em ler um código, suponhamos que eu queria salvar um dado do tipo Produto.

typedef struct_produto
{
int codigo[9];
char nome[30];
char marca[20];
}Produto;

E eu também queira salvar um dado do tipo Colaborador.

typedef struct_colaborador
{
int id[7];
char nome[30];
char cpf[11];
}Colaborador;

Seria melhor eu criar uma função que pudesse salvar os dois tipos de dados, usando dessa forma uma varíavel que identificasse quando entrou um dado do tipo produto ou colaborador...

int salvar(No_Arv **a, int opcao)
{
if(opcao == 1){ // Opção para salvar um dado do tipo produto
.....
.....
}
else if(opcao == 2){ // Opção para salvar um dado do tipo colaborador
.....
.....
}
}

Ou criasse funções separadas, uma que salvasse o dado do tipo produto e outra que salvasse o dado do tipo colaborador?

Desde já, agradeço pela ajuda.


  


2. Re: Organização e facilidade em ler um código

Alexa Bolada
alexabolada

(usa Debian)

Enviado em 26/02/2023 - 19:18h

R: Olá, é importante que você considere a simplicidade e a legibilidade de seu código ao escrevê-lo, pois isso ajudará na manutenção e na facilidade de entendimento do seu programa. Dessa forma, aconselho a criar funções diferentes para salvar dados do tipo produto ou colaborador. O uso de uma variável para diferenciar esses tipos de dados ajudará a manter as suas funções nomeadas curtas e objetivas, além de facilitar a leitura do código. Por exemplo, você pode ter uma função chamada `salvarProduto()` para salvar um produto e outra chamada `salvarColaborador()` para salvar um colaborador. Desta forma, seu código ficará mais organizado e fácil de entender. Espero ter ajudado.


3. Re: Organização e facilidade em ler um código

Paulo
paulo1205

(usa Ubuntu)

Enviado em 28/02/2023 - 01:10h

@alexabolada,

Sua resposta acima ficou confusa, pois você o autor perguntou se deveria usar funções diferentes ou usar um parâmetro a mais para especificar o tipo de dado a ser escrito, e você mandou ele escrever duas funções e usar uma variável a mais, quando, na verdade, apenas uma das duas formas deveria ser escolhida.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


4. Re: Organização e facilidade em ler um código

Alexa Bolada
alexabolada

(usa Debian)

Enviado em 28/02/2023 - 01:10h

A questão provavelmente indicava que o usuário deva escolher entre usar duas funções separadas ou usar um parâmetro a mais para especificar o tipo de dado a ser escrito. Se você quiser usar duas funções, você deve definir cada função separadamente. Se você quiser usar um parâmetro extra, você pode usar um parâmetro como tipo de dado especificado para indicar ao programa qual o tipo de dado está sendo passado. Por exemplo, a função write() possui um parâmetro como type para indicar o tipo de dado escrito. Para entender melhor essas duas formas de resolver o problema, uma boa leitura pode ser útil. Espero ter ajudado!


5. Re: Organização e facilidade em ler um código

Paulo
paulo1205

(usa Ubuntu)

Enviado em 28/02/2023 - 07:53h

Quando você tem tipos agregados de dados, em geral é melhor usar funções específicas para entrada e saída de cada tipo de dado (continue lendo e veja o exemplo na parte final desta postagem).

Como você pretende salvar os arquivos no disco? Em formato binário? Transformando todos os campos em texto?

Se for transformando para texto, você não tem escapatória de fazer código sob medida para cada tipo de dado, esteja esse código em duas funções separadas ou numa função só.

Se for em formato binário, a mais óbvia implementação é gravar diretamente o conteúdo de cada estrutura, o que é mais simples de fazer com uma função só do que seria se tivesse de haver uma conversão para texto. De fato, é tão simples de fazer com uma função só, que essa função inclusive já existe como building block para qualquer outra função específica: trata-se exatamente da função fwrite(), da biblioteca padrão do C. Provavelmente suas implementações de salvar_colaborador() e salvar_produto() (se você viesse a escrevê-las) usariam fwrite() internamente, e teriam o seguinte aspecto geral.
// Função para salvar colaborador: retorna true se for bem sucedida ou false se não o for.
bool salvar_colaborador(const Colaborador *colab, FILE *fp){
return fwrite(colab, sizeof *colab, 1, fp)==1;
}

// Função para salvar produto: retorna true se for bem sucedida ou false se não o for.
bool salvar_produto(const Produto *prod, FILE *fp){
return fwrite(prod. sizeof *prod, 1, fp)==1;
}

/* BONUS: salvar vários colaboradores ou produtos de uma vez só (os quais tipicamente estarão armazenados em arrays). */

// Função para gravar um array com n colaboradores. Retorna a quantidade de colaboradores salva com sucesso.
size_t salvar_multi_colaboradores(const Colaborador *colabs, size_t n, FILE *fp){
return fwrite(colabs, sizeof colabs[0], n, fp);
}

// Função para gravar um array com n produtos. Retorna a quantidade de produtos salva com sucesso.
size_t salvar_multi_produtos(const Produto *prods, size_t n, FILE *fp){
return fwrite(prods, sizeof prods[0], n, fp);
}


Usando funções específicas, você reduz a chance de cometer enganos, e permite que o compilador diagnostique possíveis erros (que geralmente aparecem quando a gente faz copy-and-paste ou quando estamos muito cansados). Compare estes dois códigos (ambos problemáticos).
typedef enum save_type {REG_COLAB, REG_PROD} tipo_salvamento;

// Note o uso de “void *” (ponteiro para tipo indeterminado em tempo de compilação).
bool salvar_registro(tipo_salvamento tipo_reg, void *reg, FILE *fp){
switch(type){
case REG_COLAB:
return fwrite(reg, sizeof (Colaborador), 1, fp)==1;
case REG_PROD:
return fwrite(reg, sizeof (Produto), 1, fp)==1;
}
return false;
}

int main(void){
Colaborador colab;
FILE *fp;
// ...
// Faz ajustes em colab e fp.
// ...
salvar_registro(REG_PROD, &colab, fp); // Note a mistura entre o tipo informado e o real tipo do dado.
// ...
}
bool salvar_produto(const Produto *prod, FILE *fp){
return fwrite(prod. sizeof *prod, 1, fp)==1;
}

int main(void){
Colaborador colab;
FILE *fp;
// ...
// Faz ajustes em colab e fp.
// ...
salvar_produto(&colab, fp); // Note a discrepância entre o dado informado e o que a função espera.
// ...
}

A maior diferença entre os dois casos acima é que o primeiro não permite que o compilador ajude o programador a identificar o erro: o uso de void * para permitir que a função aceite qualquer tipo de argumento (desde que seja um ponteiro) e o desacoplamento entre ponteiro e a informação do tipo que ele carrega vão permitir que o programa não apenas compile sem problemas, mas também que possivelmente execute sem qualquer tipo de alarme, até o dia em que alguém precisar ler os dados, e ver que eles provavelmente estarão corrompidos; já o segundo programa nem sequer vai compilar, porque o compilador não vai deixar você passar como argumento um ponteiro para colaborador para um parâmetro que espera um ponteiro para produto, obrigando-o a corrigir o sentido.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts