Code repetition in the same method

Asked

Viewed 118 times

3

I have a method that generates some information. As I was in a hurry to deliver, I did and sent. Well, it turns out, seeing the code more carefully, I realized how inelegant it is. It was made to meet a specification and as it was changed I had to change the code. The current rule is as follows: I have a method that handles files from Pharmacist. The same goes for the Drugstore. It happens, that now I need to create before the folder Pharmacist, two new folders. Homologation and Production. In each folder(Homologation and Production) there should be two folders: Farminterna and Farmexterna. I will talk only about Farminterna, which will also apply to External. The same files as Gero in the path: ...Homolagacao/FarmInterna/web/... are the same to: ...Producao/FarmInterna/web/.... This has made my code extremely ugly and inelegant. How do I not duplicate the code as is? Is there a Pattern for this? Below my code. Where the letter exists H refers to Homolagation and P the production.

private void CriaPastaFarmInterna()
        {
            string novo_path_H  = caminho_original + @"\Destino\Temp\Homologacao\FarmInterna\web";
            string novo_path_P  = caminho_original + @"\Destino\Temp\Producao\FarmInterna\web";
            string path_files   = caminho_original + @"\Destino\Temp";

            DirectoryInfo dirInfoH = new DirectoryInfo(novo_path_H);
            DirectoryInfo dirInfoP = new DirectoryInfo(novo_path_P);

            int indice = 1;

            if (dirInfoH.Exists == false)
                Directory.CreateDirectory(novo_path_H);

            if (dirInfoP.Exists == false)
                Directory.CreateDirectory(novo_path_P);

            List<String> myFiles = Directory.GetFiles(caminho_original + @"\Destino\Temp\web", "*.*", SearchOption.AllDirectories).ToList();

            List<String> myDirectoriesH = Directory.GetDirectories(caminho_original + @"\Destino\Temp\web").ToList();
            List<String> myDirectoriesP = Directory.GetDirectories(caminho_original + @"\Destino\Temp\web").ToList();

            var diretorios_H = myDirectoriesH.Where(d => !d.Contains("FarmInterna"));
            var diretorios_P = myDirectoriesP.Where(d => !d.Contains("FarmInterna"));

            try
            {
                foreach (string file in myFiles)
                {
                    FileInfo mFile = new FileInfo(file);
                    string newFileH = novo_path_H + (file.Replace(caminho_original + @"\Destino\Temp\web", ""));
                    string newFileP = novo_path_P + (file.Replace(caminho_original + @"\Destino\Temp\web", ""));

                    if (!Directory.Exists(newFileH))
                        Directory.CreateDirectory(Path.GetDirectoryName(newFileH));

                    if (!Directory.Exists(newFileP))
                        Directory.CreateDirectory(Path.GetDirectoryName(newFileP));

                    if (new FileInfo(newFileH).Exists == false)
                        mFile.CopyTo(newFileH);

                    if (new FileInfo(newFileP).Exists == false)
                        mFile.CopyTo(newFileP);
                }

                RenomearWebConfig(novo_path_H, "H");
                RenomearWebConfig(novo_path_P, "P");
            }
            catch(Exception ex)
            {}
        }
  • My initial idea would be to take out the duplicate lines in this code, bearing in mind that they create new directories and the file being repeated in the two directories created. You would change mainly the performance and the number of lines decreasing accordingly. As the directory is new and the files are new it does a check only in one of the folders. You can do the following, run this routine to a folder and at the end copy the files to the other folder is also an idea. You can use Adapter, but, it does not need to my view

3 answers

4


The Re-factoring for duplicate code deletion is quite simple:

  • 1) Declare a new method (it will receive the code that generalizes the solution that today is duplicated).

  • 2) Traverse the code of the original method by moving each duplicate line into the new method. Look closely: moving! It is not copying and pasting, it is cropping and pasting. Choose a pattern of lines to move; for example: move to the new method the lines you deal with "homologation", leaving the lines they treat "producing" in the original method.

  • 3) The lines that structure the execution (conditions, loops, Try-catch...) are eventually not duplicated - these you copy to the new method instead of moving.

  • 4) The lines moved to the new method will not compile because they need variables that do not exist in that context. Declare each of these missing variables as parameters of this new method. Now the new method already compiles.

  • 5) In the code of the new method, replace with parameters constants and literals that are unique to each execution, in order to make generic the lines that use these constants and literals.

  • 6) Go through the original method again and replace the lines that have already been replicated in the new method with a call to this new method, passing the parameters as required by it (in this case, the parameters referring to "production").

  • 7) Make one more call to the new method, passing as a parameter the variables of the other call (in this case, the parameters referring to "approval").

  • 8) Rename the parameters and internal variables of the new method to express its generic solution nature for both "production" and "homologation".

Ready. Now you have the original method generating the arguments needed to be passed in the two calls to the new method.

This step-by-step is generic and can be used for any Refactoring of this type.

Tip: If you are willing, add the Step Zero at the beginning of the list, which is a unit test covering the functionality and which will ensure that it continues producing the same results after the Refactoring.

