lundi 20 avril 2015

Best pattern to data persistence with C procedural language

I am using some different data structures in my program. Each data structure has associated functions to insert, delete and update some data of the data structure. For instance, to simplify the question i have a vector of struct recipes and some methods to add a new recipe, delete a recipe or change the ingredients of some recipe.

There is a Web UI so the user can perform operations like add a new recipe through this UI. The back-end functions that process the input forms call the methods for updating the data structure. Something like this:

#include <recipesAPI.h>

void addRecipeform (form *input)
{
    char* recipename;
    char* ingredient1;
    char* ingredient2;
    char* ingredient3;


    recipename = GetFormVar(input, "recipename", ""); // Get value in the POST request for the form field named recipename, if not present get ""
    ingredient1 = GetFormVar(input, "ingredient1", ""); 
    ingredient2 = GetFormVar(input, "ingredient2", ""); 
    ingredient3 = GetFormVar(input, "ingredient3", ""); 

    if (!addRecipe(recipename,ingredient1,ingredient2,ingredient3))
        return ERR_500(); // Return 500 error to the browser 

}

I wanted this vector to be persistent among different program executions.

I am using a database. I am thinking of ways to separate the domain logic (my data structures with associated methods) from the persistence. I have three ways.

1 - I may implement the access to the database inside the methods addRecipe() and deleteRecipe() but this way i am not abstracting the Data Access Layer so the business logic is mixed with the persistence layer (i can not change the database easily using this way without changing the methods that implement the constraint and operations logic over my Recipe Data Structure).

2 - Another way is creating a new database API that exposes some interfaces as saveRecipe(...) or retrieveRecipe(..) and then implement the save of a recipe to the database. Then i should create database API to set and retrieve all my data structures from the database. This way the UI back-end should be changed by something like this:

#include <recipesAPI.h>
#include <recipesDatabaseApi.h

void addRecipeform (form *input)
{
    char* recipename;
    char* ingredient1;
    char* ingredient2;
    char* ingredient3;


    recipename = GetFormVar(input, "recipename", ""); // Get value in the POST request for the form field named recipename, if not present get ""
    ingredient1 = GetFormVar(input, "ingredient1", ""); 
    ingredient2 = GetFormVar(input, "ingredient2", ""); 
    ingredient3 = GetFormVar(input, "ingredient3", ""); 

    if (!addRecipe(recipename,ingredient1,ingredient2,ingredient3))
        return ERR_500(); // Return 500 error to the browser 

    if (!database_addRecipe(recipename,ingredient1,ingredient2,ingredient3))
        return ERR_500();

}

3 - The last way that I can think of separating business logic from the persistence is defining a new API that encapsulates both the database and the business logic. This new will API expose the interface AddRecipeAndStore, but it implements the method this way

#include <recipesApi.h>
#include <recipesDatabaseApi.h

int AddRecipeAndStore(char* recipename, char* ingredient1,char*  ingredient2, char* ingredient3)  
{
    if (!addRecipe(recipename,ingredient1,ingredient2,ingredient3))
        return 0;
    if (!database_addRecipe(recipename,ingredient1,ingredient2,ingredient3))
        return 0;

    return 1;

}

I think the method 3 is the most portable. Using the method 3 above the database is separate from the data structures operations logic, but the UI back-end functions are at the same time agnostic about persistence. So i can name this new API as the RecipesManager, and it may has a method to initialize it (then it initializes both the database and the data structures). Then the back-end UI function can use this new API:

#include <recipesCM.h>

void addRecipeform (form *input)
{
    char* recipename;
    char* ingredient1;
    char* ingredient2;
    char* ingredient3;


    recipename = GetFormVar(input, "recipename", ""); // Get value in the POST request for the form field named recipename, if not present get ""
    ingredient1 = GetFormVar(input, "ingredient1", ""); 
    ingredient2 = GetFormVar(input, "ingredient2", ""); 
    ingredient3 = GetFormVar(input, "ingredient3", ""); 

    if (!addRecipeAndStore(recipename,ingredient1,ingredient2,ingredient3))
        return ERR_500(); // Return 500 error to the browser 

}

One concerng using method 3: - Data is duplicated in the database and the data structure in memory at the same time. Which method should be used when retrieving a data from the data structure, should i retrieve the data from the database or from the data structure itself? Should i retrieve the data from the data structure because it's just a matter of performance?

I dont know if there are betters ways to design and abstract persistence from the business specific logic. I am willing to listen about benefits and disadvantages abstracting the data access layer or about some open source utilities to implement some kind of object oriented database.

Aucun commentaire:

Enregistrer un commentaire