Click here to Skip to main content
15,032,967 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi;

I need to change an already developed desktop application.(Application developed by using winforms)

The application have already designed UI's with seperate UserControls(ex. PriceOfferRequestUserControl, OrderUserControl etc.), database tables and models. What I want to do is implementing a design pattern(s) for increase the application's maintability.

I haven't used MVP design pattern before but I used repository desing pattern for web service project.

My questions are;
- Is MVP design pattern suitible for enterprise desktop application? If it isn't what desing patterns best suited for enterprise desktop applications?
- Can I use MVP design pattern with repository design pattern? If I can't what is the best way to communicate with database?
- As I mentioned before, application have already creadted models(objects). But if I use the repository pattern EntityFramework also creates models from database. In this situation which model's should I use, existing ones or the created ones?

Thank you.

What I have tried:

I looked some examples for MVP design pattern.
Posted
Updated 3-Feb-18 16:57pm

1 solution

OK manifesto here!!!

Implementing MVP into an existing 1-layer app app is a rewrite. I wouldn't recommend that unless you have no backlog, and lots of testers for the app. Otherwise, polish off your resume, unless your boss is expecting a re-write and all the delays and retesting that go with it.

In that case, use a completely modern platform. Unless you have Win7 or lower users - use Xamarin forms, it's desktop/win10 compatible, and can go to mobile. Use MVVM. Of course, it's a completely different development philosophy.

If win7, use WPF, but there's no mobile route there.

But so is MVP, only with MVP you will do everything manually. MVVM a lot is built-in many ways by Microsoft.

In favor of MVP: you might keep slightly more winforms related code, but, almost all would have to be stuck in the views, which would weaken the benefit of an upgrade. Of course, it would also give you an 'out' if time ran out - at least some would be refactored/rewritten.

My recommendation: find a new need of your users, start the new app using modern architecture. If none, do the refactor/re-write.

Regarding the repository pattern: it's a powerful tool. Take note not to inject repositories into your domain objects. These should be wired up at a higher level - the objects that call the domain objects. This is a layer between the Presenters (or viewmodels) and the domain model. Domain objects shouldn't know about repositories, they shouldn't know to save/load themselves. They shouldn't have direct references to other domain objects.

Of course, repositories will know about your domain objects, you have to inject it, the mapping will be in them.

