I'm building an application that is responsible for reading data from files and displaying them in charts. The whole application is responsible for manipulating data from files, which means I have to use different parts of the same object in almost every part of my project. Charts need actual data, list of opened files needs names and states of data, etc. On top of that my application uses MEF
, so others can add new functionality and modify current modules.
My biggest problem is how to separate that data, so each layer of my application has access only to part of that data that is required for it to work. What I mean by data is:
- Name of file
- Guid Id
List<IColumn>
data orbyte[]
data- Additional future variables
I decided to use across my application IDocument
. This is my custom representation of one file that can be read and displayed in chart. Each IDocument
must have an Id
and Name
because every computer file has a name. This has all the information that is needed for a simple list of files that were imported into the application. But it doesn't have the actual data that I want to display, so I use NoSQL database for storing IDocumentData
that has List<IColumn> Columns
that I can throw into a chart. IColumn
has only List<object> Rows
which basically mimics a table.
So I seperated my file into IDocument
and IDocumentData
, now how do I keep track of which data belongs to which document? I get IDocumentData
from IReader
module and I get IWizardData
from IFileImporterWizard
module.
I was thinking about creating some kind of builder that would assign the same Id to IDocument
and IWizardData
(contains importated Name
and Id
) and when I would want to access data I would pass Id
from IDocument
. Is this a good approach?
So for example:
public class DocumentBuilder {
private IDocumentFactory _documentFactory;
private IDocumentDataRepository _documentDataRepository;
public DocumentBuilder(IDocumentFactory documentFactory, IDocumentDataRepository documentDataRepository)
{
_documentFactory = documentFactory;
_documentDataRepository = documentDataRepository;
}
public IDocument Build(IWizardData wizardData, IDocumentData documentData)
{
var document = _documentFactory.Create();
document.Id = wizardData.Id;
documentData.Id = wizardData.Id;
_documentDataRepository.Add(documentData);
return document;
}
}
So my thinking looks like this: Open File wizard returns IWizardData
(name, filePath) -> IReader
returns IDocumentData
(List<IColumn>
columns) -> DocumentBuilder
builds IDocument
and saves data
EDIT:
So I figured out how to separate business and data layers by creating
interface IDocument : IDocumentData, IDocumentInformation
IDocumentInformation
has a name and other information. IDocumentData
has Id
and DataTable Data { get; set; }
. I can save IDocumentData
and IDocumentInformation
separately and still have Id
that is the same for both of them.
I decided to change IColumn
and List<object> Rows
, because I hope DataTable
will cause less problems. Although I'm still wondering if DataTable
is a good choice, because it will probably decrease performance when loading data. I thought that it would be a good idea to load from NoSQL
only a couple of records and then add them to chart and loop it until the end.
So now IFileWizard
returns IDocumentInformation
, IReader
takes IDocumentInformation
and returns IDocumentData
and then they get combined.
Naming these things takes some time, because they all use parts of the same object, but seeing IFileWizard
returning IDocumentInformation
is a little bit weird. On the other hand in order to make them easily interchangeable I would have to declare even more common interfaces and create interface IFileWizardResult:IInfo
and have interface IDocumentInformation:IInfo
and then return IFileWizardResult
and cast it to IInfo
, etc. I don't know if this is too much decoupling or not. I want this application to be easily scalable, but making a lot of interfaces not always means better decoupling.