Injecting services best practises

Hi, i have a question about services injecting. Is it ok to inject one service into another, or is it better to avoid it as much as possible? For example, i have RecordsPage, and in its constructor RecordsService is injected, which saves records, get records and more things like that… Then i have SettingsPage with SettingService injected,which holds settings. SettingService is also injected into RecordsService, because the settings influence, how the record service works with records. But SettingService is also injected into Records page, cause the page view depends on some options from the settings. Is it ok, that SettingService is injected into RecordService and RecordPage, despite the fact that RecordService is also injected into RecordPage? It feels a little redundant to me. Whats the proper way to do this? And can this redundant injections have impact on app performance?

I do this all the time in my apps. As long as your services are global, then they will be instantiated once and shared. Just watch out for any circular references, but I’m sure you’re aware of that already.

I think as a dev you know when what you’re doing feels right or wrong. Trust yourself and how you like to organise your code so that it makes sense to you.

The Angular Style Guide recommends giving a service a single reponsibility. It also recommends that no file be longer than 300 lines of code. I’ve split a database provider into a top provider that pages can access, and helper providers that are injected into the top provider.

Re: your structure of a page speaking to a provider and also to a provider of the provider, that’s potentially dangerous. If the page only READS, then you’re probably fine, because no data changes state. But if the page WRITES data to the second provider that the first provider didn’t expect, you might generate a long-term hard-to-detect error. So I’d avoid it structurally, because otherwise you’re forcing extra discipline on yourself and all future coders.

(One common READ-ONLY example is checking of auth state. Many providers and pages need to know if a user is logged in. But only the auth service can/should change whether the user s logged in.)

The way I resolve this is with Subjects. If something exposed by a provider may ever be changed during the app’s run time, I never expose it as raw data, either as a public property or via a getter function. I only expose it as a Subject, which ensures that any consumers must subscribe() to it, and will therefore be updated as necessary, no matter who is generating the write op.

I have services that offer both subscriptions and getter functions. No high-minded reason for this. What happened was that I started out all-getters, and then as I learned some rxjs, I started using BehaviorSubject instead. But it sounds as though you’re imposing a “no getter functions ever” rule. I might be on board with this, frankly. But why is “only subscriptions” safer than “getter is a public way to return the value of a private variable?”

Specific example: user ID. I have both a private variable that stores that, and a BehaviorSubject that emits it as a stream. Then my database service uses the getter to generate a string that is a database reference to, e.g. user profile data. And several places in the app listen to the stream and change behavior if a new value is emitted. Are you saying there’s a potential issue with this type of structure?

Because it makes consumers aware that the value may change at any time, and provides a simple way to keep up-to-date.

A rule I try to follow is “only have one way of accessing any particular information”, because if you have more than one, inevitably it opens the door to bugs involving what happens when they don’t agree.

So I’m cool with getters for stuff that either (a) never changes during app run, like something loaded at startup from an asset resource, or (b) is clearly documented saying “cache this at your own risk; it’s only intended for immediate use”. Anything else I prefer to expose as a Subject.

1 Like

Can u post some simple example? So u have for example private variable records in your service, and Subject recordSubject, which pages subscribe to? And when the variable records changes u post updated variable with Subject.next()?

And one more question, what about app performance? Doesnt using subscriptions have a negative impact on that?

So u suggest not injecting service into service, and if one service needs some data from another, its better passing it as parameter from the Page?

private _example: BehaviorSubject<number> = new BehaviorSubject<number>(5);

// update example
this._example.next(6);

// method exposed in provider for pages to use
exampleStream(): Observable<number> {
  return this._example.asObservable();
}

// in a page
exampleLocalCopy: number;
this.exampleProvider.exampleStream().subscribe(ex => this.exampleLocalCopy = ex);
2 Likes

Not sure where you got that impression from. I have absolutely no problem with services injecting other services.