I'm doing a simple project that represents a CI Pipeline in a low scale. So I'm trying to model "the best way possible" to practice DDD.

Basically I have the following information:

  • PipelineSettings (A configuration file that shows me the steps the pipeline will have)
  • PipelineSteps (A collection of classes implementing an interface that will execute part of the job)

I started with a class called RunPipeline that work as a command/application service.

RunPipeline has two repositories IPipelineSettingsRepository & IPipelineStepsRepository and I was thinking in creating a Pipeline object that will be a domain object inside this command.

So the code would be something like this:

public class RunPipeline {

    private readonly IPipelineSettingsRepository pipelineSettingsRepository;
    private readonly IPipelineJobsRepository pipelineJobsRepository;

    public RunPipeline(
        IPipelineSettingsRepository pipelineSettingsRepository,
        IPipelineJobsRepository pipelineJobsRepository) {

        this.pipelineSettingsRepository = pipelineSettingsRepository;
        this.pipelineJobsRepository = pipelineJobsRepository;

    public async Task Run(BuildOrder buildOrder) {
        var pipelineSettings = pipelineSettingsRepository.GetAll();
        var pipelineSteps = pipelineJobsRepository.GetAll();
        var pipeline = new Pipeline(pipelineSettings, pipelineSteps);

        await pipeline.Run(buildOrder);


But I need to perform a validation that is that every pipeline setting is backed by a pipeline step, because if not I will try to execute a step that will not be able to be executed and it will fail.

So I was thinking in a few options:

  • Have a Pipeline factory that has a validation service injected, verifies and then returns the Pipeline object
  • Have a domain service that creates a Steps object containing inside a collection of Steps containing a PipelineSetting(config) for that Step and a PipelineStep(execution) and inject that to the Pipeline object.
  • To inject or create internally a validator in the Pipeline object.
  • To validate this in the RunPipeline command (I don't think this would be good cause I could create a pipeline with an incorrect state)
  • To create a Validate method in Pipeline object and pass a IPipelineValidation implementation and pass it from RunPipeline command.

I'm thinking that Pipeline is the core of the app, and should execute concrete behaviours since is what it's solving a specific problem for this business.

What do you think?

  • 2
    It's worth noting that DDD is a design technique, not a coding technique. If you want to do it "correctly," my observation is that you appear to be working backwards from the code into the business domain, instead of establishing a business domain and ubiquitous language and seeing what code naturally arises from that. The book "Learning Domain-Driven Design" by Vlad Khononov doesn't even talk about code until page 63. Commented Jul 14, 2022 at 13:12
  • I started by trying to find the relevant words when talking and searching for CI pipelines. Understanding that a Pipeline run Steps and handle and make choices based on a configuration. I was just having the doubt of injecting to the pipeline a service to validate that what I want to run is valid, so everytime I create a pipeline its in a valid state, or if I should do it in a PipelineFactory. Again, the example is very simple, but just wanted to try to design it correctly Commented Jul 14, 2022 at 16:37
  • 1
    Alright. Doesn't seem to have much to do with DDD, though. Commented Jul 14, 2022 at 16:39
  • 1
    Curiously, pipelines are just the opposite of DDD. While DDD put emphasis on conciliating data structures and behavior, Pipelines are pure behavior decoupled from the data they manage
    – Laiv
    Commented Dec 11, 2022 at 10:12

1 Answer 1


[..] Pipeline is the core of the app, and should execute concrete behaviours [..]

In object-orientation every object is supposed to execute behavior. Combined with DDD, that behavior should be specifically business-related behavior.

In this context, I think there are too many abstractions here, some only tangentially relevant to the domain. Specifically I think PipelineSettings is a technical thing. What behavior does it have in your model? PipelineStep is good, although sounds a bit technical, I would perhaps call it Task (as some CI systems do). I suspect Pipeline could be a Task, if it has the same exposed behavior (i.e. run it).

The RunPipeline sounds and looks like a procedure. It gets data from somewhere and does something with someone else's data. This should belong to a proper object.

Overall I suspect (and I don't know your specifics of course) this could be achieved with less number of abstractions (i.e. simpler), and less procedurally (i.e. more maintainably).

  • First thanks for the answer :) * I agree it is not a complicated domain and could be simpler, but I just wanted to see if this type of small project can help me to solve some doubts. * I agree PipelineStep could be call Task or Job (like CI systems have Pipeline->Stages>Jobs) Pipeline is the one that will iterate each step and will use pipelineStepSettings to determinate what to do in case something happens. (ex: if the step can fail it will continue, if not will throw an error) Also will be in charge of filling a file to show the state of the pipeline Commented Jul 14, 2022 at 9:52

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.