4

I am working on a project of an online service provider.

I have tables for admin, agent, customer and tables for data storage like city, services, category, sub-category, gender.

I have created classes for the admin, customer and agent. But should I create classes for city, services, category, etc or use as methods in admin, customer and agent.

note:- I want to perform CRUD operation for city, services, category, sub-category, gender tables.

Is it good to have one class for each table in a database? If not then please explain how to avoid this situation? Can I use enum or ArrayList instead of class for data storage?

  • 3
    It's pretty typical in a CRUD system. One class maps to a single table, and you can use an ORM to reduce the boilerplate required to manage this system. However, if your system ends up containing a lot of business logic, you'll want to isolate your domain model from the other layers, and at this point, you may end up with a different setup. – Vincent Savard Mar 29 '18 at 13:03
  • @VincentSavard As much as I know ORM is referred as an anti-pattern. How to deal with its consequences. – prasam mehta Mar 29 '18 at 14:37
  • 3
    It all depends on the context. Using an ORM becomes an issue if you're tainting your domain layer with persistence-related stuff. In a CRUD system, you tend to move away from a layered architecture, because it just adds drawbacks (having to change every layer for every new field you want to persist) without the benefits (isolating the business logic, which you don't need since you have no business logic). – Vincent Savard Mar 29 '18 at 15:11
  • @VincentSavard is there any other way or design pattern except ORM for class design. Can I use enum or ArrayList instead of classes for data storage and repository for CRUD operations? – prasam mehta Mar 29 '18 at 15:52
  • 2
    You might be surprised to discover that using the term "anti-pattern" is itself often considered to be an anti-pattern. Not uncommon to find the term used in place of an actual explanation. In any event, figure out what your app needs to do without worrying about persistence. If you find that, for example, gender just needs to be an enum instead of a class then make it an enum. After your domain model meets your application requirements then figure out the best way to persist. In many cases you will find that one class per table works well. But maybe not. – Cerad Mar 30 '18 at 19:23
3

Put them in their own class (city, services, category, sub-category, gender). Why wouldn't you? Is there a concern that you'll have too many classes that interact with the data storage?

If you want to expand on any of these entities, there would be no reason to change the: customer, agent or admin classes. That doesn't mean a customer can't be associated with many cities in some sort of list/array, but when it comes to managing the cities themselves, why bother the customer code? If you associate a city with a country, parish or province, try not to mess with anything else.

A few months down the road, either you or a new/additional developer may need to modify how the category or sub-categories work, so wouldn't it be pretty simple to start with those classes?

If it wasn't for the design of your database, how would you handle it? Many proponents of OOP, suggest holding off on database/storage decisions until you get the business logic and requirements established.

  • Thanks. But I found that each class for each table is an anti-pattern. Will you clarify on this? Is each class for each table ORM or different? – prasam mehta Mar 29 '18 at 17:41
  • 2
    @prasammehta - It is an anti-pattern to assume each class should have its data written to disk in only one table. – JeffO Apr 4 '18 at 23:17
  • 3
    @prasammehta it seems to me that you are conflating "one class per table" with the Active Record design pattern wherein the model class is responsible for persisting itself (e.g., $customer->save()) which is often criticized due to violating SRP and introducing very tight coupling to the persistence mechanism which often presents difficulties with writing tests for your business objects. You should write your business logic first and figure out persistence later. – John Hall Apr 20 '18 at 18:19
  • We have one class per table and have many, many different entity classes - generally for each table in the database. It's worked very well for a few years. – John Hunt Jun 28 '18 at 13:03
1

Yes, its normally good to have a one to one mapping between classes and tables.

The type of objects you mention are regarded as 'entity objects' in that they represent a 'real' thing, many of which exist, each with differing, but not necessarily different, data.

eg you have many customers in your database and when you want to work with one in code you instantiate a customer object, populate its data from the database and pass it around, call its methods etc.

You can have other types of object which don't follow this rule. For example you might have a MailSenderService with methods like MailSenderService.SendMailToCity(City city)

There's no point have a MailSenderService table, its just the one object with some logic used to send mail in it.

  • Thanks for the answer. But what about city, services, category, sub-category, gender which don't have extra behaviour except for CRUD operations. These tables are just byproducts of data normalization in RDBMS. These tables store data which are used as reference data in other tables. ex. city_id in agent and customer tables. Can I use repositories for CRUD operation and array list for data storage? – prasam mehta Mar 29 '18 at 14:34
  • all of them, I was just using customer as an example – Ewan Mar 29 '18 at 18:48
1

Think about it from the different perspective and recall that there is no silver bullet design.

What are you trying to achieve by your design? Do you want to have your data completely consistent or optimized for performance?

I have tables for admin, agent, customer and tables for data storage like city, services, category, sub-category, gender.

Admin, Agent and Customer sounds like entities in your domain. You will implement some business logic around them, so it makes sense to define appropriate classes. Usually data for each of such classes is contained inside single table in DB (could not be the case for derived entities).

City could be seen differently. Does city have some properties, like references to services or category (exactly this direction of relationship) or like country name? If I try to remove city from DB, should I remove all customers associated with city or at least prevent removal of city? If the answers for these questions is "Yes", then city has some properties, thus it is some entity in your business domain and it should be defined as class. If the answer is "No" and you know that city in your domain is just name of city, then you don't have to define city as class.

From programming perspective, would you like to work with something like $customer->getCity()->getName() (city defined as entity) or $customer->getCity() (city defined as string)? In the first case, you will always have JOIN at some point, either during fetching of $customer from DB (eager strategy) or during call to getCity() (lazy strategy). In the second case, city will be inlined in same table as customer, thus you will have better performance for bulk operations (like fetching 10K customers with your ORM).

Ok, city is pretty complicated entity to discuss without knowledge of your problem domain, but e.g. gender is definitely doesn't worth defining as class. How often are you going to change gender in your system? Do you even really need CRUD for it or is getting list of gender enough? From my development experience, we had gender as enum for 3 years without making any change to list of genders. It is pretty safe bet that you can define it as enum.

Concrete mechanism of connecting such enum as Gender to property depends on your framework of choice. E.g. in Doctrine you could use https://github.com/fre5h/DoctrineEnumBundle/ to implement abstract enums for property. Concrete values of choices for enum could be fetched from database during cache warmup or app initialization, for example.

Remember, the more interconnected entities you have, the more performance problems you will have in future (because of JOINs performed during every query). In the end, design can evolve, and performing data migrations is not that hard if you have suitably designed database on every step of application life (at least you have primary keys and foreign keys that reflect your domain). The best way to start designing you app/database is:

  1. Understand problem domain (what entities are there, what data flows you have).
  2. Build ERD of your business domain (good starter book on the topic could be "Learning MySQL" by Hugh Williams, Seyed Tahaghoghi).
  3. Create first version of database schema and evolve it over time accordingly to upcoming business requirements.
  4. Add app-database connection code to fit your database design (usually database lives longer than code).

Another good book for reading is "Refactoring Databases: Evolutionary Database Design" by Scott W. Ambler, Pramodkumar J. Sadalage.

TL;DR Don't try to fit design accordingly to tools that you have, instead create design that is appropriate for your problem domain and pick tools that will help to implement it.

Hope this provides some insight.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.