[Angular] Semantic difference between Subject and Observable when using $ suffix.
#181
Replies: 5 comments 3 replies
-
|
Somehow |
Beta Was this translation helpful? Give feedback.
-
|
The way we envision this rule and how we use it at Infinum is as follows:
This naming convention works hand-in-hand with The idea is that you never expose subjects publicly, you only expose them after converting to observable using some operators via pipe or asObservable(). This is how we want to name and use Observables: class SomeComponent {
private _isLoading$ = new BehaviourSubject(false); // for internal use for "state management"
public isLoading$ = this._isLoading$.pipe(debounceTime(250)); // for use in template
// to be called from some methods, for example during data fetching
private updateLoadingState(state) {
this._isLoading$.next(state)
}
}Same logic applies to services as well, for example: class AuthService {
private _user$ = new BehaviorSubject<User | null>(null);
public user$ = this._user$.asObservable();
public isLoggedIn$ = this.user$.pipe(map(Boolean)); // Maybe a bit unnecessary, you could always check if user$ is null. Could be useful in some cases so it's also nice to expose it like this
public login() {
this.http.post(...).pipe(tap((u) => this._user$.next(u)))
}
}To sum up, we use this naming convention and the rule about no exposed subjects to ensure that the public interface of component/service/whatever only exposes the base observable. This makes it easier to keep track of who can change value of the observable and to debug the flow. The only "ugly" part is that you need a separate name for private member and here we use |
Beta Was this translation helpful? Give feedback.
-
|
I agree with @fvoska on this one. I would honestly add @Injectable()
export class SidebarService {
private readonly isOpenSubject$ = new BehaviorSubject<boolean>(false);
isOpen$ = this.isOpenSubject$.asObservable();
private readonly isExpandedSubject$ = new BehaviorSubject<boolean>(false);
isExpanded$ = this.isExpandedSubject$.asObservable();
open(): void {
this.isOpenSubject$.next(true);
}
close(): void {
this.isOpenSubject$.next(false);
}
expand(): void {
this.isExpandedSubject$.next(true);
}
collapse(): void {
this.isExpandedSubject$.next(false);
}
} |
Beta Was this translation helpful? Give feedback.
-
|
I have opened a task to expand the reasoning of the mentioned Handbook chapter with conclusions from this discussion. |
Beta Was this translation helpful? Give feedback.
-
|
Handbook chapter has been updated with a bit more reasoning: |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
At PDC, we've recently discussed this topic and come up with different points of view. As I noticed this section in the handbook, to avoid discussing in different places, I wanted to share why I advocate for suffixing subjects with
Sub(orSubject) instead of both suffixing with$.I'd like to show you some examples of where I had issues in the past and what others say about it. Also, I want to be open-minded, even though it might sound offensive.
Angular documentation says this:
Here they say "observable values", "the most recent value from an observable", not using it in the context of subjects when we are able to push new values to it (IMO, that's the intent).
$is here to indicate that you can subscribe to it (to be a consumer), not that you can push a new value to it (to be a producer).However, let's see the opposite arguments from a blog post q/a, where they say:
IMO this is semantically wrong. How
Subjectis implicitly anObservable, it shouldn't indicate that it should be used as an observable directly. That's why we haveasObservable()method on aSubjectto limit the usage just to act as a consumer, not also as a producer. Additionally, they didn't post any more valid arguments about it.I found a tweet thread that talks about it.
I don't like
$$suffix just because it makes the code less readable. For example, it reminds me of naming variables likevar,var1,var11,var111, etc. When you'll try to find some variable with the same name, but different (and similar) suffixes, you will end up with a list of variables with a bunch of$characters.There are some additional tweets where people state their opinions, I can comment on them, but it would be too verbose.
I found that I'm not the only one who has this distinction between subjects and observables. Moreover, I found a specific rule that people use to have a consistent subject suffix (that isn't also
$).Practical example
Let's say we have a sidebar that we want to open/close and expand/collapse. A simple service would look like:
This way we have a clear separation of concerns on who is a consumer and a producer. In the case of more complex services with more subjects and observables, it's easier to find the correct one, e.g.:

I'd like to hear your opinions about that statements on this topic. Would it be useful to give you more concrete examples in the code, and screenshots from the IDE? Just let me know.
Beta Was this translation helpful? Give feedback.
All reactions