0

Right now I’m working on a very big banking solution developed in VB6. The application is massively form-based and lacks a layered architecture (all the code for data access, business logic and form manipulation is in the single form class). My job is now to refactor this code. I'm writing a proper business logic layer and data access layer in C# and the form will remain in VB.

Here are code snippets:

public class DistrictDAO
{
    public string Id{get;set;}
    public string DistrictName { get; set; }
    public string CountryId { get; set; }
    public DateTime SetDate { get; set; }
    public string UserName { get; set; }
    public char StatusFlag { get; set; }
}

District Entity class, why its extension is DAO, Im not clear.

 public class DistrictGateway
{
    #region private variable
    private DatabaseManager _databaseManager;
    #endregion

    #region Constructor
    public DistrictGateway(DatabaseManager databaseManager) {
        _databaseManager = databaseManager;
    }
    #endregion

    #region private methods
    private void SetDistrictToList(List<DistrictDAO> dataTable, int index, DistrictDAO district){
        // here is some code for inserting 
    }    
    #endregion

    #region public methods
        try
        {
        /*
         query and rest of the codes
         */    

        }
        catch (SqlException sqlException)
        {
            Console.WriteLine(sqlException.Message);
            throw;
        }
        catch (FormatException formateException)
        {
            Console.WriteLine(formateException.Message);
            throw;
        }
        finally {
            _databaseManager.ConnectToDatabase();
        }


    public void InsertDistrict() { 
        // all query to insert object
    }

    public void UpdateDistrict() { 

    }
    #endregion
}

DistrictGateway class responsible for database query handling Now the business layer.

  public class District
{
    public string Id { get; set; }
    public string DistrictName { get; set; }
    public string CountryId { get; set; }
}


public class DistrictManager
{
    #region private variable
    private DatabaseManager _databaseManager;
    private DistrictGateway _districtGateway;
    #endregion

    #region Constructor
    public DistrictManager() { 
        // Instantiate the private variable using utitlity classes
    }
    #endregion

    #region private method
    private District TransformDistrictBLLToDL(DistrictDAO districtDAO) { 

        // return converted district with lots of coding here
    }

    private DistrictDAO TransformDistrictDLToBLL(District district)
    {

        // return converted DistrictDAO with lots of coding here
    }

    private List<District> TransformDistrictBLLToDL(List<DistrictDAO> districtDAOList)
    {

        // return converted district with lots of coding here
    }

    private List<DistrictDAO> TransformDistrictDLToBLL(List<District> district)
    {

        // return converted DistrictDAO with lots of coding here
    }


    #endregion

    #region public methods
    public List<District> GetDistrict() {
        try
        {
            _databaseManager.ConnectToDatabase();
          return TransformDistrictBLLToDL(  _districtGateway.GetDistrict());

        }
        catch (SqlException sqlException)
        {
            Console.WriteLine(sqlException.Message);
            throw;
        }
        catch (FormatException formateException)
        {
            Console.WriteLine(formateException.Message);
            throw;
        }
        finally {
            _databaseManager.ConnectToDatabase();
        }
    }

    #endregion

This is the code for the business layer.

My questions are:

  1. Is it a perfect design?
  2. If not, what are flaws here?
  3. I think, this code with duplicated try catch block
  4. What can be good design for this implementation
Dan J
  • 16,319
  • 7
  • 50
  • 82
A N M Bazlur Rahman
  • 2,280
  • 6
  • 38
  • 51

4 Answers4

0

Perfect? No such thing. If you have to ask here, it's probably wrong. And even if it's "perfect" right now, it won't be once time and entropy get ahold of it.

The measure of how well you did will come when it's time to extend it. If your changes slide right in, you did well. If you feel like you're fighting legacy code to add changes, figure out what you did wrong and refactor it.

Flaws? It's hard to tell. I don't have the energy, time, or motivation to dig very deeply right now.

Can't figure out what you mean by #3.

The typical layering would look like this, with the arrows showing dependencies:

view <- controller -> service +-> model <- persistence  (service knows about persistence)

There are cross-cutting concerns for each layer:

  • view knows about presentation, styling, and localization. It does whatever validation is possible to improve user experience, but doesn't include business rules.
  • controller is intimately tied to view. It cares about binding and validation of requests from view, routing to the appropriate service, error handling, and routing to the next view. That's it. The business logic belongs in the service, because you want it to be the same for web, tablet, mobile, etc.
  • service is where the business logic lives. It worries about validation according to business rules and collaborating with model and persistence layers to fulfill use cases. It knows about use cases, units of work, and transactions.
  • model objects can be value objects if you prefer a more functional style or be given richer business logic if you're so inclined.
  • persistence isolates all database interactions.

You can consider cross-cutting concerns like security, transactions, monitoring, logging, etc. as aspects if you use a framework like Spring that includes aspect-oriented programming.

duffymo
  • 305,152
  • 44
  • 369
  • 561
0

Though, you aren't really asking a specific question here, it seems you may just need some general guidance to get you going on the right path. Since we don't have an in-depth view of the application as a whole as you do, it would be odd enough to suggest a single methodology for you.

n-tier architecture seems to be a popular question recently, but it sparked me to write a blog series on it. Check these SO questions, and blog posts. I think they will greatly help you.

Blog Series on N-Tier Architecture (with example code)

Community
  • 1
  • 1
David Anderson
  • 13,558
  • 5
  • 50
  • 76
0

For a big project i would recommend the MVVM pattern so you will be able to test your code fully, and later it will be much easier to extend it or change parts of it. Even you will be able to change the UI,without changing the code in the other layers.

BigL
  • 1,631
  • 1
  • 11
  • 10
0

If your job is to refactor the code then first of all ask your boss if you should really, really should just refactor it or add functionality to it. In both cases you need an automated test harness around that code. If you are lucky and you should add functionality to it, then you at least have a starting point and a goal. Otherwise you will have to pick the starting point by yourself and do not have a goal. You can refactor code endlessly. That can be quite frustrating without a goal.

Refactoring code without tests a recipe for disaster. Refactoring code means improving its structure without changing its behavior. If you do not make any tests, you cannot be sure that you did not break something. Since you need to test regularly and a lot, then these tests must be automated. Otherwise you spend too much time with manual testing.

Legacy code is hard to press into some test harness. You will need to modify it in order to get it testable. Your effort to wrap tests around the code will implicitly lead to some layered structure of code.

Now there is the hen and egg problem: You need to refactor the code in order to test it, but you have no tests right now. The answer is to start with “defensive” refactor techniques and do manual testing. You can find more details about these techniques in Micheal Feather's book Working Effectively with Legacy Code. If you need to refactor a lot of legacy code, you should really read it. It is a real eye opener.

To your questions:

  1. There is no perfect design. There are only potentially better ones.
  2. If the application does not have any unit tests, then this is the biggest flaw. Introduce tests first. On the other hand: Those code snippets are not that bad at all. It seems that DistrictDAO something like the technical version of District. Maybe there was some attempt to introduce some domain model. And: At least DistrictGateway gets the DatabaseManager injected as constructor parameter. I have seen worse.
  3. Yes, the try-catch blocks can be seen as code duplicates, but that is nothing unusual. You can try to reduce the catch clauses with a sensible choice of Exception classes. Or you can use delegates or use some AOP techniques, but that will make the code less readable. For more see this other question.
  4. Fit the legacy code into some test harness. A better design will implicitly emerge.

Any way: First of all clarify what your boss means with refactoring code. Just refactoring code without some goal is not productive and will not make the boss happy.

Community
  • 1
  • 1
Theo Lenndorff
  • 4,556
  • 3
  • 28
  • 43