What it is prevalence?
The prevalence concept originally was idealized by the Brazilian Klaus
Wuestefeld and materialized in the project Prevayler, an implementation in
Java. It is an union of old separately applied concepts already in other
scenes.
As I mentioned in the summary, the use of the prevalence is an alternative to
the use of database. With it, all the business-objects are persisted in the
memory and have guarantee of that they will be recouped faithful in case that
has some fall of energy or fails in the application. Amongst the main
prevalence use advantages I can cite:
- The great profit of performance for query's;
- The drastic reduction of costs of a solution (it
eliminates costs of serving pair here the database (the hardware), licenses
of the
serving software of data base, operational
cost of maintenance and etc);
- Induces a development truily objects
oriented (in the my most interesting opinion).
It does not leave to visit the section "
What it is?" in the site of XPrevail project.
Key concepts
To understand the functioning general of the prevalence is important that
before let us know some terms comumente used inside of this concept, of this
form, let us see to follow the main ones of them.
PrevalenceEngine
: One is about an prevalence framework's class, that is responsible for
all the execution proceeding, it register and backup of the alterations
carried through in the PrevalentSystem
. Many times we referenciamos it simply as "
engine
". We will see more ahead than
the XPrevail
make available four type of different
engines
, each one with its particularitities.
PrevalentSystem
: A class defined for the user who must to reference all the
business objects of the application, or either, the objects that will be
persisted.
The objects referenceds ones
will be serializeds
when snapshot will be requested to
PrevalenceEngine
one. Of this form, any object is of this class will have its lost state.
Snapshot
:
The PrevalenceEngine
is the process in which
serialize
all
the PrevalentSystem
(in the reality we will see more ahead than
the XPrevail
supports the work with multiples
PrevalentSystem
's), such which it is at the moment of the request. This gives to origin a
new archive of snapshot, and becomes unnecessary the reading of the
archives of log
of previous operations.
Operation
: By the original concept considered by the prevalence, all alteration to be
carried through in objects kept for a PrevalentSystem
must be made through objects of class that implement
the
IOperation
interface
defined by framework. These instances are passed to
the PrevalenceEngine
for register and execution. In the prevayler project
the interface equivalent is called
Transaction
. (to see in
manifest
more details).
Prevalence execution flux
To understand the concept better, I go to describe which now would be
the flux of execution of a prevalent application. It imagines that let
us have only one business class in one given application, the
Client
class
. We go to the pacings to become this prevalent application.
1.
We need to define a class that will keep reference our Client
objects
, it it will be our PrevalentSystem and it could call
Clients
.
2.
We will have to declare a reference it PrevalenceEngine and
to initialize it, moment in which will be demanded the information of
which class will be the PrevalentSystem, of course must inform Clients
.
3.
The initialization of the PrevalentSystem must be requested to the
PrevalenceEngine, through the PrevalentSystem property. It will accurately return an instance from the Clients
class
with an equal state to the one of the last execution (in case that she has
had one).
4.
As it was mentioned, any alteration in the PrevalentSystem, to prevail
is demanded that it is made through objects of class that implement the
IOperation
interface
. Thus, we can declare two class,
a AddClient
call
and another
RemoveClient
call
, both implementing
the IOperation
interface
. Respectively they would be used to add and to remove objects
Client
of the PrevalentSystem. (To the long one of this text we will be able to see
what the XPrevail considers for a simpler and intuitive programming, not
demanding the creation of these class)
5.
To add a client, we now need to create an instance of
the AddClient
class
, passing in its constructor the necessary information the execution of its
task. We must then request to the PrevalenceEngine that executes this
operation. This will involve the serialization of the
AddClient
object
later in an archive destined to log of operations and its
execution, where of fact the addition of the client will occur.
6.
Let us say that after to execute some times item 5, beyond terms also carried
through some removals of client, we will have then a PrevalentSystem I
contend one definitive amount of Client
objects
. The archive of log of operations will contain a serialized version of
all the objects (that they implement IOperation
) that they had effected alterations in the PrevalentSystem, accurately in
the same order where they had occurred.
7.
Case in this point occurred an energy feed. Our application would have to be
restituted in air, so soon the environment has been re-established. At the
moment of the initialization of the PrevalenceEngine, it it will go to
read all the generated archives of log of operations. It will deserialize all
the objects contained in the archives and will go to execute them again. He
attempts against for the detail that the objects kept in this archive are of the AddClient
class
, not them of
the Client
class
. The PrevalenceEngine is constantly registering the alterations carried
through in business objects, not them business objects itself.
8.
Having the application directed to air and its recouped previous state, we
could generate plus some alterations in the PrevalentSystem and request one
snapshot. At this moment the PrevalenceEngine will go to generate a new
archive, not one of operations, but a specifically for snapshot. This archive
will contain a serialized version of the entire PrevalentSystem, or either,
effectively of all the business objects. Let us say that after snapshot, we
made plus some alterations in the state of the PrevalentSystem and occurred
another feed of energy.
9.
When our application to request the initialization of the
PrevalenceEngine, it will search for most recent snapshot generated. Of
ownership of it, it will deserialize its content and will get a version of
the PrevalentSystem. Made this, it will catch all the archives of log of
posterior operations to last snapshot and re-will execute all previously the
operations in top of the gotten PrevalentSystem. This will result in a
PrevalentSystem such which existed before the feed, of the possible optimized
form more.
Requirements of the prevalence
The prevalence possess two required requirements to be taken care of for the
business objects that will be persisted, them must be
serializables and deterministics. A deterministic object is that one
that submitted to one same series of alterations, in one same order, always
will result in one same final state. The class that represents the
PrevalentSystem, obviously, also needs to be serializable. In .NET the more
efficient and simplest form to become a serializable class is through the SerializableAttribute attribute.
The involved concepts in the prevalence are established in such way to
execute the tasks of an optimized form, this reflected in questions as:
- To serialize the alterations in business objects, in the place of
proper them, this significantly diminishes the amount of space in disk
necessary to guarantee the state of the PrevalentSystem.
- Not to have any type of indexation in the generated archives, after all the
objective is not to simulate a data base, but yes to eliminate it. Of this
form, one concentrated only in the process of serialization and restoration
of the objects.
- The restoration of a PrevalentSystem through its snapshot is
extremely faster than the backup through log of operations. It is
easy to perceive the reason, through one snapshot it
deserialize the PrevalentSystem as a whole, directly, already with log
of operations, it it needs to deserialize all the objects of operations and
to execute them again. Therefore he is recommended to carry through snapshots
periodically, but it has care, during snapshot of a PrevalentSystem cannot be
modified.
One another important detail, as all the objects are kept in memory, to work
of efficient form with prevalence are necessary to have memory RAM enough to
house all the objects of business of the system.
I wait that they have noticed that covering the described pacings
previously we do not have no involved instruction SQL. Positive a collateral
effect of the prevalence concept is that we are obliged to face with more
seriousness the object oriented concept, therefore will be only with it that
we will work. We use our proper programming language to carry through querys,
can bring and manipulate the data of any form.
What it is the XPrevail?
The XPrevail is a .NET prevalence objects layer, friendly and extended,
implemented in Delphi for .NET. The framework is compatible with any
language .NET, besides being freeware and opensource. The manifest topic XPrevail brings the reasons for which the XPrevail exists, as well as its
differentials front to other implementations of prevalence.
Great part of you differentiate them searched for me, front to the others
frameworks of prevalence, had been in favor of a more natural programming,
providing one framework so transparent and less intromicive how much it was
possible. I looked for to leave the model of
programming with the XPrevail in such way that an
application was less dependent of it, facilitating the swap of the mechanism
of persistence without great efforts.
I see the persistence as an isolated aspect of a software, not having to
influence significantly in its model, architecture and
implementation. This ideology was a constant during the modeling and
implementation of the XPrevail. These objectives had taken me to
make it some things of different form, besides adding some small features.
Amongst the main ones you differentiate brought for the XPrevail I can detach
the following ones:
PrevalentSystem's multiples
The XPrevail brings
the
MultiSystemsPrevalenceEngine, capable to work with
multiples PrevalentSystem's based
in transparent proxy's of NET. This type of engine brings the great advantage
not to need to define objects to carry through all the alterations in
the PrevalentSystem, these alterations can be made through methods defined in
the proper PrevalentSystem. The calls to these methods are intercepted and
automatically converted into objects that are, in the traditional way,
serialized and executed.
It makes possible a good splitting of responsibilities, in mode that each
PrevalentSystem keeps operations only on objects logically
related. Moreover, we can use the controlling class of the
proper system as the PrevalentSystem's, not needing to create a global one
involving them.
In summary, the use of PrevalentSystem's multiples helps to the terms a
friendly and elegant code, more compliant with the good oriented object
programming.
Covering on all the business objects
The XPrevail introduces, through
the ExtremePrevalenceEngine
, the possibility to intercept all the solicitations carried through to
business objects and automatically to transform them into
appropriate objects, to serialize them and to execute them. With this,
we can work of full transparent form, having access business objects and
modifying them directly, without the intervention of a external class, not
even of a PrevalentSystem.
This is an important pacing in the process to become the use of the XPrevail
friendliest the client code, with some few requirements, will be
able to make the prevalence of business objects directly, exactly for
alterations carried through in them. This also contributes for a form of more
natural programming and less dependent of the XPrevail or the concept of
prevalence (It sees in roadmap the intention of the XPrevail in also supporting persistence in relationary
data base).
Support to aspects oriented programming - AOP
Another well interesting feature brought by the XPrevail is the
possibility to use a model of development based on the concepts of the
aspects oriented programming, many times referenced simply as AOP. Great
part of framework is based on proxy's, in turn, in the interception
of code, basic principle of the AOP. Of this form, as I already it came
using a similar boarding for communication between proxy's and internal
class of framework, it was only question to publish a way it client
code to get features of this boarding, so soon I perceived
this potential.
Engines of framework that they implement
the
IAspectsSupport
interface
, currently
the
MultiSystemsPrevalenceEngine
and
the
ExtremePrevalenceEngine
, make avaible half to register and to deregister aspects (any
object that implements the
IAspect
interface
)
.
The XPrevail make avaible two implemented aspects, in version
preliminary daily pay, that can already freely be used by the client code, is
they it TraceAspect
and ProfileAspect
. Respectively, they are capable to register called the methods in top
business objects and to register the times taken for execution of the same
ones. This is features extremely useful and powerful, certainly it still will
be well developed in the future versions of the XPrevail (to see roadmap).
He does not leave to visit the "
Manifest" section in the site of XPrevail.
Working with the XPrevail
We will now see an full example of use of the
ExtremePrevalenceEngine , the main PrevalenceEngine of the XPrevail, in it is where we find the real
essence of framework. Before continuing, a tutorial reading of the Hello Prevalence and Hello Prevalence 2 , in the site of the XPrevail, can sufficiently help the agreement of the
example that we will develop here.
Defining the object model
Before thinking about the persistence we need first to define the model of
our business objects. For simplicity questions we go to work with only
one business object, People . We will use it stops creating a small application for I register in
cadastre of people.
People = class
strict private
FName: System.String;
FBirthDate: System.DateTime;
FEMail: System.String;
public
function ToString : String; override;
procedure set_Name(const Value: System.String);
procedure set_EMail(const Value: System.String);
procedure set_NiverDate(const Value: System.DateTime);
function get_Age: Integer;
property Name : System.String read FName write set_Name;
property Age : Integer read get_Age;
property EMail : System.String read FEMail write set_EMail;
property BirthDate : System.DateTime read FBirthDate write
set_NiverDate;
constructor Create(aName : String; aEMail : String;
aBirthDate :
DateTime);
end;
Soon, this would be the definition standard of our class, however we need to
make some alterations in mode that it takes care of the requirements of the
prevalence and the ExtremePrevalenceEngine. For this, we will need to make the following modifications:
-
As it was said, the business objects need to be serializables, then we must
include the SerializableAttribute attribute in the class.
-
The business objects, as well as the PrevalentSystem, need to be descending
MarshalByRefObject.
-
So that framework obtains to correctly identify a given business
object, it it needs to implement the IObjectID interface, besides being marked with the BusinessObjectClassID attribute.
Carried through the necessary alterations, the interface of our
People class is thus:
[Serializable]
[BusinessObjectClassID(PeopleClassID)]
People = class (MarshalByRefObject, IObjectID)
strict private
FID : System.String;
FName: System.String;
FBirthDate: System.DateTime;
FEMail: System.String;
public
function ObjectID : string;
function ToString : String; override;
procedure set_Name(const Value: System.String);
procedure set_EMail(const Value: System.String);
procedure set_NiverDate(const Value: System.DateTime);
function get_Age: Integer;
property Name : System.String read FName write set_Name;
property Age : Integer read get_Age;
property EMail : System.String read FEMail write set_EMail;
property BirthDate : System.DateTime read FBirthDate write
set_NiverDate;
constructor Create(aID, aName : String; aEMail : String; aBirthDate :
DateTime);
end;
The next pacing is to create a class that will be our PrevalentSystem, sees
then the definition of the PeopleManager class for this intention.
[Serializable]
[PrevalentSystemClassID('{319D4955-4CE8-4443-9010-9BAE12046C24}')]
PeopleManager = class (MarshalByRefObject, IBusinessObjectFromID)
strict private
FPeoples : ArrayList;
strict protected
function BusinessObjectFromID(BOClassID, ObjectID: string): TObject;
public
function AllPeoples : ArrayList;
[BusinessObjectExport]
function get_Peoples(Index: Integer): People;
property Peoples[Index : Integer] : People read get_Peoples;
function get_PeopleCount : Integer;
property PeopleCount : Integer read get_PeopleCount;
[Operation]
[BusinessObjectExport]
function AddPeople(aID, aName : String; aEMail : String; aBirthDate :
DateTime) : People;
[Operation]
[RealBusinessObjectRecovery]
procedure RemovePeople(aPeople : People);
constructor Create;
end;
Such which a business object class, the PrevalentSystem also needs to descend
of MarshalByRefObject and to receive the Serializable attribute (in the truth to be serializable). As the ExtremePrevalenceEngine is a PrevalenceEngine that it supports to work with some PrevalentSystem's,
it is necessary that they are marked with the PrevalentSystemClassID attribute, so that framework obtains to identify them correctly. It also
notices that the IBusinessObjectFromID interface is implemented by the PeopleManager class, this is necessary only if the PrevalentSystem in question keeps
reference the business objects.
It observes the use of some attributes decorating methods of the
PeopleManager class, let us see now so that it serves each one of them.
1.
Operation : It indicates to the XPrevail that the method in question carries through
alterations in the state of the PrevalentSystem. In case that a method that
modifies the state of the PrevalentSystem is marked with this attribute, the
alteration will not prevail.
2.
BusinessObjectExport : It indicates to framework that this method returns an object from business
for is of the PrevalentSystem, this form, the XPrevail intercepts this call
and returns one proxy for the object in question, in mode that the
alterations carried through directly in the object are persisted. It observes
that, as in all mechanism of persistence, it fits to the programmer to decide
what will be persisted. Alterations in an object of business gotten for a
method without this attribute will not be persisted.
3.
RealBusinessObjectRecovery : It indicates to the XPrevail that it must recoup the object from a version
duplicate of it (more details in the box to follow).
RealBusinessObjectRecovery
The prevalence in general way prohibit that class that implement the
IOperation interface (or Transaction in the Prevayler), or either, that they modify the state of a PrevalentSystem
has direct reference to a business object. Therefore of this form, the
business object will be duplicate and the alteration in question will be
given in this version duplicates, this cause sufficient problems. This error
is sufficiently common, being considered an error of baptism of the
prevalence.
Then, the XPrevail does not recommend that this is fact, however not
prohibit. It it leaves the option of thus shape you its code, being client of
will involve some cost of performance. Being certain of this option, it is
enough to mark the method with the RealBusinessObjectRecovery attribute and the XPrevail will take care of so that this does not generate
unexpected problems. This will be demonstrated in the example.
Soon, now already we have our justifd class to develop our prevalent
example. And best, all the persistence code already was practically
fact, or either, almost none. It observes that the requirements of the
XPrevail are not very intrusive, since attributes and/or implementations of
interfaces are decided with adornments through. An eventual decision to
remove the XPrevail as persistence mechanism, or to customize software to
another mechanism, does not imply in a significant loss of code.
Developing a console application
We now go to create a console application to illustrate the use of the
class that we define. So that the text is not big extensive, I will
place only the really excellent stretches of implementation. To have access
to the full code it is enough to make download of the applicatory one of
example of this article. To compile it, it is essential to lower the
XPrevail, you can make this through link http://xprevail.sourceforge.net/en-us/download.htm.
The first point to comment as to get an initial instance of our
PrevalentSystem and as we will see, it must be requested to the
PrevalenceEngine. But for this, we need first to get an instance of proper
engine. The code below illustrates all this process:
001. var
002.
Engine : ExtremePrevalenceEngine;
003.
GenKeys : GenerateKeys;
004.
PManager : PeopleManager;
005.
006. begin
007.
Engine := XPrevailFactory.CreateExtremePrevalenceEngine([typeOf(GenerateKeys),
typeOf(PeopleManager)], Path.Combine(Environment.CurrentDirectory, 'data'));
008.
GenKeys
:= Engine.PrevalentSystems[typeOf(GenerateKeys)] as GenerateKeys;
009.
PManager := Engine.PrevalentSystems[typeOf(PeopleManager)] as PeopleManager;
010. {�}
011. end.
The lines 002 to 004 contain only the declarations of the
references. In line 007 the creation of an instance of the
ExtremePrevalenceEngine class is requested, as we can see, this is made
through the XPrevailFactory class. The CreateExtremePrevalenceEngine method
requires as first parameter an array of System.Type representing the PrevalentSystem's that will be managed by engine. As the
parameter informs the folder where the archives of log of operations and
archives of snapshots will be placed.
Certainly you already it perceived that we are using as a PrevalentSystem,
represented for the GenerateKeys class. That as the name it suggests, will
serve exactly as a generator of ID's for our objects. The definition of this
class is very simple and can below be seen:
[Serializable]
[PrevalentSystemClassID('{5CFE36DA-9C6A-495F-911B-10CD99374195}')]
GenerateKeys = class (MarshalByRefObject)
strict private
HashKeys : HashTable;
public
[Operation]
function NewKey(ObjectType : System.Type) : Integer;
constructor Create;
end;
It assures that an only one for objects of a specified type is generated
sequential, can occur of business objects to have equal ID's, since that they
are of different types. This is a requirement of the ExtremePrevalenceEngine . It observes that as it does not keep business objects, does not need to
implement the IBusinessObjectFromID interface. To follow we can see the
implementation of its main method, the NewKey.
function GenerateKeys.NewKey(ObjectType: System.Type): Integer;
var
KeyID : Integer;
begin
Monitor.Enter(ObjectType);
try
if HashKeys.Contains(ObjectType) then
begin
KeyID := Integer(HashKeys.Item[ObjectType]);
Inc(KeyID);
HashKeys.Item[ObjectType] := &Object(KeyID);
end
else
begin
KeyID := 1;
HashKeys.Add(ObjectType, &Object(KeyID));
end;
Result := KeyID;
finally
Monitor.Exit(ObjectType);
end;
end;
Strings 008 and 009 get the instances of our PrevalentSystem's. As the
operations of the PeopleManager will use the GenerateKeys , it is important that this last either requested first one. This is made
through the PrevalentSystems property, having informed the System.Type of the intended PrevalentSystem. We now go to continue analyzing some
stretches keys of the implementation of our applicatory one.
Adding a people
var
{...}
ID : String;
begin
{...}
ID := Convert.ToString(GenKeys.NewKey(typeOf(People)));
PManager.AddPeople(ID, Name, Email, BirthDate);
{...}
end;
Removing a people
{...}
PManager.RemovePeople(PManager.Peoples[
Ind
]);
{...}
Editing a people
var
Ind : Integer;
Pp : People;
Value : String;
begin
{...}
Ind
:= Convert.ToInt32(Console.ReadLine);
Pp := PManager.Peoples[
Ind
];
{...}
WriteLine('');
WriteLine('Type new value:');
Value := Console.ReadLine;
case
Ind
of
1 : Pp.Name := Value;
2 : Pp.EMail := Value;
3 : Pp.BirthDate := Convert.ToDateTime(Console.ReadLine);
else begin
WriteLine('Invalid option, exiting.');
Exit;
end;
end;
{...}
end;
Listing the people
var
Arr : ArrayList;
I : Integer;
begin
Console.WriteLine('');
Arr := PManager.AllPeoples;
for I := 0 to Arr.Count - 1 do
begin
with (Arr[I] as People) do
begin
Console.WriteLine('[{0}] {1}', &Object(I), &Object(ToString));
end;
end;
Console.WriteLine('');
end;
Showing the results
As we can see, all the code is surprising simple. Now let us see a little of
our application in execution:
Figure 1.
Aperture of the ObjectApp example
Figure 2.
Adding a people
Figure 3.
Listing the registered in cadastre people
Being our application ready we can register in cadastre, modify and exclude
people the will, and best, independent of that it occurs, its data will be
safe. It carries through these operations some times, requests snapshot's
evaluates it the result. You can make tests killing the process or same
disconnect the machine, you will see that the data will be kept and recouped
in the next execution. Everything this without using a data base!
After to carry through some operations, to request one snapshot and later
more operations we can see that the XPrevail generated the files as shown in
figure 4.
Figure 4.
Archives of log of operations and archive of snapshot
Supporte to Aspects Oriented Programming - AOP
In this article I will only introduce this subject, but it certainly will be
boarded in more details in posterior tutorial or articles.
One of the excellent features brought for the XPrevail is the support to a
programming based on the principles of the Aspects Oriented Programming -
AOP. This support is dynamic and extensible, the process of creation of
aspects is simple and very powerful. Through it we can have elegant solutions
for generation of logs, control of concurrency, profiler, auditorship and etc.
The AOP promises to fill a gap not filled by the POO, where the
cited example most classic is the generation of log's. In the traditional
boarding when we need to generate one log of the execution flux of our
applicatory one we finish being obliged to spread code for some class. Code
this that is not of the intention of the class.
The AOP understands that the generation of log's, as well as diverse other
problems - including the persistence, it is aspect of software and it does
not have to join the business rules. The implementation of the AOP today
still is not something standardized such which the POO, of this form, can
find some forms of boardings and philosophies of implementation of this
concept.
I go to only show now a bit of the potential of this wonder and as you to
make use of it through the XPrevail.
Using the ProfilerAspect
It assumes that let us want to make to profiler of our application to know
how much time is delaying the execution of some methods. How you it would
make this? Obviously it would open the application source and it would start
to distribute measurement codes, clearly. But, let us see as we make this
with the XPrevail. For this we will modify only two lines of our
applicatory one of test, sees:
{...}
Engine.RegisterAspect(ProfilerAspect.Create(nil, falsifies));
{...}
This line registers a new aspect (this already available by the
XPrevail) in ours engine. Its constructor asks for two parameters, the first
one is one stream for register of the measurements - passing nil it he will
emit in the console. As the parameter indicates if it must indiscriminately
act on all the methods of the PrevalentSystem's and business objects kept by
the Engine.
As we pass false it will act only on the methods marked with the
MethodProfiler attribute. Then, to test, we go to place this attribute in the PeopleManager.AllPeoples method.
{...}
[ MethodProfiler ]
function AllPeoples: ArrayList;
{...}
Soon, made this it is enough to compile the application and we will execute
again. It sees in figure 5 the result.
Figure 5.
ProfilerAspect in action
Frightful? Not, I would say fun. Certainly this is a very powerful feature.
As it said previously, it now wanted only to leave this presatation, will
have one another tutorial or article approaching in more details the use
and development of aspects with the XPrevail.
Current state of the XPrevail project
Today the XPrevail is in the version 0.9.4 alpha, improvements and refatorys
is being made in it constantly. Although it is a version alpha it already is
full functional. To visits the section " Roadmap" of the project site to know where route it goes to be lead.
In general lines, it is possible that the XPrevail comes to support
persistence in relational data bases, of transparent form. Features as
replications, support efficient to transactions and object locking also are
foreseen. The objective biggest is that let us can, through the XPrevail, to
program prevalent applications, with aspects, fault tolerance and load
balance. Also it has support the development of dual applications, would be a
type of tolerance to the feeds same for applications statefull.
Still I am gradual developing the tutorial documentation of the class,
articles and and unit tests. Any aid in this direction, as well as with
translation for other languages will be appreciated. The spreading of
framework through articles, creation of examples and cases of study will be
very well comings.
Conclusion
Simple, not? It are the object model, you saw much referring code the
persistence in our application? Really not. It obtains to calculate how much
time already spent inside codifying SQL of its class
L
? But for me, most cool it is the sensation of that the persistence does
not exist, that we are freely working with objects, without in worrying them
about its state, therefore they will prevail.
They do not leave to visit the project site
http://xprevail.sourceforge.net and start already to program prevalent applications.
Version 1.1 - 11/21/2004
FernandoVM
is Borland Delphi Certified, speaker of all the editions of the BorCon
Brazil. Already it acted as contributor, writer and publisher technician of
the ClubeDelphi magazine. He is manager of technology, architect and
coordinator of the team of development of the Tactium product, a real-teime
distributed solution of CTI/CRM used for more than 90 companies,
throughout 14 Brazilian states, in the Softium Inform�tica Ltda.
Creator and mantenedor of the XPrevail project, Can be contacted in
fernandovm@users.sourceforge.net
or
http://fernandovm.blogspot.com
.