Vibemail - extensions for vibe's Mail class to send multi-part emails with attachments
Adam D. Ruppe via Digitalmars-d-announce
digitalmars-d-announce at puremagic.com
Tue Sep 29 09:22:41 PDT 2015
On Tuesday, 29 September 2015 at 14:57:13 UTC, Sebastiaan Koppe
wrote:
> Good. But why put everything in one package?
dub forces me to do it that way. It isn't my preference, but
reorganizing all my files and creating twenty or thirty different
github repos to house them is unacceptable.
The unit of encapsulation in D is the module. If a module does
two wildly different and independent things, you would break it
up. Similarly, and I think this is often neglected, if two
modules are intertwined and one cannot work without the other,
they are really one unit and should be merged.
The merged module will present a cleaner interface and be easier
to maintain since it can handle its own private implementation
without worry of exposing internals for its friend module nor
having something change independently of it.
(I wish D would fix that bug where public and private symbols can
conflict though. So annoying and breaks this beautiful
encapsulation. You might notice simpledisplay.d has a function
named toInternal for example. I'd like to name it to, but then it
would break code that uses std.conv.to, despite that internal
function being private! Ugh!)
That forms the basis of my general policy: make modules that
stand alone and do a task as completely as necessary. I only
split them up when there's a technical requirement and the split
lowers overall complexity.
And, of course, when possible, I like to make those dependencies
optional; they aren't required unless you actually use those
specific features.
Modules in D do a pretty good job at this. They can contain most
their own metadata, too: write ddoc inline, you can grep it for
version options (and since D doesn't allow versions to cross
module boundaries, it is as simple as a grep) and import
dependencies, and you can even have some control over the linker
with stuff like pragma(lib), showing system dependencies.
Modules also have a one-to-one correspondence to files, making
them a natural thing to download, move around, etc. Other
programs know how to handle files so you can version them and
such too.
D's modules work! Why does dub reject this model?
> A guy on npmjs.com goes the other extreme and he actually has a
> package
> (https://github.com/sindresorhus/negative-zero/blob/master/index.js) that consists of 1 line of code.
Disgusting. Think of all the overhead involved in that package,
not just for the author, but now for everybody who use it... and
everyone who uses something that uses it, and so on and so forth
- right down to the end user!
There needs to be a balance struck between "don't repeat
yourself" and avoiding dependencies.
It is generally considered a bad idea to do the whole system
together at once. (though Docker and VMWare appliances and such
do actually try to do that and have found some success in the
market) Making changes to that means a lot of extra work that is
easy to do wrong. (The duplication itself btw isn't a big problem
to me, computers are good at doing the same thing over and over
again; it is an easily automated problem, at least until
something goes wrong.)
In code, we factor common functionality into functions that can
be used from multiple places instead of copy/pasting the bodies
everywhere.
It is similarly a bad idea to have a deep web of external
dependencies. This also makes maintenance harder - where is the
problem? Where do you make the change? How long will it take to
get upstreamed? Do you understand what is going on anymore; will
changing that dependency break some unrelated project somewhere
else?
In code, we try to write our functions such that they do not use
global variables. We like pure functions whenever we can. We like
to use const or immutable to limit the scope of confusing
changes. We like to use private to limit the function's interface.
Negative zero should be a constant (and probably a private one at
that, that'd be a bizarre implementation detail to expose to an
API user). Here, it is instead a public global mutable function
pointer.
> In the description you say "or better yet, ditch dub and do
> things the simple, reliable way of dmd *.d" How is that more
> reliable?
It works the same way every time you do it and exposes all the
options dmd has without needing wrapper json options which may or
may not actually be there, or documented, or keep working the
same way next time you try.
> I copy/pasted your arsd/dom.d code in a couple of projects. But
> none of them will receive updates unless I do 'm manually.
That means you don't have to put up with me randomly breaking
your code! You don't have to wait for me to publish a bug fix.
You aren't locked in to the way I did things and are free to
customize it as you wish.
It is very easy to update it too, even if you do customize it
(git will handle the conflicts, if any) - you can always do a git
pull from me, then test and push back up to your copy (or, not
even bother with the push and just keep the development
dependencies private or ask your users to retrieve it
themselves... it is just a file download, very easy to do).
> However, the idea of having a package-manager is a good idea.
> If only to serve as documentation on the libs you package
> depends on.
dscanner --imports *.d | sort | uniq
Always up-to-date!
Though, dscanner and dub.json both fail to get across all the
nuance possible with the D module system. For example, running
that on dom.d yields:
arsd.characterencodings
arsd.database
arsd.jsvar
Yet, dom.d is also standalone!
characterencodings is only needed if you call one of the
character conversion functions; it is a lazy local import inside
a template.
database is the same, it is only used if you actually call the
fillForm function. (Which is the only reason I permit that btw,
dom and database should NOT depend on one another and I might
just copy/paste that function out someday).
jsvar is only used with a rare -version switch that I never
finished anyway. I should probably just delete those lines.
But, how do you express the half-dependency of characterencodings
in a dub.json dependencies list? Perhaps a configuration could do
it.... or the character converting functions could be pulled out
into a third package on which you depend to get them.... what a
pain compared to just "don't call this function and you never
need it but if you want it it is right there"!
Here's how I documented it in dom.d:
/**
BTW: this file optionally depends on
arsd.characterencodings, to help it correctly read files from the
internet. You should be able to get characterencodings.d from the
same place you got this file.
If you want it to stand alone, just always use the
`parseUtf8` function
*/
That explains it better than dub.json has the capability to.
I'm not completely against the idea of a package manager or even
against dub itself. I just see very little value add from it and
quite a bit of complication and associated questions about it on
the support forums.
More information about the Digitalmars-d-announce
mailing list