Clean implementation of FTP File Cleaners

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite












I was refactoring some of my utility code modules used in my test projects, and wanted to apply my knowledge of clean OOP design patterns and SOLID principles to make these modules more useful and easier to use.



I have an interface called IFtpFileCleaner:



/// <summary>
/// Responsible for deleting a single file located in a remote server
/// </summary>
public interface IFtpFileCleaner

/// <summary>
/// Deletes a remote file
/// </summary>
/// <param name="remotePath">
/// The full remote path.
/// </param>
void Clean(string remotePath);



I have an abstract class called RemoteFileCleaner, which implements IFtpFileCleaner:



/// <summary>
/// The file cleaner base class provides common code for all the implementations to reduce code duplication
/// </summary>
public abstract class RemoteFileCleaner : IFtpFileCleaner

/// <summary>
/// The FTP _client.
/// </summary>
private readonly IFtpSecureClient _client;

/// <summary>
/// Initializes a new instance of the <see cref="RemoteFileCleaner"/> class.
/// </summary>
/// <param name="client">
/// The FTP client.
/// </param>
protected RemoteFileCleaner(IFtpSecureClient client)

_client = client;


/// <summary>
/// Deletes a single file located on a remote server
/// </summary>
/// <param name="remotePath">
/// The full path of the remote file.
/// </param>
public void Clean(string remotePath)

try

_client.Init();
_client.DeleteFile(remotePath);

catch (Exception e)

Console.WriteLine($"Failed to clean file remotePath.Environment.NewLinee");
throw;

finally

_client.Disconnect();

Console.WriteLine($"Remote File remotePath was deleted.");




Now, I can have concrete implementations of my file cleaners. Like SFTPFileCleaner, FTPFileCleaner, and FTPSFileCleaner. They all look very similar. For instance, SFTPFileCleaner looks like this:



/// <summary>
/// The SFTP implementation of <see cref="RemoteFileCleaner"/>.
/// </summary>
public class SFTPFileCleaner : RemoteFileCleaner

/// <summary>
/// Initializes a new instance of the <see cref="SFTPFileCleaner"/> class.
/// </summary>
public SFTPFileCleaner()
: base(new FtpSecureClientTestFactory().CreateSFTPClient())





As you can see, I am performing "Bastard Injection" here in the concrete implementation because I would like to easily instantiate these cleaners in my test methods. Here is an example:



[TearDown]
public void Cleanup()

_ftpCleaner = new SFTPFileCleaner();
_ftpCleaner.Clean(_expectedRemotePath);



  1. What do you guys think about this design? Is it clean and easy to use?

  2. Can it be improved any further?

  3. Is there a name for this design pattern? To me is seems to be the mixture of Facade Pattern (Bastard Injection) and Strategy Pattern. Am I correct?






share|improve this question





















  • Welcome to Code Review! I see you added one line to the code, which doesn't appear to invalidate the current answer, but if the changes were more drastic then those would be reversed. For more information on this, see what you may and may not do after receiving answers.
    – Sam Onela
    May 24 at 18:35











  • Hi @SamOnela, sorry about that. I just realized I was missing a re-throw statement in my catch block. I didn't know about the rules. Won't happen again. :)
    – Shervin Shahrdar
    May 24 at 18:46






  • 1




    1. Not terribly clean - you're mixing data processing (FTP file deletion) with user interface (Console.WriteLine) elements and therefore violating both Dependency Inversion and Single Responsibility Principle. Inject a logger (such as Log4Net's ILog) or at worse a TextWriter in the constructor for status logging operations.
    – Jesse C. Slicer
    May 24 at 19:20










  • @JesseC.Slicer, Is it a common practice to use Log4Net in test projects? I simply want to write to a console, so that I can see the error message in the NUnit test runner and debug things faster. I do have an ILogger interface in my production code with different implementations such as Log4Net and LocalModular (My own version). Can I do another Bastard Injection from the inherited classes and inject a NativeModularLogger(new ConsoleLogger()) into the RemoteFileCleaner ?
    – Shervin Shahrdar
    May 24 at 19:39
















up vote
0
down vote

favorite












I was refactoring some of my utility code modules used in my test projects, and wanted to apply my knowledge of clean OOP design patterns and SOLID principles to make these modules more useful and easier to use.



I have an interface called IFtpFileCleaner:



