You are not logged in.
Hi,
I need to rewrite a very big application with a legacy Firebird database using Delphi XE (now I’m using Delphi 2007).
The source code is over 2M lines of code and since the application contains more than 400 forms I need to separate it into different modules.
For the new application I need two things :
· separate the business logic from the forms (Views)
· create just a few modules that manages the application core parts. For example one module for the orders management,another one for the warehouse management,another one for the sells.
Is there a best practices for load plug-in (DLL or BPL) using interfaces for the Business logic?
Which is the correct way to use the mORMot solution ? Can I modularize mORMot validations and queries ?
For the forms I think to use this approach http://delphi.cjcsoft.net/viewthread.php?tid=44129 or similiar (I had tried Jedi plug-in and TMS)
thank you in advance
The mind is like a parachute, it only works if you open it.
Albert Einstein
Offline
Your application, even with plug-ins, still has a 2-Tier architecture.
The main benefit of mORMot is to have a n-Tier architecture, with n>2.
That is, you create a server in which the logic remains, and your clients are just simple views with minimal logic.
Tier 1 = client, Tier 2 = server, Tier 3 = DB.
And mORMot is even more effective with a 4-Tier solution:
Tier 1 = client, Tier 2 = application Server, Tier 3 = business logic server, Tier 4 = DB.
Of course, here "tiers" are logical, so in a typical mORMot architecture, you may have just 2 physical executable:
- one Client (Tier 1)
- one Server (Tier 2,3 and 4 - using a local Sqlite3 database)
I'm currently working on a didactic new sample to show how to write a TDD + SOA + MVC app using mORMot, and following most DDD principles.
Offline
I have this successful proof of concept using "mORMot" services as DLL.
https://drive.google.com/open?id=0Bx7LP … lAwYmNjQWs
Maybe is helpful for you.
Esteban
Offline
Thank you AB for the reply, good I wait for the new example.
I like DDD approach but I'm little confused on using it on very big application and how define contracts to write less code: i.e. write general interfaces like IRemoteSQL (validations? authorizations?) or an interface for every object.
The mind is like a parachute, it only works if you open it.
Albert Einstein
Offline
very interesting Martin... thank you
The mind is like a parachute, it only works if you open it.
Albert Einstein
Offline
ab,
interesting hint:
Tier 1 = client, Tier 2 = application Server, Tier 3 = business logic server, Tier 4 = DB
how is implemented Tier 3 in your diagram?
Simply a set of classes or you are thinking in something more mORMot-ish ?
Offline
@EMartin
I tested the program you provided, it worked very well.
After that, I wrote a DLL like the example, Interface copy from "16 - Execute SQL via services"。
IRemoteSQL = interface(IInvokable)
['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
procedure Connect(const aServer, aDatabase, aUserID, aPassWord: RawUTF8);
function GetTableNames: TRawUTF8DynArray;
function Execute(const aSQL: RawUTF8; aExpectResults, aExpanded: Boolean): RawJSON;
end;
but found the following two questions:
1. when client call ServiceRegisterClientDriven(TypeInfo(IRemoteSQL), ISQL), error occurred:
{
"ClassName":"EServiceException",
"Address":"015E4340",
"Message": "TServiceFactoryClient.Create(): server's IRemoteSQL contract differs from client's: expected [\"ED5FDD7EA62781EB\"], received [\"4607DE69C9F22AD4\"]"
}
Exception EServiceException raised - ErrorCode=400
2. call ISQL.Execute with parameters ('select * from aTable', True, False).
but when trace the DLL, received parameters are ('select * from aTable', False, False).
what's wrong with me? Can you help me?
Last edited by daisutao (2016-07-06 12:27:32)
Offline
@daisutao I don't know what the problem, it is a proof concept and I did not have time to deep in the same. Sorry.
Esteban
Offline
@ab
do you know what happened?
Offline
The reason seems to be parameter Boolean。
when i change Boolean to ByteBool, the problem 2 is ok.
a bug??
Offline
There is not enough code to reproduce the issue.
Bug may be most probably in the use. There are a lot of mORMot servers, in production, using boolean parameters, I can tell you!
You may write a simple client/server project and post a link to a dropbox archive here.
Offline
i known, when service build in exe, it's ok, but build in dll, error happended.
please check the following code:
https://www.dropbox.com/s/iokoydstrxbwv … d.zip?dl=0
problem 1. at file fClient.pas line 64
Client.ServiceRegisterClientDriven(TypeInfo(IRemoteSQL), ISQL)
--------------with param '*', will pass--------------
Client.ServiceRegisterClientDriven(TypeInfo(IRemoteSQL), ISQL, '*')
problem2. call ISQL.Execute with param True, received param False.
function Execute(const aSQL: RawUTF8; aExpectResults, aExpanded: Boolean): RawJSON;
--------------change Boolean to ByteBool, will ok--------------
function Execute(const aSQL: RawUTF8; aExpectResults, aExpanded: ByteBool): RawJSON;
Last edited by daisutao (2016-07-07 08:16:54)
Offline
I have this successful proof of concept using "mORMot" services as DLL.
https://drive.google.com/open?id=0Bx7LP … lAwYmNjQWs
Maybe is helpful for you.
Your sample app does not work with TPersistentWithCustomCreate
TTest = class(TPersistentWithCustomCreate)
public
constructor Create;
end;
TDLLOneService = class(TInterfacedObject, IDLLOneService)
protected
function Test1(const aText: RawUTF8): RawUTF8;
procedure ABC(out x: TTest);
end;
the problem concerns invalid class recognition in exe, mOROmot does not recognize TPersistentWithCustomCreate
Probably the mORMot should be attached to new package (bpl) and build with that runtime packages in both - exe and dll.
Offline
The problem is probably in your code.
TTest = class(TPersistentWithCustomCreate)
public
constructor Create;
end;
The TPersistentWithCustomCreate constructor is virtual and your Create is not marked as "override".
public
constructor Create; override;
end;
As with any virtual constructor.
Offline
No, that virtual keyword is not a problem, I just forget to put it in sample above.
Look how the mOROmot classified the class inherited from TPersistentWithCustomCreate
if C<>nil then
continue else begin
ItemCreate := cicTObject;
exit;
end;
instead of
end else begin
ItemCreate := cicTPersistentWithCustomCreate;
exit;
I think that the virtual table for dll is other then exe so for example the "is" statement won't work if you won't check Build with runtime packages for dll+exe and use the package that contain the class you are testing by "is".
Offline
So it is a problem of Delphi RTTI.
There are two TPersistentWithCustomCreate classes, one in the dll and one in the main exe
But I don't understand
1. why the classes are mixed
2. why you need to use the mORMot client/server feature between a dll and an exe
Offline
I can confirm that moving mormot*.pas/Syncommons.pas to the new package (bpl) and building both exe and dll with that package solved the problem. Now the TPersistentWithCustomCreate class is identified as:
end else begin
ItemCreate := cicTPersistentWithCustomCreate;
exit;
Thanks.
Offline
So it is a problem of Delphi RTTI.
There are two TPersistentWithCustomCreate classes, one in the dll and one in the main exeBut I don't understand
1. why the classes are mixed
2. why you need to use the mORMot client/server feature between a dll and an exe
Ad2. I've created the TSQLRestServerFullMemory in my Server Core. There are a lot of basic methods for most of my customers. But I have a few customers who needs the special features such as /root/Stupid.StupidMethod. I will never add such sh*t to the server core so I decided to create the dll libraries which extends my TSQLRestServerFullMemory by custom methods.
--------
MyCustomer123.dpr
begin
TInterfaceFactory.RegisterInterfaces([TypeInfo(IStupid)]);
RestServer := (SharedFunctions as ISharedFunctions).RestServer;
RestServer.ServiceDefine(TStupidIntegration, [IStupid], sicShared);
end;
Offline
You are forgetting we have bpl
I have a standard ERP, and for the few customers with non standard needs we make modules (packages) that plug in the system, using all standard stuff, and adding or overriding any functionality
I'm starting with mORMot, so I'm just making some packages with the sources, wich works fine
Drawback: when you build a new version, you need to rebuild the customer packages as well
Offline
You are forgetting we have bpl
I have a standard ERP, and for the few customers with non standard needs we make modules (packages) that plug in the system, using all standard stuff, and adding or overriding any functionalityI'm starting with mORMot, so I'm just making some packages with the sources, wich works fine
Drawback: when you build a new version, you need to rebuild the customer packages as well
@Javierus, we have the similar solution since a years (I mean extra features in libraries), but we use DLL instead of BPL. We use that feature in both - client application and server. To be honest, the client application without plugins is extremely thin, allows to log-in and log-out, the plugins makes it a huge application with features depends on customer needs or the features bought by customer.
Offline
That's one place Delphi still outshines FPC, I really wish FPC had BPL equivalent.
Offline
@radexpol our app is a VCL monolith, there are no tiers: refactoring that to a n-tier cross platform is our goal
We are going for a MVVM approach there
Back to plugins: the exe just loads the main bpl, wich provides most of the erp-agnostic services: base form classes, security, automation, reporting, everything
The whole ERP is in fact a bunch of plugins that use the basic classes and services, and offer new classes and services to anyone that needs them
There are more ERP plugins providing major (ie. Manufacturing) or minor functionality, and the customer plugins, wich again can be major (ie.airport handling) or minor (ie.integration with a customer web)
All this depends heavily on sharing classes between plugins, and that is natural with BPL
I don't have any idea on how to do that without BPL. To be honest, I never had any need to restrict myself to DLL
Offline
I use bpl here too.
An advantage of DLL is that it does not force you to compile with the dependency on runtime pakages.
But, if you are compiling the exe and the DLL with the dependency on runtime packages, any advantage of the DLL is lost.
Offline
BPL is good only when it was well coded, otherwise the code would be like a monolithic, taking out any benefits for use it.
IMO a good way to have modularization using DLL is using the same approach as dbExpress (since Delphi 7):
- create a entry point Interface
- the library exports a function that creates an instance tha implements the interface
Instead of having a lot of functions inside a DLL, we have just one entry point using object-oriented approach.
Offline