Home > Net >  Downsides of subjects to asObservable
Downsides of subjects to asObservable

Time:12-15

Hi im really questioning the usage of a "asObserveable()" call on subject.

In my view it creates a big unecassary overhead. The prevention of calls like "next()" or "complete()" are in my view useless.

Can you name me a good reason why you should do this?

Just compare this two

  1. Without
export class TestService {
     public get test$(): Observable<test> {
        return this.test$.asObservable();
     }
    
      public get test2$(): Observable<test> {
        return this.test2$.asObservable();
      }
    
      public get test3$(): Observable<test3> {
        return this.test3$.asObservable();
      }
    
      public get test4$(): Observable<test4> {
        return this.test4$.asObservable();
      }
    
      private readonly _test1$ = new ReplaySubject<test1>(1);
      private readonly _test2$ = new ReplaySubject<test2>(1);
      private readonly _test3$ = new ReplaySubject<test3>(1);
      private readonly _test4$ = new ReplaySubject<test4>(1);
 }

  1. Without
 export class TestService {  
      public readonly test1$ = new ReplaySubject<test1>(1);
      public readonly test2$ = new ReplaySubject<test2>(1);
      public readonly test3$ = new ReplaySubject<test3>(1);
      public readonly test4$ = new ReplaySubject<test4>(1);
}

CodePudding user response:

I can give a good reason. Suppose, you want to emit some event execCompleted$ based on certain action . Here is how it is implememted

export class TestService {
 private readonly execCompleted$ = new Subject<string>();

 public async makeServerCall(userData){
   const resp = await this.http.post('...').toPromise();
   this.execCompleted$.next(resp.data.id);
   return resp;
 }

 public getUpdatedId(){
   this.execCompleted$.asObservable();
 }

}

Now, this service is used by two Components -> Admin and UserInfo.

The Admin component can update some user info by using makeServerCall() and update some user data. This event has to be captured by UserInfoComponent so that it can listen and update the info (once some update has been performed).

By exposing Subject using getUpdatedId() , you are restricting any other component to mistakingly send the next() event on execCompleted$. This Subject will only get triggered when makeServerCall(userData) is called.

This is just a simple example. There are more complex cases but all has the same underlying intention.

To not allow unwanted events to be emitted or cancelled. Only the intended source should so that.

This is a standard practice in programming where you want some restrictions on what can be extended by others and what can't. Kinda like open-closed principal.

CodePudding user response:

Downsides of subject's asObservable

Some boiler-plate code. Not much else.

In my view it creates a big unnecessary overhead.

Have you measured it? Subjects extend Observables, all it does is create a shallow copy. I'd be surprised if you found an app where the difference is bigger than the variance (effectively not measurable).

Upsides of subject's asObservable

A cleaner architecture means it's easier to find bugs and/or easier to stop bugs from being created in the first place.

Encapsulation is one of the fundamentals of a clean architecture. Because encapsulation hides some part of our program from other parts, it makes each part a bit easier to reason about. Therefore it is easier to understand, write, extend, and maintain.

If there is a bug in a well architected system, the surface area is much smaller.

In general, the benefits for these sorts of decisions tend to make themselves known on larger projects with bigger teams. If you're writing a hobby project at home or making a minimal viable product by yourself or a small team, it might makes sense to forgo over-planning in order to make haste. Such a project might need a re-write/overhaul once it grows, but by then the added effort will be worth it.

Alternatives to Subject's asObservable

If you have a static type checker set relatively strictly (TypeScript, Elm, PureScript, ClojureScript, etc), then you can just return the Subject as an Observable without making any changes to the runtime representation of the type.

You get the encapsulation with zero run-time cost.

  • Related