/// <summary>
/// Responsible for deleting a single file located in a remote server
/// </summary>
public interface IFtpFileCleaner

/// <summary>
/// Deletes a remote file
/// </summary>
/// <param name="remotePath">
/// The full remote path.
/// </param>
void Clean(string remotePath);



I have an abstract class called RemoteFileCleaner, which implements IFtpFileCleaner:



/// <summary>
/// The file cleaner base class provides common code for all the implementations to reduce code duplication
/// </summary>
public abstract class RemoteFileCleaner : IFtpFileCleaner

/// <summary>
/// The FTP _client.
/// </summary>
private readonly IFtpSecureClient _client;

/// <summary>
/// Initializes a new instance of the <see cref="RemoteFileCleaner"/> class.
/// </summary>
/// <param name="client">
/// The FTP client.
/// </param>
protected RemoteFileCleaner(IFtpSecureClient client)

_client = client;


/// <summary>
/// Deletes a single file located on a remote server
/// </summary>
/// <param name="remotePath">
/// The full path of the remote file.
/// </param>
public void Clean(string remotePath)

try

_client.Init();
_client.DeleteFile(remotePath);

catch (Exception e)

Console.WriteLine($"Failed to clean file remotePath.Environment.NewLinee");
throw;

finally

_client.Disconnect();

Console.WriteLine($"Remote File remotePath was deleted.");




Now, I can have concrete implementations of my file cleaners. Like SFTPFileCleaner, FTPFileCleaner, and FTPSFileCleaner. They all look very similar. For instance, SFTPFileCleaner looks like this:



/// <summary>
/// The SFTP implementation of <see cref="RemoteFileCleaner"/>.
/// </summary>
public class SFTPFileCleaner : RemoteFileCleaner

/// <summary>
/// Initializes a new instance of the <see cref="SFTPFileCleaner"/> class.
/// </summary>
public SFTPFileCleaner()
: base(new FtpSecureClientTestFactory().CreateSFTPClient())





As you can see, I am performing "Bastard Injection" here in the concrete implementation because I would like to easily instantiate these cleaners in my test methods. Here is an example:



[TearDown]
public void Cleanup()

_ftpCleaner = new SFTPFileCleaner();
_ftpCleaner.Clean(_expectedRemotePath);



  1. What do you guys think about this design? Is it clean and easy to use?

  2. Can it be improved any further?

  3. Is there a name for this design pattern? To me is seems to be the mixture of Facade Pattern (Bastard Injection) and Strategy Pattern. Am I correct?






share|improve this question





















  • Welcome to Code Review! I see you added one line to the code, which doesn't appear to invalidate the current answer, but if the changes were more drastic then those would be reversed. For more information on this, see what you may and may not do after receiving answers.
    – Sam Onela
    May 24 at 18:35











  • Hi @SamOnela, sorry about that. I just realized I was missing a re-throw statement in my catch block. I didn't know about the rules. Won't happen again. :)
    – Shervin Shahrdar
    May 24 at 18:46






  • 1




    1. Not terribly clean - you're mixing data processing (FTP file deletion) with user interface (Console.WriteLine) elements and therefore violating both Dependency Inversion and Single Responsibility Principle. Inject a logger (such as Log4Net's ILog) or at worse a TextWriter in the constructor for status logging operations.
    – Jesse C. Slicer
    May 24 at 19:20










  • @JesseC.Slicer, Is it a common practice to use Log4Net in test projects? I simply want to write to a console, so that I can see the error message in the NUnit test runner and debug things faster. I do have an ILogger interface in my production code with different implementations such as Log4Net and LocalModular (My own version). Can I do another Bastard Injection from the inherited classes and inject a NativeModularLogger(new ConsoleLogger()) into the RemoteFileCleaner ?
    – Shervin Shahrdar
    May 24 at 19:39












up vote
0
down vote

favorite









up vote
0
down vote

favorite











I was refactoring some of my utility code modules used in my test projects, and wanted to apply my knowledge of clean OOP design patterns and SOLID principles to make these modules more useful and easier to use.



I have an interface called IFtpFileCleaner:



/// <summary>
/// Responsible for deleting a single file located in a remote server
/// </summary>
public interface IFtpFileCleaner

/// <summary>
/// Deletes a remote file
/// </summary>
/// <param name="remotePath">
/// The full remote path.
/// </param>
void Clean(string remotePath);



