Closed ScreamZ closed 3 years ago
Hello Andréas,
Thank you so much for this detailed analysis of feature-u's static typing. You are obviously passionate about technology and I am grateful for your fervent support of feature-u.
I must admit that I am not currently a TypeScript user (and it is not on my radar at the moment). I have used "tightly typed" languages in the past, and understand their benefits. I also fully understand that TypeScript has become a very popular tool for a lot of developers.
When it comes to an API design, there are trade-offs between the more rigid "tightly typed" nomenclature, and providing for (shall I say) more pliability through various overloaded constructs. I realize that the latter may be considered an "anti pattern" to many, however I think in the right scenario it has it's merits. Obviously, very good developers are free to disagree.
With a proclivity to "static typing", your suggestions make a lot of sense. For me however, that was not an overriding goal of feature-u.
In reality, there is nothing that you suggest here that wasn't considered in the original design of feature-u's API.
As an example, take the useFassets()
API:
The current useFassets()
API takes on 3 distinct forms. This may be an anti-pattern to some (and problematic in strongly typed definitions), but I actually prefer the way it currently operates.
Per the the useFassets()
API docs:
+ useFassets(): fassets ... the full Fassets object
+ useFassets(fassetsKey): fassetResource | fassetResource[] ... array used when fassetsKey has wildcards
+ useFassets(mapFassetsToPropsStruct): {key1: fassetResource, key2: fassetResource, ...}
The second case is identical to the get()
method of the Fassets
object ...
The third case allows you to retrieve multiple keys with one invocation.
The docs provide more detail with examples.
In my mind, this provides a very concise way to extract multiple aspects in a single invocation.
A withKeys
parameter directive (as suggested in #33) would force it to be applicable to all fassets in a given invocation (when using the "3rd form" above).
Providing two useFassets()
APIs (singular/plural) to distinguish wildcard support, would require them to error out when the invoker did not conform to the wildcard requirements. In my mind it is better for a single API to interpret whether wildcards are provided, and adjust appropriately.
If you think about it, the input to createFeature()
(i.e. it's named parameters) more accurately delineates a series of dynamic run-time directives, rather than a rigid data structure.
This is compounded by the fact that Feature aspects can be extended (at run-time) through feature-u plugins.
Currently this is handled through run-time validation, which does not easily translate to a rigid type construct.
In my mind, any attempt to model this in a more rigid typing construct, may represent a direct "conflict of interest", and could introduce even more complexity than the alternative.
You're suggestion that TypeScript support may improve feature-u's acceptance, is most likely true. However, when it is all said and done, I believe it would be negligible (on this one count).
I have spent countless hours in promoting feature-u: through articles, social media, presentations, extensive documentation, etc. (to the point where I am a bit worn out).
In my mind, the crux of the "feature-u acceptance" problem is that it is very different from the norm. It is more of an architectural utility dealing with decoupling and code organization and app orchestration.
What I have found (the hard way) is it is very difficult to get traction on a new and unique idea!
The irony is that feature-u has a lot in common with Micro Frontends (from a feature decoupling perspective), which has been making gains in popularity. As you know, truly isolated Feature-Driven Development (FDD) is something that is incredibly powerful! But unfortunately, it is hard to get the word out :-(
This is all compounded by the fact that my time is very limited in regard to feature-u enhancements.
It is possible, that at a different time, you would have had an easier time in convincing me to move in this direction.
Ultimately, this enhancement would require a number of breaking changes to shore up feature-u's static typing. This would mean multiple releases to "ease in" the new approach (with deprecations etc).
I am currently extremely busy on other projects, which is taking all my time at the moment.
Even with your assistance, this would inevitably require time that I do not have ... for support, and documentation, and deployment, etc.
As just one example, the deployment process (in it's current form) is very manual and lengthy (obviously a separate discussion). It involves too many manual steps (like maintaining versioned docs etc). While this is an obvious opportunity for automation, it would require my time (i.e. the "catch 22").
Regrettably, I am not in a position to commit time to this enhancement, even if I were convinced it were the right direction.
At this time, I am not willing to promote a formal TypeScript mapping directly in the feature-u project, for a variety of reasons (including support issues, limited time constraints, and overall direction).
If you feel this PR's TypeScript definition has value (in it's current form - without changes to feature-u's API), might I suggest that you promote it through a separate project. By tagging the project with the feature-u keyword, it would be easily found by feature-u TypeScript users. In this way I would be "out of the loop" regarding support etc.
I do not want to discourage you from your use of feature-u.
I appreciate the time you have spent on this, and feel it will be valuable to other TypeScript users (even though somewhat limited with the current API).
Hi,
I open a proposal, that I started working on. @KevinAst, it's a followup to the mail I sent to you :-) I'll be really pleased to exchange with you on all of this :-)
More and more I get interested in Domain Driven Design, and naturally, I turned back to feature-u which is a great tool, I think yet kind of under rated, bringing simpler examples and typescript support could help to improve notoriety of such jewel
Why use Typescript
Typescript is more and more widely used within JavaScript projects as it brings reliability using static type checking before runtime. It's a Microsoft tool, high backed and kind of essential for all real project with high stakes. This is a great tool, that prevents typo issues and safeguards against various errors.
The integration of typings within
feature-u
With that in mind here is a simple work in progress implementation of a definition file that brings types to the library. This needs a bit of thinking yet, especially with interfaces injections and generic types that's why I'm open to suggestions.
Some issues and enhancement to consider in order to play well with static typing
Currently, as given this pull request makes no breaking change, it's just an enhancement of what already exists. But we might consider some changes to make the API cleaner and less "magic" in some parts.
@withKeys change
As described in #33, this is kind of "hacky" as it relies on runtime inspection and regexp. This is cool, it works but I think we could get better security by playing with a different signature or split into multiple functions. This is also more performant as regular expressions are not know to be the fastest thing in the world.
Generic type support with feature collaboration
How can we provide an interface for the contract with
use
,define
anddefineUse
? As requiring module es6 file is kind of bad practice, but we still want type checks.⚠️ I mean this is the core issue and feature of typescript here, I need to type the fasset in and out but what can I accept in terms of coupling in order to make this work?
Imagine I have one React component that I provide as a fasset, here is it's interface contract:
How can I use
const ScreenShell = useFasset<any>("ScreenShell")
with some kind of generic type matching this contract ?Here I used a component, but I have the same exact issue if I
define
a graphQL query that others module can use (how do I type the return type ?) or a redux selector (How do I type the selector value ?)Aspect augmentation
Currently FeatureArguments (looks like the same object than Feature itself) is defined as follow:
If we add a new Aspect there is two possibilities:
createFeature
function that allows to inject new properties