This moves some code into that layer (DDD calls it 'services' code layer, others call it the application layer, many don't know of its usefulness). Note: having the domain objects know about abstractions of the repositories is just as bad coupling wise.

Everybody makes objects so you can do 'foreach (Account acct in Customer.Accounts)...' ... and then put that logic in customer. That's not SoC. It spans both business objects. Don't put references or list of references to one business object in another. Put that logic that touches both in the ddd-services layer. (note these are not business objects - they take references to the business objects) This also solves the n+1 problem. this also solves 95% of the Objects-Relational impedance mismatch. This lets you do what you want in your app and persist to SQL without eating the dry bran flakes of NoSql. A lot of things fall in place.

Stitch business objects together by their PK IDs an FK ids. Some will claim this leaks the SQL implementation into the objects. But if you're storing in SQL anyway you have no choice. And it doesn't carry the disadvantage of those leaks esp. if you put them in string types in your objects, then it can hold int, guid, composite key, etc. whatever you can change it to. In other words, don't worry about such 'leaking'.

Don't go too far of course or your business objects will be anemic. For simple cases parameter injection is OK as long as you don't keep a reference to the other business object. Example (code in ddd-services layer object - which gets the others injected - cust.GetAmountDue(from acct in accounts where acct.custid==cust.id) ). Here you injected an enumerable of Account - by parameter - into the GetAmountDue method of Customer. No constructor/property injection - that's holding the reference!

For your 3rd question, if you use EF skip the repositories or you will be double-wrapping your DB. AFAIK most ORMs have mocking built in for your unit tests. Knowing that Business Objects should not persist themselves helps this make sense. In your DDD-services layer map the EF models to your domain objects. For the sake of all that is good in the world, use AutoMapper (etc), or ExpandoObjects/Propertybag domain objects, with matching property names (loop thru them to map), otherwise, get ready to end it all looking for errors you will make monkey-coding the stuff.

If this is all too much, remember - SOLID is not do or die. It can only make things 20-30% better than a well-written OO program that took a reasonably conservative to from a fanciness standpoint, and until you get good at it, chances are it will make things 20-50% WORSE than that!
   
Comments
Onur ERYILMAZ 4-Feb-18 10:36am
   
Thank you for reply.

As I understand, you recommend starting from scratch with using WPF or Xamarin Forms. I will consider that.

I have a few questions though.

1- You talked about domain objects and business objects. As I understand I need to seperate my objects.

For example:

EF creates an object based on my database schema like this;

public class Company
    {
        [Required]
        [Key]
        public string CompanyCode { get; set; }
        public string CompanyName { get; set; }
        public CompanyTypes CompanyType { get; set; }
        public string CompanyTaxAdministration { get; set; }
        public string CompanyTaxNumber { get; set; }
        public string CompanyWebAdress { get; set; }
        public string CompanyMailAdress { get; set; }
        public byte[] CompanyLogo { get; set; }

        public virtual ICollection<CompanyAddress> CompanyAddresses { get; set; }

        public Company()
        {
            CompanyAddresses = new HashSet<CompanyAddress>();
        }
    }


And I have an object like this:

public class Company
    {
        public string CompanyCode { get; set; }
        public string CompanyName { get; set; }
        public CompanyTypes CompanyType { get; et; }
        public string CompanyTaxAdministration { get; set; }
        public string CompanyTaxNumber { get; set; }
        public string CompanyWebAdress { get; set; }
        public string CompanyMailAdress { get; set; }
        public byte[] CompanyLogo { get; set; }

        public Company(string cCode, string cName, CompanyTypes cType, string taxAdmin, string cTaxNum, string web, string mail, byte[] logo)
        {
            CompanyCode = cCode;
            CompanyName = cName;
            CompanyType = cType;
            CompanyTaxAdministration = taxAdmin;
            CompanyTaxNumber = cTaxNum;
            CompanyWebAdress = web;
            CompanyMailAdress = mail;
            CompanyLogo = logo;
        }
    }


So, when user wants to create a new company, first I get the user inputs and put these in my Company object and then convert this object to EF object with AutoMapper then send EF object to repository to save it?
fastal 4-Feb-18 22:29pm
   
I think you are on a track that would work.

I would think if you are still going to use repositories, do the mapping between the EF objects and YOUR objects INSIDE the repositories. Here is a great post that goes into more detail about doing it that way:
https://stackoverflow.com/questions/24588838/entities-vs-domain-models-vs-view-models

I refer to the same things when I say 'domain objects' and 'business objects' - but not all writers do that, I see. In that post, it appears as though they may mean the EF objects by 'domain' objects - although I'm not sure, that seems a non-standard way of doing it. Sorry for using both of the terms.

You will see most people don't talk about the 'DDD-Services' layer for composing and integrating your business objects. This example is no exception. Just make room for it in your project - it is not a layer that all properties need to be mapped to nor 'thru' - when you have some complicated inter-object logic, though, it may make more sense to make a new object in the services layer, inject the business objects that need the work done, and do the work there, to avoid mixing references to objects. Note - this is about 10% of the logic that really needs it, but, usually it's the more complicated logic ;-)

If your business objects don't hold references to repositories, it makes unit tests easier, there is less to mock... I would not recommend mocking nor abstracting your business objects either to test your domain layer objects - this will result in less granular units as they depend on the business objects, but if your business objects have good tests, that will mitigate this. This will give you most of the value of the tests without the technical debt of abstracting your business objects (which takes more than it gives). If this last paragraph doesn't make sense, ignore it ;-)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900