I have an abstract class called RemoteFileCleaner, which implements IFtpFileCleaner:



/// <summary>
/// The file cleaner base class provides common code for all the implementations to reduce code duplication
/// </summary>
public abstract class RemoteFileCleaner : IFtpFileCleaner

/// <summary>
/// The FTP _client.
/// </summary>
private readonly IFtpSecureClient _client;

/// <summary>
/// Initializes a new instance of the <see cref="RemoteFileCleaner"/> class.
/// </summary>
/// <param name="client">
/// The FTP client.
/// </param>
protected RemoteFileCleaner(IFtpSecureClient client)

_client = client;


/// <summary>
/// Deletes a single file located on a remote server
/// </summary>
/// <param name="remotePath">
/// The full path of the remote file.
/// </param>
public void Clean(string remotePath)

try

_client.Init();
_client.DeleteFile(remotePath);

catch (Exception e)

Console.WriteLine($"Failed to clean file remotePath.Environment.NewLinee");
throw;

finally

_client.Disconnect();

Console.WriteLine($"Remote File remotePath was deleted.");




Now, I can have concrete implementations of my file cleaners. Like SFTPFileCleaner, FTPFileCleaner, and FTPSFileCleaner. They all look very similar. For instance, SFTPFileCleaner looks like this:



/// <summary>
/// The SFTP implementation of <see cref="RemoteFileCleaner"/>.
/// </summary>
public class SFTPFileCleaner : RemoteFileCleaner

/// <summary>
/// Initializes a new instance of the <see cref="SFTPFileCleaner"/> class.
/// </summary>
public SFTPFileCleaner()
: base(new FtpSecureClientTestFactory().CreateSFTPClient())





As you can see, I am performing "Bastard Injection" here in the concrete implementation because I would like to easily instantiate these cleaners in my test methods. Here is an example:



[TearDown]
public void Cleanup()

_ftpCleaner = new SFTPFileCleaner();
_ftpCleaner.Clean(_expectedRemotePath);



  1. What do you guys think about this design? Is it clean and easy to use?

  2. Can it be improved any further?

  3. Is there a name for this design pattern? To me is seems to be the mixture of Facade Pattern (Bastard Injection) and Strategy Pattern. Am I correct?






share|improve this question













I was refactoring some of my utility code modules used in my test projects, and wanted to apply my knowledge of clean OOP design patterns and SOLID principles to make these modules more useful and easier to use.



I have an interface called IFtpFileCleaner:



/// <summary>
/// Responsible for deleting a single file located in a remote server
/// </summary>
public interface IFtpFileCleaner

/// <summary>
/// Deletes a remote file
/// </summary>
/// <param name="remotePath">
/// The full remote path.
/// </param>
void Clean(string remotePath);



I have an abstract class called RemoteFileCleaner, which implements IFtpFileCleaner:



/// <summary>
/// The file cleaner base class provides common code for all the implementations to reduce code duplication
/// </summary>
public abstract class RemoteFileCleaner : IFtpFileCleaner

/// <summary>
/// The FTP _client.
/// </summary>
private readonly IFtpSecureClient _client;

/// <summary>
/// Initializes a new instance of the <see cref="RemoteFileCleaner"/> class.
/// </summary>
/// <param name="client">
/// The FTP client.
/// </param>
protected RemoteFileCleaner(IFtpSecureClient client)

_client = client;


/// <summary>
/// Deletes a single file located on a remote server
/// </summary>
/// <param name="remotePath">
/// The full path of the remote file.
/// </param>
public void Clean(string remotePath)

try

_client.Init();
_client.DeleteFile(remotePath);

catch (Exception e)

Console.WriteLine($"Failed to clean file remotePath.Environment.NewLinee");
throw;

finally

_client.Disconnect();

Console.WriteLine($"Remote File remotePath was deleted.");




Now, I can have concrete implementations of my file cleaners. Like SFTPFileCleaner, FTPFileCleaner, and FTPSFileCleaner. They all look very similar. For instance, SFTPFileCleaner looks like this:



/// <summary>
/// The SFTP implementation of <see cref="RemoteFileCleaner"/>.
/// </summary>
public class SFTPFileCleaner : RemoteFileCleaner

/// <summary>
/// Initializes a new instance of the <see cref="SFTPFileCleaner"/> class.
/// </summary>
public SFTPFileCleaner()
: base(new FtpSecureClientTestFactory().CreateSFTPClient())





