-
Notifications
You must be signed in to change notification settings - Fork 761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Builder pattern needed? #6
Comments
One use case I've come across (I'm going to try and dig up a really good blog post about this as well), is for when creating mock data in unit tests. I used to do this very much like your above example. e.g. let createUser;
beforeEach(() => {
createUser = () => {
return {
username: 'bob.smith',
email: '[email protected]',
accountType: ACCOUNT_TYPES.DEVELOPER
};
};
}));
// some spec
it('should do something', () => {
const user = createUser();
}); This is all well and good, but what if we don't always want to test against a "developer" user. Well, we could do something like you suggested and pass in an object to override the parameters, or use individual parameters (e.g. This is fine, but if you often find yourself having to modify the default/generic object in order to obtain a useful object to test against, you can end up with lots of: const user = createUser({
accountType: ACCOUNT_TYPES.ADMIN,
username: 'some.user'
});
// ...
const user = createUser({
accountType: ACCOUNT_TYPES.ADMIN,
username: 'some.user'
});
// ...etc... That seems fine in isolation, but if each of those definitions is really saying "create me an admin user", then that would be better abstracted to a In a simple example like this, it's probably more overhead that it's worth to do anything more complicated than that. If, such as in a real, complicated application, you're needing to create users in a lot of different places (read: a lot of different tests), the above can quickly get repetitive and you can end up with lots of these types of functions littered through the test suite. In such a situation, having a generalised "userBuilder" can help reduce duplication through the tests. Much of this can be applicable to non-test code, too, but I'm specifically focussing on that as it's what I found most useful. Apologies for the slight incoherence, trying to type out this quickly during the downtime of waiting for something to compile... A really good blog post on this is: http://davedevelopment.co.uk/2015/01/28/test-data-builders.html The examples in that blog post are all PHP, but it's just as relevant here. Especially if you want to work with immutable data (though not a prerequisite to this being useful). TL;DR: For a very small or very simple use cases, it introduces overhead that almost certainly isn't worth it. But the same can be said of most abstractions. (One of?) the benefits comes with reducing complexity and repetitiveness in larger and more complicated use cases. |
Thanks for the quick response! I am kinda struggling to see where a builder would be easier for testing. so instead of: const user = createUser({
accountType: ACCOUNT_TYPES.ADMIN,
username: 'some.user'
}); you would need to do something like: const user = User(User.Builder('some.user').withAccountType(ACCOUNT_TYPES.ADMIN)) So I do not see the benefit of that in testing. So yes, I am still struggling to see 'why' :) Btw small addition to your test code to make it more flexible: let createUser;
beforeEach(() => {
createUser = options => {
const defaultUser = {
username: 'bob.smith',
email: '[email protected]',
accountType: ACCOUNT_TYPES.DEVELOPER
}
return Object.assign({}, defaultUser, options);
};
}));
// some spec
it('now you can do stuff like this:', () => {
// default user
const user = createUser();
// different email
const otherUser = createUser({email: 'another email'})
}); |
I would never use a class in the first place when a simple object literal and simple functions can do the job. hence I do not need to create anything with the |
@msqaddura , in javascript you have the choice to do OOP or functional. And I think you are missing the point. I was trying to find an answer to the following question:
I am not trying to attack any patterns here, I just do not think it belongs in every language. And since TypeScript is merely a superset of javascript, it is still javascript. And as per definition of the builder pattern, the problem it is trying to solve is not present in javascript. |
man I believe you are completely out of the context between Prototyping(apparently your style), Object Oriented(apparently not your style), Functional(everyone's style that doesnt really matter)... what am saying is just that for you and the way you look at javascript (over a typescript code) you do not need any pattern it wont help you anyway... unless you are hardcore Object Oriented with javascript/typescript then you can use a pattern but for you it is absolutely no point to bother about a pattern. just because there is a pattern it doesnt really mean that we have to use it everywhere... it can only make things worse if we are forcing it into something that is not meant for it. |
https://github.com/joelpalmer/Typescript--Builder-Pattern without a builder it would be we can add destructing pattern over here for scrambled values where order doesnt matter so yes you can fiddle it down to literal objects but once change in superior constructor will have to be done to all constructors super() call... but with builder you would just need to change the method in the superior class... again you can find a way to simplify so it is always like this... you can always find your way out |
@msqaddura you lost me at 'superior constructor'.
Never would I fall in the trap of extending, so never would I have the issue you just described. And your example is again an example of how a Java person would write node. Just take a look at the 'request' module and see how it is done generally in node: https://github.com/request/request // You would do:
request.get({
host: 'localhost',
port: 9999,
path: 'mypaeh'
}, callback)
// not
new Get("http","myPath","localHost",9999) The only reason why you are finding these issues is because you are not coming up with common nodejs/javascript examples. You find the problems by using javascript as if it was java. |
typescript adds types to javascript, it doesn't mean you have to forget about javascript essence the same question can be done in a javascript page where described a builder pattern, or typescript, because the issue is the same, and the |
Typescript is a superset of javascript. Which means plain javascript is valid typescript. The But let's make it very clear, adding typescript does not mean this language becomes Java and it does not mean you should treat it in the same way. By adding typescript for it's The builder pattern does not solve any problems that exist in javascript or typescript for that matter. |
@msqaddura really... all I want to do is open a discussion where we could all learn from, yet you fail to address anything I mentioned in my comment and post a picture of what AtScript is? I do sense you are being very defensive but fail to come up with real examples or benefits. Even the examples you post in pure javascript clearly indicate that you have no great experience with pure javascript at all. All I was hoping for was a conclusion to my question as to why would I ever use a builder pattern as a javascript developer. There is no need for childish discussion or immature responses. |
Even though the last comment was quite long ago, but I just stumbled across this question. Here are the advantages: Decouples the model of the creation of the model.If your model changes often, you don't need to change as many places. -> Clearer git history on business files, less conflicts due to refactorings. Radability is improvedReadability is especially improved, if you have a huge object with a lot of properties and when you create a lot of elements through the builder: If you take a look at the example, that this dense code would need for each of the method chains at least 1-2 more lines, it is harder too read. ContextA real builder can have multiple sub builders, that depend on the called method. In the example above for the first call you have different possibilities of initialization, which will change some fundamental things. Extensibility / TransformationsThe builder can add very usefull utilities to make the usage of the model a lot easier. A junior dev might not know dependencies between different properties of the model. But they can be encapsulated into a nice api using a builder. They can set multiple properties (also with good default values specially for these calls) They can set pre defined values They can even extend the usages, by allowing transformation of inputs. This way the model does not need to be extended, as long as we can map to the result in some way: I hope this makes it clear, that there are indeed use cases for such a pattern. Btw. jQuery is a huge builder pattern. (https://www.w3schools.com/jquery/jquery_chaining.asp) |
Hi,
Since node/javascript does not have the problem that a builder pattern fixes, since you can just pass along an object literal, why would you want to apply all this overhead?
If we take a look at the example: https://github.com/torokmark/design_patterns_in_typescript/blob/master/builder/builder.ts
We could just use an object literal instead:
This achieves the same thing as the builder pattern. The main difference here is that user.js is a lot smaller than the builder.ts example. (10 lines vs 60+)
Passing along an object literal, which is very common in node, is just as readable as with a builder, but with a lot less overhead or boilerplate.
So my question is: why would you do this?
The text was updated successfully, but these errors were encountered: