In many cases in C# i can use interface to get loose coupling between components.
for example a component could retrieve an
ITextFileReader reader = dic.Resolve<ITextFileReader();
No matter which implementation is currently bound. For example in test environment i could pass a spy or mock.
In node.js i use
require('./myTextReader.js")
but there is a fix dependency to that specific file.
what is the best practice to get the described behavior f orm above in node.js implemented?
What I don't want to do is to have some facade / wraper with "If...." clauses which may decide who to delegeate the call
Also i want to avoid to have the setup configuration as a part of my production code. the setup code should be outside the domain logic in the Application Composition layer.
So as best thing i would have something like a component registration, and consumer which just use the registration information to get there instance (without knowing anything ábout the registration details )
i found di.js which seems to be the angular.js approach. I could also implement some kind of di by myself. But reinventing the wheel is often a bad decission.
What is the current best practice / state of the art to do this?
Related
Introduction
React is really flexible, it seems that we are not forced to follow a specific architecture when programming interfaces, unlike with other libraries, it is something like coding a plain view. With small web apps, this is cool, but... as soon as your app starts to grow, the speed with which you code will decrease progressively, contrary to if you had defined your architecture from the beginning of the principles.
My Architecture
In my case, I am not using Redux for state management... instead, I am using React Context + React Hooks.
This is my current project structure (serverless app built using firebase):
/app
/components
/Activity
/Authentication
/Profile
/Buttons
/Text
/Inputs
/Giphy
/Messaging
/HOCs
...
/screens
/Activity
/Authentication
/Profile
/Messaging
...
/contexts
/Users
/Content
/Auth
...
/hooks
/auth
/profile
/users
/content
/badges
/i18n
...
/navigation
/Stacks
/Tabs
...
/services
/third-party
/firebase
/api
...
/lib
/theme
/styles
/utils
/functions (backend)
As you can notice, I am using some kind of domain-driven design to structure my project files.
Also, I am separating concerns from screens and components using hooks, and managing complex state (or which need to be synchronized between routes) inside contexts that contains the respective reducers.
This seems to me like some kind of MVC. Where the View is composed by all my React Functional Components, the controller is composed by all my Business and UI hooks, and the data of my Model is contained inside Contexts (or, at least the dynamic data, because of efficient reasons).
As you can see, I have a folder "services" which is just the interface that my business hooks use in order to connect to my server (cloud functions).
Questions
Does this architecture have a name (flux/redux??)? I mean, with the passage of time as a React programmer, mistake after mistake, I have ended up organizing my projects like this, in a "natural" way.
Is it an anti-pattern to split all my components logic with hooks? I mean, all the functional components of my project just contain the event handlers or the JSX to render the UI. I have moved every single block of code to hooks, some of them contain the logic of my business, others simply complex logic related to the graphical interface (animations, ...)
Which advices do you give to me in order to refine my current architecture?
useSelector with React Context? I have implemented some custom hooks that just read and compute derived data from contexts... as I can't use "useSelector", I don't know if this is something typical, because they just consume the necessary contexts (useContext) and then execute some calculations.
Is it Redux really necessary? For a medium-large project, I have handled it well using React Context and with the help of the hooks my code has been quite clean. Do you think that over time, as the project continues to grow, it will be necessary to move to Redux?
Are react hooks the controllers of an application?
Well, not completely sure that this is the right place to put questions like this, but let try to answer, from my point of view, to these points.
Answers
I don't think this specific architecture has a name (like, for example, this one, that has a name https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/). In any case the name would not be "Flux" or "Redux" since these names are more related to how data is treated instead of how folders are structured in the project. I don't think there is some strict rule about folder hierarchy to follow to be fully compliant with Flux or Redux patterns. For sure there are best practices and conventions, but they are not mandatory.
To answer this point, let me share this link https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 about an article posted by Dan Abramov. I am sharing this article because of the last update made (the article is dated 2015, but there is an important update made in 2019). As you can see seems that you are doing it good since you are putting the core logic in hooks. Just a note about this point: you said "functional components" but I think you were referring to "presentation components", this is an important distinction because "functional component" means that your component is based on a function (instead of a class), "presentation component" instead means that the component does not contain business logic. A "presentation component" can be both class-based or functional and a functional component can contain business logic (class-based component are being replaced by functional ones, but this is another story).
Some advice: be coherent with capitalization and casing (you are mixing uppercase and lowercase, dash-case and camelCase, usually I like to name every file or folder in dash-case, but it depends on you); nut sure if HOCs folder should be here; maybe you can put all the utils (lib, theme, styles and utils itself) in a directory called utils where each util is named property;
About context, and this is a controversial topic, just want to share some considerations taken from docs https://reactjs.org/docs/context.html#before-you-use-context and share my opinion on that. The idea behind context is "Context provides a way to pass data through the component tree without having to pass props down manually at every level", as per documentation subtitle. So, basically, it si something created to avoid "property drilling", as exposed here https://medium.com/swlh/avoid-prop-drilling-with-react-context-a00392ee3d8 for example. This is just a personal point of view but, maybe, is better to introduce Redux for global state management instead of using Context API.
Don't be scared to use Redux. Be scared if, while using Redux, you have tons of duplicated lines of code. In this case you should think about how to abstract your actions and reducers (for example with action creators). If you will be able to generalize stuff like "getting a list of items from your backend", you will realize that your code will not just have less lines of code than a repetitive one, but it is even more readable and coherent. For lists, for example, you may have an action like const getListOfNews = list("NEWS_LIST", "/api/news/"); where list is an action creator like const list = (resource, url) => (params = {}) => dispatch => { // your implementation... };, something similar with reducers.
No, they just "let you use state and other React features without writing a class" as said here https://reactjs.org/docs/hooks-intro.html from docs. It is important to avoid trying to adapt a pattern like MVC to something that was created with different ideas, and this is a general advice. Is like if you are coming from Angular and you try to work in the same way in React. Basically you should work with React, or other libraries/frameworks, without trying to transform them from what they are to what you already know.
I'm working on an Angular project at the minute that is designed to very modular - sections of the app can be enabled and disabled for different clients using Webpack. This structure is working nicely for me so far, but one issue I've run into is working out how to handle services that might not always be present.
My current solution is pretty simple - I use $injector.has() to check if the service currently exists, and if so, I use $injector.get() to grab it:
function initialize($injector) {
if ($injector.has("barcode")) {
let barcode = $injector.get("barcode");
// Do stuff with the barcode service
}
}
This seems to work - however, I can't find much information on the use of this pattern and whether or not it has any potential downsides.
So, my questions are:
Are there any caveats to using the injector this way that I should be aware of?
Is there a better/more idiomatic way of doing this?
This is probably the best way to accomplish what you want; however, in doing this, note that you are moving from Dependency Injection (DI) to Service Locator pattern.
The following from the Angular 2 docs is quite relevant (emphasis mine):
We avoid this technique unless we genuinely need it. It encourages a careless grab-bag approach such as we see here. It's difficult to explain, understand, and test. We can't know by inspecting the constructor what this class requires or what it will do. It could acquire services from any ancestor component, not just its own. We're forced to spelunk the implementation to discover what it does.
Framework developers may take this approach when they must acquire services generically and dynamically.
(Aside: It's worth having a read over what's coming for dependency injection in Angular 2 -- Optional dependencies, Factory providers, etc.)
Angular 1's docs on the matter make reference to it running afoul of The Law of Demeter (which is of course more of a guideline than a Law, right?).
In any case, just some additional things to be aware of:
You won't be warned (by having errors thrown) of circular dependencies where this is used; in fact, this is often a technique people use to get around these warnings.
Since you now have a dependency on $injector in addition to what you inject with it, your unit tests will either need to mock $injector, or use something like module('moduleThatIsUsingInjectorExplicitly', function($provide) { $provide.value('barcode', barCodeMock);}.
As mentioned in the quote above, your code will be a little less clear since these 'optional' dependencies are not defined in the usual places.
Plenty of other reading out there on Service Locator pattern, and contrasting it with DI. Interesting enough, but practical implications for us are probably limited, especially as JavaScript's lack of Interface/Abstract and Angular 1's implementation of DI mean there are fewer real points of difference.
For a project I am working on, one of the things I've written is an instantiable service for an Angular UI Bootstrap Calendar control.
You can see the plunker for it in action here.
The code question I have is more of an architectural and best-practices question. Specifically, I think I've written an Angular anti-pattern.
Services - like the calendarSvc - are singletons, yet I am explicitly circumventing this by making the factory return a constructor function.
That being said, there is a concrete business need for 1-n calendars to exist on a single page. This code is an effective refactor of the code needed to manage a single calendar, so it definitely helps the code to be more DRY.
Question: What are some effective alternatives to this instantiable service that still let me specify instances of reusable Calendar objects as needed, but are done without circumventing the Angular way of managing the code?
What you did is not a antipattern, but indeed best practice!
See this style guide page for example: http://github.com/mgechev/angularjs-style-guide#services.
You did not circumvent the Angular way. The idea of the factory is the possibility to return constructor functions. The other alternative to creating services is the service-method of module which would automatically instantiate your service with the new keyword.
Take also a look at this other StackOverflow answer as reference: https://stackoverflow.com/a/20110304/669561
I am new in AngularJS DI, and I am wondering how to do things that I usually do in Ninject. I understand the limitations, so if it is not possible, a workaround will do.
I have to create objects that handle different event types, I usually follow the strategy pattern, and with Ninject in C# I can use multi-injection to inject an array of strategies in the constructor of my strategy broker.
The idea is that I would like to create more "handlers" (strategies) and add them to the AngularJS DI system, without alter common code. I have done this in JS before, by having an object where I can append the new strategies, but I wonder which is the right way of doing it in Angular.
Would be possible somehow in Angular to do something similar?
I'm working within a Javascript + BackboneJS (an MVC framework) + RequireJS framework, but this question is somewhat OO generic.
Let me start by explaining that in Backbone, your Views are a mix of traditional Views and Controllers, and your HTML Templates are the traditional MVC Views
Been racking my head about this for a while and I'm not sure what the right/pragmatic approach should be.
I have a User object that contains user preferences (like unit system, language selection, anything else) that a lot of code depends on.
Some of my Views do most of the work without the use of templates (by using 3rd party libs, like Mapping and Graphing libs), and as such they have a dependency on the User object to take care of unit conversion, for example. I'm currently using RequireJS to manage that dependency without breaking encapsulation too much.
Some of my Views do very little work themselves, and only pass on Model data to my templating engine / templates, which do the work and DO have a dependency on the User object, again, for things like units conversion. The only way to pass this dependency into the template is by injecting it into the Model, and passing the model into the template engine.
My question is, how to best handle such a widely needed dependency?
- Create an App-wide reference/global object that is accessible everywhere? (YUK)
- Use RequireJS managed dependencies, even though it's generally only recommended to use managed dependency loading for class/object definitions rather than concrete objects.
- Or, only ever use dependency injection, and manually pass that dependency into everything that needs it?
From a purely technical point of view, I would argue that commutable globals (globals that may change), especially in javascript, are dangerous and wrong. Especially since javascript is full of parts of code that get executed asynchronously. Consider the following code:
window.loggedinuser = Users.get("Paul");
addSomeStuffToLoggedinUser();
window.loggedinuser = Users.get("Sam");
doSomeOtherStuffToLoggedinUser();
Now if addSomeStuffToLoggedinUser() executes asynchronously somewhere (e.g. it does an ajax call, and then another ajax call when the first one finishes), it may very well be adding stuff to the new loggedinuser ("Sam"), by the time it gets to the second ajax call. Clearly not what you want.
Having said that, I'm even less of a supporter of having some user object that we hand around all the time from function to function, ad infinitum.
Personally, having to choose between these two evils, I would choose a global scope for things that "very rarely change" --- unless perhaps I was building a nuclear powerstation or something. So, I tend to make the logged in user available globally in my app, taking the risk that if somehow for some reason some call runs very late, and I have a situation where one user logs out and directly the other one logs in, something strange may happen. (then again, if a meteor crashes into the datacenter that hosts my app, something strange may happen as well... I'm not protecting against that either). Actually a possible solution would be to reload the whole app as soon as someone logs out.
So, I guess it all depends on your app. One thing that makes it better (and makes you feel like you're still getting some OO karma points) is to hide your data in some namespaced singleton:
var myuser = MyApp.domain.LoggedinDomain.getLoggedinUser();
doSomethingCoolWith(myuser);
in stead of
doSomethingCoolWith(window.loggedinuser);
although it's pretty much the same thing in the end...
I think you already answered your own question, you just want someone else to say it for you : ) Use DI, but you aren't really "manually" passing that dependency into everything since you need to reference it to use it anyways.
Considering the TDD approach, how would you test this? DI is best for a new project, but JS gives you flexible options to deal with concrete global dependencies when testing, ie: context construction. Going way back, Yahoo laid out a module pattern where all modules were loosely coupled and not dependent on each other, but that it was ok to have global context. That global context can make your app construction more pragmatic for things that are constantly reused. Its just that you need to apply that judiciously/sparingly and there need be very strong cases for those things being dynamic.