As you can see, I am performing "Bastard Injection" here in the concrete implementation because I would like to easily instantiate these cleaners in my test methods. Here is an example:



[TearDown]
public void Cleanup()

_ftpCleaner = new SFTPFileCleaner();
_ftpCleaner.Clean(_expectedRemotePath);



  1. What do you guys think about this design? Is it clean and easy to use?

  2. Can it be improved any further?

  3. Is there a name for this design pattern? To me is seems to be the mixture of Facade Pattern (Bastard Injection) and Strategy Pattern. Am I correct?








share|improve this question












share|improve this question




share|improve this question








edited May 24 at 18:20
























asked May 24 at 15:52









Shervin Shahrdar

1012




1012











  • Welcome to Code Review! I see you added one line to the code, which doesn't appear to invalidate the current answer, but if the changes were more drastic then those would be reversed. For more information on this, see what you may and may not do after receiving answers.
    – Sam Onela
    May 24 at 18:35











  • Hi @SamOnela, sorry about that. I just realized I was missing a re-throw statement in my catch block. I didn't know about the rules. Won't happen again. :)
    – Shervin Shahrdar
    May 24 at 18:46






  • 1




    1. Not terribly clean - you're mixing data processing (FTP file deletion) with user interface (Console.WriteLine) elements and therefore violating both Dependency Inversion and Single Responsibility Principle. Inject a logger (such as Log4Net's ILog) or at worse a TextWriter in the constructor for status logging operations.
    – Jesse C. Slicer
    May 24 at 19:20










  • @JesseC.Slicer, Is it a common practice to use Log4Net in test projects? I simply want to write to a console, so that I can see the error message in the NUnit test runner and debug things faster. I do have an ILogger interface in my production code with different implementations such as Log4Net and LocalModular (My own version). Can I do another Bastard Injection from the inherited classes and inject a NativeModularLogger(new ConsoleLogger()) into the RemoteFileCleaner ?
    – Shervin Shahrdar
    May 24 at 19:39
















  • Welcome to Code Review! I see you added one line to the code, which doesn't appear to invalidate the current answer, but if the changes were more drastic then those would be reversed. For more information on this, see what you may and may not do after receiving answers.
    – Sam Onela
    May 24 at 18:35











  • Hi @SamOnela, sorry about that. I just realized I was missing a re-throw statement in my catch block. I didn't know about the rules. Won't happen again. :)
    – Shervin Shahrdar
    May 24 at 18:46






  • 1




    1. Not terribly clean - you're mixing data processing (FTP file deletion) with user interface (Console.WriteLine) elements and therefore violating both Dependency Inversion and Single Responsibility Principle. Inject a logger (such as Log4Net's ILog) or at worse a TextWriter in the constructor for status logging operations.
    – Jesse C. Slicer
    May 24 at 19:20










  • @JesseC.Slicer, Is it a common practice to use Log4Net in test projects? I simply want to write to a console, so that I can see the error message in the NUnit test runner and debug things faster. I do have an ILogger interface in my production code with different implementations such as Log4Net and LocalModular (My own version). Can I do another Bastard Injection from the inherited classes and inject a NativeModularLogger(new ConsoleLogger()) into the RemoteFileCleaner ?
    – Shervin Shahrdar
    May 24 at 19:39















Welcome to Code Review! I see you added one line to the code, which doesn't appear to invalidate the current answer, but if the changes were more drastic then those would be reversed. For more information on this, see what you may and may not do after receiving answers.
– Sam Onela
May 24 at 18:35





Welcome to Code Review! I see you added one line to the code, which doesn't appear to invalidate the current answer, but if the changes were more drastic then those would be reversed. For more information on this, see what you may and may not do after receiving answers.
– Sam Onela
May 24 at 18:35













Hi @SamOnela, sorry about that. I just realized I was missing a re-throw statement in my catch block. I didn't know about the rules. Won't happen again. :)
– Shervin Shahrdar
May 24 at 18:46




Hi @SamOnela, sorry about that. I just realized I was missing a re-throw statement in my catch block. I didn't know about the rules. Won't happen again. :)
– Shervin Shahrdar
May 24 at 18:46




1




1




