0

I have thought of this for a while and I want to know what you think about this. This is more of a way to structure the code that might not be 100% object oriented and that is not the purpose. I would like to divide the code into Data, UseCases and HelperMethods

  • Data should be more clean (or "anemic", if you will) objects
  • UseCases (or business flow) would map to a specific use case
  • HelperMethods is for pure function that helps the UseCase look cleaner, but is not generic, the logic is mostly used in the usecase. This could have been private static in the UseCase-code, but then you cant use it fluent syntax and you cant unit test them

Example

Data

Customer
{
   public string Name{get;set;}
   ...
}

UseCase

GiveCustomerDiscount
{
    // Read data from db with repo, about customer, previous orders, "isFridayBlack", and so on
    // Process data for customer with help from helper methods that takes data as input and 
    //    what kind of discount as output
    // Update Customer with repo
}

HelperMethod

  // Takes a customer and data and calculates a discount
  //  "Exposes" Extension methods and public static methods
 

So question: Is this good coding style? Will it bite me, as code base increases? Can I get some more information about this approach or similar?

7
  • 5
    For small to medium sized applications, this will be sufficient. But the larger your program will get, the more structure it will require. There are whole books written about this topic (like "Domain Driven Design" by Eric Evans), and it is also a very opinionated topic, IMHO too opinionated for the Q&A format of this site.
    – Doc Brown
    Commented Oct 25, 2022 at 12:29
  • I familiar with DDD and since its so popular its hard discussing against it. One problem I have against it, is the domain object that gets large and multi purposed since they have to handle every context, and then comes the division into BC, which is too much of a moving target. BUT this thread was not to discuss DDD, since there are millions of articles and threads about it. It was to discuss this approach and similar ones
    – Cowborg
    Commented Oct 25, 2022 at 12:53
  • 1
    I think the simple answer to this not to worry about what problems the code might face in the future, because that depends on assumptions about things that might happen, not things which are certain. Code is supposed to change as its requirements change yet trying to pre-empt change is futile. The best you can do is code for requirements you're certain about "today", keep things simple and invest a lot more effort in automated behavioural testing (tests which test behaviour, not code structure) so that it's much easier for future developers to rewrite the code later. Commented Oct 25, 2022 at 13:06
  • Ok, that answer says absolutely nothing, I understand why this question got closed down.
    – Cowborg
    Commented Oct 25, 2022 at 13:16
  • Let me reiterate my point with different words to make it clearer: I think there is nothing wrong in starting a small program with only few layers and an anemic data model, as shown in the question. But when your program starts to grow, you will find several occasions to refactor (for example, methods which can serve multiple use-cases might be moved into your data objects). It is not the decision you make today on your code structure which will bite back on you, but the lack of adapting it constantly when your program grows.
    – Doc Brown
    Commented Oct 25, 2022 at 14:16

2 Answers 2

2

Will it bite me as code base increases?

Things that may bite you:

Customer
{
   public string Name{get;set;}
   ...
}

Public setter indicates shared mutable state. Could be problematic for readability, debugging, or in a concurrent environment. Prefer immutable where possible.

HelperMethods is a poor name for a class or package. I need names that tell me what does and doesn't belong inside. Resist the temptation to leave your pure functions languishing under meaningless names. Good names organize code. As your functions grow in number step back and look at them together and think about better ways to organize them.

A fluent syntax doesn't require static. Neither do pure functions. Static means static. You can choose to use static for this but static isn't giving you purity or fluency. You have to do that yourself.

Consider this example: =

Nutrition secretFormula(Nutrition nutrition) {
    return nutrition
        .Builder(240, 8)
        .calories(100)
        .sodium(35)
        .carbohydrate(27)
        .build()
    ;
}

Because this code takes a reference to Nutrition rather than reach out to it statically it doesn't actually know what implementation of Nutrition it's talking to. That means this code doesn't need to be touched if you need to change how Nutrition works. Sure the new version of Nutrition has to be backwards compatible with this code, but it's engine is free to do with this whatever it likes.

0

First, I would like to clear up terminologies involved.

What you are proposing is called procedural programming. I.e. there are data structures which are essentially global, usually any part of the application can get their hands on any data, and there are procedures (use-cases and helpers) that act on that data in whatever way they want.

This is in contrast to object-orientation, which co-locates data and any logic that acts upon it. Data is not available at all outside of objects, and what "you can do" is severely limited, close to actual valid business cases. It also enables abstraction, since you now do not deal with raw data in every procedure.

Functional programming is even further away than object-orientation to what you propose. FP limits what you can do even further. Not only does it also co-locate data and function, it also forbids you from causing side-effects and forces you to use the type-system even more rigorously to restrict what "you can do" even further. FP people often say: if it compiles it works.

Will it bite me, as code base increases?

Yes, almost certainly. You forgo any chances that things that change together will be together, you make using abstractions really hard and failure prone, and you allow any part of the application to do basically anything it wants.

2
  • I gave this answer a +1 for the first part about OO, but when you talk about FP, I guess you have a language like Haskell in mind, not Lisp or Scheme (or Javascript, which allows functional programming as well), so it sounds like you are somewhat overgeneralizing.
    – Doc Brown
    Commented Oct 27, 2022 at 10:44
  • @DocBrown Fair enough. My bias for statically typed languages got the best of me. Commented Oct 27, 2022 at 11:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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