Uncle Bob’s Clean Architecture – Composed Entities Explained

androidarchitectural-patternsArchitectureclean code

I'm building an Android application, and trying to follow the Clean Architecture pattern.

I am a little confused on what my entities should look like regarding some of my use cases.

Example

I have a list of channels, and each channel have programs.
I want to display a list of the current program for each channel, and when an element is clicked, I display a channel page with the channel detailed info and the current program info.

Entities

I can see here that I should have a Channel and a Program entity. But should Channel have a field List<Program> programs (as there are mutiple programs during the day)? And another Program currentProgram?
Or should Channel be separated

Use case

Should they return entities, or some dto object?
Currently, my use cases return entities, but are mapped to some dto objects in the presenters.

TL;DR

Which of the proposition below is the way to go?

Pseudo-Code propositions

Case A

Entities

Channel
{
  id()
  name()
  logo()
}

Program
{
  id()
  name()
  thumbnail()
  start_date()
  end_date()
}

Use Cases
List<Channel> GetChannelsUseCase()
Program GetCurrentProgramForChannel(channelId)

Presenter

fetchChannels()
{
    // Builds a List<CurrentProgramViewModel> based on
    // GetChannelsUseCase composed with GetCurrentProgramForChannel for each channel
}

Case B

Entities

Channel
{
  id()
  name()
  logo()
  programs()
}

Program
{
  id()
  name()
  thumbnail()
  start_date()
  end_date()
}

Use Cases
List<Channel> GetChannelsUseCase()

Presenter

fetchChannels()
{
    // Builds a List<CurrentProgramViewModel> based on
    // GetChannelsUseCase and filtering the programs()
    // to extract the 'current' program
}

Case C

Entities

Channel
{
  id()
  name()
  logo()
}

Program
{
  id()
  name()
  thumbnail()
  start_date()
  end_date()
}

Repository
List<Channel> GetChannelsUseCase()
Program GetCurrentProgramForChannel(channelId)

Use Cases
List<ProgramDto> GetCurrentProgramUseCase()

{
    // The Use Case requests the repository to get the entities
    // and builds a ProgramDto object
}

Presenter

fetchChannels()
{
    // Maps a List<CurrentProgramViewModel> based on the
    // List<ProgramDto> returned by GetCurrentProgramUseCase
}

ps: I'll ask about the datasource and repository later / in another topic if necessary

Best Answer

In my experience, a Program isn't permanently tied to a Channel. In fact, a Program can appear on several Channels sometimes even at the same time!

I think you're missing a Listing entity which takes care of associating Programs with a specific time. This means that your Programs should no longer track their start and end times anymore but they probably should track their duration. You might benefit from a Schedule as well to link a Listing with a Channel.

Pseudocode:

Channel
{
  id,
  name,
  logo,
}

Program
{
  id,
  name,
  thumbnail,
  duration,
}

Schedule
{
  channelId,
  date,
  listings = Collection<Listing>
}

Listing
{
  program,
  startTime,
  endTime = () => startTime + program.duration,
}

You would then have a service that allows you to query Schedules base on the channel and date.