Following this step-by-step, the code goes like this:

private void CriaPastaFarmInternaEExterna()
{
    string novo_path_H = caminho_original + @"\Destino\Temp\Homologacao\FarmInterna\web";
    string novo_path_P = caminho_original + @"\Destino\Temp\Producao\FarmInterna\web";

    List<String> myFiles = Directory.GetFiles(caminho_original + @"\Destino\Temp\web", "*.*", SearchOption.AllDirectories).ToList();

    CriaPastaFarm(novo_path_H, myFiles, "H");
    CriaPastaFarm(novo_path_P, myFiles, "P");
}

private void CriaPastaFarm(string novo_path, IEnumerable<string> files, string ambiente)
{
    DirectoryInfo dirInfo = new DirectoryInfo(novo_path);

    if (dirInfo.Exists == false)
        Directory.CreateDirectory(novo_path);

    List<String> myDirectories = Directory.GetDirectories(caminho_original + @"\Destino\Temp\web").ToList();
    var diretorios = myDirectories.Where(d => !d.Contains("FarmInterna"));

    foreach (string file in files)
    {
        FileInfo mFile = new FileInfo(file);
        string newFile = novo_path + (file.Replace(caminho_original + @"\Destino\Temp\web", ""));

        if (!Directory.Exists(newFile))
            Directory.CreateDirectory(Path.GetDirectoryName(newFile));

        if (new FileInfo(newFile).Exists == false)
            mFile.CopyTo(newFile);
    }
    RenomearWebConfig(novo_path, ambiente);
}

Note: I left out the variables Indice and path_files that were not being used. I also left out the Try-catch because the way you used it, clearing the exception, can cause problems.

Note: There are several things that can be improved, such as replacing with a Enum the literals "H" and "P" in order to increase the expressiveness of the code; replace the comparison (condição == false) by denying the condition, (!condição), which is more usual; delete file path repetitions (@"\Destination Temp web"); etc..

  • Caffé, I have not yet implemented your example, but it was extremely useful for me. Tomorrow (Tuesday) I will do what you suggested.

  • Caffé, as it would be for the Farmexterna?

0

Friend, centralize the repeated code in a new method, and call this method 2 times passing the parameters that change the behavior of the program.

private void CriaPastaFarmInterna()
        {
            NovoMetodo(caminho_original + @"\Destino\Temp\Homologacao\FarmInterna\web", 'H');
            NovoMetodo(caminho_original + @"\Destino\Temp\Producao\FarmInterna\web", 'P');


}

private void NovoMetodo(string novoPath, char letra) {

    DirectoryInfo dirInfo = new DirectoryInfo(novoPath);    

    if (dirInfo.Exists == false)
                Directory.CreateDirectory(novoPath);

    List<String> myFiles = Directory.GetFiles(caminho_original + @"\Destino\Temp\web", "*.*", SearchOption.AllDirectories).ToList();

    List<String> myDirectories = Directory.GetDirectories(caminho_original + @"\Destino\Temp\web").ToList();

    var diretorios = myDirectories.Where(d => !d.Contains("FarmInterna"));

    try
    {
        foreach (string file in myFiles)
        {
            FileInfo mFile = new FileInfo(file);
            string newFile = novoPath + (file.Replace(caminho_original + @"\Destino\Temp\web", ""));

            if (!Directory.Exists(newFile))
                Directory.CreateDirectory(Path.GetDirectoryName(newFile));


            if (new FileInfo(newFile).Exists == false)
                mFile.CopyTo(newFile);

        }

        RenomearWebConfig(novoPath, letra);
    }
    catch(Exception ex)
    {}

}

0

you can try it as follows:

private void CriaPastaFarmInterna(string oldPath, string newPath)
{
    var oldDirectory = new DirectoryInfo(oldPath);
    var newDirectory = new DirectoryInfo(newPath);

    if (!oldDirectory.Exists)
        return false;       

    if (!diretorio.Exists)
        diretorio.Create();

    for (var subDirectory in oldDirectory.GetDirectories())
    {
        CriaPastaFarmInterna(subDirectory.FullName, newPath + @"\" + subDirectory.Name)
    }

    for (var oldFile in oldDirectory.GetFiles())
    {
        var newFile = new FileInfo(newDirectory.FullName + @"\" + oldFile.Name);
        if (!newFile.Exists)
            oldFile.CopyTo(newFile.FullName)
    }
}

private void CriaPastaFarmInterna()
{
    string oldPath   = caminho_original + @"\Destino\Temp\Web";
    string newPathH  = caminho_original + @"\Destino\Temp\Homologacao\FarmInterna\web";
    string newPathP  = caminho_original + @"\Destino\Temp\Producao\FarmInterna\web";

    try
    {
        CriaPastaFarmInterna(oldPath, newPathH);
        CriaPastaFarmInterna(oldPath, newPathP);

        RenomearWebConfig(novo_path_H, "H");
        RenomearWebConfig(novo_path_P, "P");
    }
    catch(Exception ex)
    {           

    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.