1. Not terribly clean - you're mixing data processing (FTP file deletion) with user interface (Console.WriteLine) elements and therefore violating both Dependency Inversion and Single Responsibility Principle. Inject a logger (such as Log4Net's ILog) or at worse a TextWriter in the constructor for status logging operations.
– Jesse C. Slicer
May 24 at 19:20




1. Not terribly clean - you're mixing data processing (FTP file deletion) with user interface (Console.WriteLine) elements and therefore violating both Dependency Inversion and Single Responsibility Principle. Inject a logger (such as Log4Net's ILog) or at worse a TextWriter in the constructor for status logging operations.
– Jesse C. Slicer
May 24 at 19:20












@JesseC.Slicer, Is it a common practice to use Log4Net in test projects? I simply want to write to a console, so that I can see the error message in the NUnit test runner and debug things faster. I do have an ILogger interface in my production code with different implementations such as Log4Net and LocalModular (My own version). Can I do another Bastard Injection from the inherited classes and inject a NativeModularLogger(new ConsoleLogger()) into the RemoteFileCleaner ?
– Shervin Shahrdar
May 24 at 19:39




@JesseC.Slicer, Is it a common practice to use Log4Net in test projects? I simply want to write to a console, so that I can see the error message in the NUnit test runner and debug things faster. I do have an ILogger interface in my production code with different implementations such as Log4Net and LocalModular (My own version). Can I do another Bastard Injection from the inherited classes and inject a NativeModularLogger(new ConsoleLogger()) into the RemoteFileCleaner ?
– Shervin Shahrdar
May 24 at 19:39










1 Answer
1






active

oldest

votes

















up vote
1
down vote













Wouldn't it make more sense to have IRemoteFileCleaner as the base class, and have FTPFileCleaner (which inherits from IRemoteFileCleaner as the class which all the others inherit from?






share|improve this answer





















  • So, just a simple rename? Good idea.
    – Shervin Shahrdar
    May 24 at 16:10










  • @ShervinShahrdar Yeah, I guess so.
    – Solomon Ucko
    May 24 at 22:09










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195097%2fclean-implementation-of-ftp-file-cleaners%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote













Wouldn't it make more sense to have IRemoteFileCleaner as the base class, and have FTPFileCleaner (which inherits from IRemoteFileCleaner as the class which all the others inherit from?






share|improve this answer





















  • So, just a simple rename? Good idea.
    – Shervin Shahrdar
    May 24 at 16:10










  • @ShervinShahrdar Yeah, I guess so.
    – Solomon Ucko
    May 24 at 22:09














up vote
1
down vote













Wouldn't it make more sense to have IRemoteFileCleaner as the base class, and have FTPFileCleaner (which inherits from IRemoteFileCleaner as the class which all the others inherit from?






share|improve this answer





















  • So, just a simple rename? Good idea.
    – Shervin Shahrdar
    May 24 at 16:10










  • @ShervinShahrdar Yeah, I guess so.
    – Solomon Ucko
    May 24 at 22:09












up vote
1
down vote










up vote
1
down vote









Wouldn't it make more sense to have IRemoteFileCleaner as the base class, and have FTPFileCleaner (which inherits from IRemoteFileCleaner as the class which all the others inherit from?






share|improve this answer













Wouldn't it make more sense to have IRemoteFileCleaner as the base class, and have FTPFileCleaner (which inherits from IRemoteFileCleaner as the class which all the others inherit from?







share|improve this answer













share|improve this answer



share|improve this answer











answered May 24 at 16:06









Solomon Ucko

822313




822313











  • So, just a simple rename? Good idea.
    – Shervin Shahrdar
    May 24 at 16:10










  • @ShervinShahrdar Yeah, I guess so.
    – Solomon Ucko
    May 24 at 22:09
















  • So, just a simple rename? Good idea.
    – Shervin Shahrdar
    May 24 at 16:10










  • @ShervinShahrdar Yeah, I guess so.
    – Solomon Ucko
    May 24 at 22:09















So, just a simple rename? Good idea.
– Shervin Shahrdar
May 24 at 16:10




So, just a simple rename? Good idea.
– Shervin Shahrdar
May 24 at 16:10












@ShervinShahrdar Yeah, I guess so.
– Solomon Ucko
May 24 at 22:09




@ShervinShahrdar Yeah, I guess so.
– Solomon Ucko
May 24 at 22:09












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f195097%2fclean-implementation-of-ftp-file-cleaners%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation