Re: RFC: App::SFDC
by 1nickt (Canon) on Jul 14, 2015 at 13:24 UTC
|
Hi ali0sha,
It's too late now but I would have tried to not create yet another new namespace on CPAN ...
There was already:
- Salesforce
- Net::Salesforce
- DBD::Salesforce
- WebService::Salesforce
- WWW::Salesforce
- WWW::SFDC
(WWW-SFDC-0.30 - 10 Jul 2015 - Alexander Brett)
The last named of which was created by you a few days ago!
I know that CPAN is littered with poorly chosen namespaces, and when you want to contribute a new package, you often have to steer clear of them, and often want to choose a better name anyway. It's hopeless, and getting worse every day, as ironic hipsters post their Dist:Zilla plugin bundles, or even just their CPAN install bundles, as ... CPAN modules (!)
But I dunno, if you were going to put your utility routines under WWW::, couldn't you have worked with the existing WWW::Salesforce, which is apparently well-maintained and -reviewed ... And if the app was going to be under one namespace, I would have tried to put all components under the same space. As I understand it now, your dist is um, distributed between App::SFDC and WWW::SFDC ...
Please don't take this too personally. It's a pet peeve of mine, and you did ask :)
The way forward always starts with a minimal test.
| [reply] [d/l] |
|
|
Hiya,
I completely understand your frustration about namespacing - in fact, I was thinking carefully about this when I created the modules.
To first address App::SFDC - this lives in the App:: namespace because it's a command line application. Those other things are not - I feel pretty safe on this one.
Then to address WWW::SFDC - I feel strongly that this is a separate package from App::SFDC because it provides a usage-agnostic wrapper around the APIs. So basically, I think the crux of your feedback is; why did I choose to write my own wrapper, WWW::SFDC, instead of expanding on one of the existing ones, specifically:
- Salesforce
- WWW::Salesforce (WebService::Salesforce should actually be part of this dist)
(I'm excluding Net::Salesforce and DBD::Salesforce as they are doing fundamentally different things, viz. an OAUTH wrapper and a DBD library respectively)
The main difference between WWW::SFDC and the two existing modules is scope; Salesforce offers several SOAP APIs, including the Partner, Metadata, Tooling and Apex APIs. I need a library which will allow me to easily transition between all of these different APIs to perform intricate operations. However, WWW::Salesforce and Salesforce only wrap around the Partner APIs, and to extend them to work through all of the existing APIs would have meant effectively a ground-up rewrite and be completely backwards-incompatible.
Despite this, I contacted Fred Moyer (the WWW::Salesforce) maintainer in December to see whether we could work together on the project, but he only replied to me once, and I was moving really fast on getting this up and running.
What would you have done differently in this situation? At this extremely early stage, I could, if I got in contact with one of those maintainers and manage to work it out, transition to a different namespace, but I think these are fairly good grounds for going it alone.
| [reply] |
|
|
Sounds like you did everything you could have. As I said, it was mostly a general rant.
The main flaw in CPAN in my opinion is that there is simply no option to move or even delete a namespace once it's created.
I can grok not deleting ever; and it is possible to get control of a zombie and at least edit it to state that it is dead. But not being able to move dists means that as everything expands (CPAN itself, the world that CPAN dists connect to, and the functionality of the dists), the structure can never be reorganized or optimized. For example, by combining working dists, that have claimed a general namespace which they don't fully deliver on, with new dists, like yours, that either complete the functionality or introduce an abstraction level that the old dist should be under. In the case of Salesforce, that can never happen, so your dist, which is more complete and newer, is forced to live alongside others in the hierarchy, and a user just searching for a Perl interface to Salesforce.com is left to sort it all out for himself.
The only thing I think I would suggest is to make sure to put a section in your POD explaining the history of the solutions offered for the problem you are tackling. I rely on such a "History" or "Rationale" or "Why this module" section from the author quite often when trying to choose a CPAN package. The response you posted above would be most of what you needed to say. And it's not any kind of mea culpa, but just a road map for the user who is searching for your code, but just isn't sure about that yet.
The way forward always starts with a minimal test.
| [reply] [d/l] |
|
|
Re: RFC: App::SFDC
by Monk::Thomas (Friar) on Jul 14, 2015 at 20:30 UTC
|
my ($result, $headers) = $self->_call(
'executeAnonymous',
SOAP::Data->name(string => $code),
$options{debug} ? SOAP::Header->name('DebuggingHeader' => \SOAP::Dat
+a->name(
debugLevel => 'DEBUGONLY'
))->uri($self->uri) : (),
);
because it makes it hard to see what's going on. I would prefer it to build the function arguments separately, like:
my @args = (
'executeAnonymous'
SOAP::Data->name(string => $code),
);
if ($options{debug}) {
# this line should also be cleaned up somehow
push @args, SOAP::Header->name('DebuggingHeader' => \SOAP::Data->nam
+e(debugLevel => 'DEBUGONLY'))->uri($self->uri);
}
my ($result, $headers) = $self->_call(@args);
| [reply] [d/l] [select] |
|
|
Do you think it's more that just a stylistic/opinion choice? My feeling is that creating intermediate variables and modifying them is less clear because it requires keeping track of more variables over more statements and lines.
| [reply] |
|
|
It is basically a stylistic choice, but I think it improves the readability of the code a lot. At least to me. I picked this code example because at first glance I simply saw 'stuff', then while looking at it there were 'revelation'-like experiences. Oh! It's a function call! Oh! It's using a ternary operator to build a conditional argument set. Oh! The conditional is just there to help debugging.
I rewrote the code to make these 3 different aspects more visible and make it easier to mentally skip parts that are probably not relevant to spotting bugs, e.g. the debug conditional.
Generally I try to format the code in a way that minimizes the mental effort and the time required to recognize the building blocks. Hopefully this helps to reduce the 'TL;DR'-effect when reading / scanning over it and helps to spot possible bugs more easily. That's also the reason why I try to avoid the ternary operator in complicated statements. Sure it's convenient, but '?' is a lot less visibly distinct then 'if ('. In your case I was even able to drop the 'else' branch, because it didn't have any purpose besides satisfying the syntax.
| [reply] |
|
|