[yast-devel] High level notes about new storage API
Hi,
let me do some high level user oriented review of new storage API.
At first I think it is good that design decisions are documented, which
is nice. Also having goals and requirements is documented which is fine
to understand some decisions. What I miss is all requirements, I think
it would be nice to write down all features old libstorage have and
maybe discuss if it still make sense in new libstorage.
Now first note. I do not see in decisions why C++ is used as language
for this library. I think it would be nice to document it why it is
needed as currently from document I see that planned users are machinery
( which use ruby ), Yast (ruby) and kiwi (perl). Is there any
performance reasons, availability of bindings, libraries or any other
reason to use it? As libstorage basically use CLI of other programs, so
question is why not use more high level language.
Now lets move to examples. From my user POV there is some confusing API
calls and parameters. For example lets use find1.cc as example which I
comment (I can do this for all examples).
// creating some global storage is fine
Devicegraph* devicegraph = new Devicegraph();
// this looks strange for me
// 1) how disk can be created? I expect disk is detected or proposed
// 2) why saying that disk have "/dev/sda" what if I am on qemu which
// have "/dev/vda"?
Disk* sda = Disk::create(devicegraph, "/dev/sda");
// this looks fine for me, creating partition table on disk
PartitionTable* gpt = sda->create_partition_table(PtType::GPT);
// here I do not get why I need to pass "/dev/sda1" ? Let me say it
// this way, if I have generic code that generate partition for passed
// partition table how I can know if it is hda, sda or vda? and why
// I need to know number of partition? cannot it by default create next
// available one and pass number as optional parameter?
gpt->create_partition("/dev/sda1", PRIMARY);
Partition* sda2 = gpt->create_partition("/dev/sda2", PRIMARY);
// here I create top level container, looks fine for me
LvmVg* system = LvmVg::create(devicegraph, "/dev/system");
// this is very confusing, why I need devicegraph here? Why exposing it
// to user? From doc I know that both sda2 and system have reference to
// it so why it need to be passed?
// And also why it need User::create? Why it is not simple
// `system.add(sda2)` call which is more intuitive for me?
User::create(devicegraph, sda2, system);
// in general it looks fine for me, just is there reason to pass
// whole device name? who not having thing like
// `system->create_lvm_lv("root")`
LvmLv* system_root = system->create_lvm_lv("/dev/system/root");
// creation of filesystem, intuitive and easy
Filesystem* filesystem = system_root->create_filesystem(EXT4);
// quite confusing, what is adding mountpoint to filesystem?
// filesystem do not know about mount points, I expect something like
// `devicegraph.mountpoint.add("/", filesystem)`
filesystem->add_mountpoint("/");
// some debug output, nothing to comment, not sure if it is needed to
// be public methods
cout << "num_devices: " << devicegraph->num_devices()<< endl;
cout << "num_holders: " << devicegraph->num_holders() << endl;
cout << endl;
// validation of storage, easy and intuitive... does it raise exception
// if failed?
devicegraph->check();
// printing of object, fine and intuitive C++ code
cout << devicegraph << endl;
// printing graphiz image, easy and intuitive API call
devicegraph->write_graphviz("test1.gv");
// looking for all filesystems that are mounted as root mountpoint
// is confusing. why it do not return single filesystem?
for (const Filesystem* filesystem : Filesystem::find_by_mountpoint(devicegraph, "/")) {
// I am not sure if I can imagine what is ancestor of filesystem?
// I hope there is better name for it
// second note is boolean parameter, it is really hard to read it and
// hard to remember what such parameter mean. see e.g
//http://programmers.stackexchange.com/questions/147977/is-it-wrong-to-use-a-b...
for (const Device* device : filesystem->get_ancestors(false)) {
// this a bit break polymophysm, but it is explained in design
// document, so fine for me
if (dynamic_cast
On Wed, Oct 21, 2015 at 04:36:19PM +0200, Josef Reidinger wrote:
Now lets move to examples. From my user POV there is some confusing API calls and parameters. For example lets use find1.cc as example which I comment (I can do this for all examples).
// creating some global storage is fine Devicegraph* devicegraph = new Devicegraph();
// this looks strange for me // 1) how disk can be created? I expect disk is detected or proposed
The probing code must also be able to create the object representing a disk. With the Image/Kiwi mode you can create a disk which is backed by a loop device.
// 2) why saying that disk have "/dev/sda" what if I am on qemu which // have "/dev/vda"? Disk* sda = Disk::create(devicegraph, "/dev/sda");
The probing code uses the parameter. Currently you are basically looking at functions to manipulate the device graph.
// this looks fine for me, creating partition table on disk PartitionTable* gpt = sda->create_partition_table(PtType::GPT);
// here I do not get why I need to pass "/dev/sda1" ? Let me say it // this way, if I have generic code that generate partition for passed // partition table how I can know if it is hda, sda or vda? and why // I need to know number of partition? cannot it by default create next // available one and pass number as optional parameter? gpt->create_partition("/dev/sda1", PRIMARY); Partition* sda2 = gpt->create_partition("/dev/sda2", PRIMARY);
Use PartitionTable.get_unused_partition_slots() to get the name, type and possible region. The interface will change to allow also passing the region.
// here I create top level container, looks fine for me LvmVg* system = LvmVg::create(devicegraph, "/dev/system");
// this is very confusing, why I need devicegraph here? Why exposing it // to user? From doc I know that both sda2 and system have reference to // it so why it need to be passed? // And also why it need User::create? Why it is not simple // `system.add(sda2)` call which is more intuitive for me? User::create(devicegraph, sda2, system);
User::create is a low-level function to manipulate the device graph. Functions like system.add_physcial_volume will be added.
// in general it looks fine for me, just is there reason to pass // whole device name? who not having thing like // `system->create_lvm_lv("root")` LvmLv* system_root = system->create_lvm_lv("/dev/system/root");
This will change. For LVM there are only mostly empty classes currently.
// creation of filesystem, intuitive and easy Filesystem* filesystem = system_root->create_filesystem(EXT4); // quite confusing, what is adding mountpoint to filesystem? // filesystem do not know about mount points, I expect something like // `devicegraph.mountpoint.add("/", filesystem)` filesystem->add_mountpoint("/");
Only filesystems have mount-points so to me it looks natural to handle them there. Alternatively we could add objects for mount-points in the graph. BTW: E.g. ext4 knows its last mount point (try dumpe2fs).
// some debug output, nothing to comment, not sure if it is needed to // be public methods cout << "num_devices: " << devicegraph->num_devices()<< endl; cout << "num_holders: " << devicegraph->num_holders() << endl; cout << endl;
// validation of storage, easy and intuitive... does it raise exception // if failed? devicegraph->check();
My idea are exceptions for fatal errors where the graph is so broken that it cannot be used anymore, e.g. duplicate storage id. Such an error indicates a libstorage internal problem. For other things that the user can repair I think a list of issues should be returned, e.g. the user created a raid with level 6 but only added two drives. Here the user just has to add more drives, change the level or remove the raid.
// printing of object, fine and intuitive C++ code cout << devicegraph << endl; // printing graphiz image, easy and intuitive API call devicegraph->write_graphviz("test1.gv");
// looking for all filesystems that are mounted as root mountpoint // is confusing. why it do not return single filesystem? for (const Filesystem* filesystem : Filesystem::find_by_mountpoint(devicegraph, "/")) {
You can mount a device at several mount-points. With btrfs this is even standard, see https://github.com/openSUSE/libstorage/blob/master/doc/status-current-code.m....
// I am not sure if I can imagine what is ancestor of filesystem? // I hope there is better name for it // second note is boolean parameter, it is really hard to read it and // hard to remember what such parameter mean. see e.g //http://programmers.stackexchange.com/questions/147977/is-it-wrong-to-use-a-b... for (const Device* device : filesystem->get_ancestors(false)) {
get_ancestors is the base function in Device and thus is not specially named for filesystems. Otherwise the name is standard, e.g. https://en.wikipedia.org/wiki/Tree_%28data_structure%29. The bool parameter was already mentioned several times here and will be replaced by an enum.
// this a bit break polymophysm, but it is explained in design // document, so fine for me if (dynamic_cast
(device)) cout << "mount point \"/\" somehow uses a logical volume" << endl; } } delete devicegraph;
So in general, I think that we should now more focus on API and its usability as it is hard to change it in future. When having good API, some cleaning or refactoring of implementation later is easier ( current code in new libstorage is short and easy, but I worry in future with more features, we need to be prepared to clean it also).
We are focused on the API at the moment.
Regards,
Arvin
--
Arvin Schnell,
On Wed, 21 Oct 2015 17:30:50 +0200
Arvin Schnell
On Wed, Oct 21, 2015 at 04:36:19PM +0200, Josef Reidinger wrote:
Now lets move to examples. From my user POV there is some confusing API calls and parameters. For example lets use find1.cc as example which I comment (I can do this for all examples).
// creating some global storage is fine Devicegraph* devicegraph = new Devicegraph();
// this looks strange for me // 1) how disk can be created? I expect disk is detected or proposed
The probing code must also be able to create the object representing a disk. With the Image/Kiwi mode you can create a disk which is backed by a loop device.
What about using name "Disk::propose" for creating such disk? I think it is just confusion caused by naming, as said I create in library disk a bit confusing.
// 2) why saying that disk have "/dev/sda" what if I am on qemu which // have "/dev/vda"? Disk* sda = Disk::create(devicegraph, "/dev/sda");
The probing code uses the parameter. Currently you are basically looking at functions to manipulate the device graph.
ok, if using propose, then it make sense to me as it propose disk with given name, which is fine.
// this looks fine for me, creating partition table on disk PartitionTable* gpt = sda->create_partition_table(PtType::GPT);
// here I do not get why I need to pass "/dev/sda1" ? Let me say it // this way, if I have generic code that generate partition for passed // partition table how I can know if it is hda, sda or vda? and why // I need to know number of partition? cannot it by default create next // available one and pass number as optional parameter? gpt->create_partition("/dev/sda1", PRIMARY); Partition* sda2 = gpt->create_partition("/dev/sda2", PRIMARY);
Use PartitionTable.get_unused_partition_slots() to get the name, type and possible region. The interface will change to allow also passing the region.
Great, so it already have such functionality. I just expect that create partition can have reasonable defaults and use this method inside for default parameters. So you have gpt->create_partition(); and it inside get available ones with above mentioned get_unused_partition_slots. Of course it should support passing manual names, region and so on. This way API will be simple for common usage and powerfull if needed.
// here I create top level container, looks fine for me LvmVg* system = LvmVg::create(devicegraph, "/dev/system");
// this is very confusing, why I need devicegraph here? Why exposing it // to user? From doc I know that both sda2 and system have reference to // it so why it need to be passed? // And also why it need User::create? Why it is not simple // `system.add(sda2)` call which is more intuitive for me? User::create(devicegraph, sda2, system);
User::create is a low-level function to manipulate the device graph. Functions like system.add_physcial_volume will be added.
Great.
// in general it looks fine for me, just is there reason to pass // whole device name? who not having thing like // `system->create_lvm_lv("root")` LvmLv* system_root = system->create_lvm_lv("/dev/system/root");
This will change. For LVM there are only mostly empty classes currently.
// creation of filesystem, intuitive and easy Filesystem* filesystem = system_root->create_filesystem(EXT4); // quite confusing, what is adding mountpoint to filesystem? // filesystem do not know about mount points, I expect something like // `devicegraph.mountpoint.add("/", filesystem)` filesystem->add_mountpoint("/");
Only filesystems have mount-points so to me it looks natural to handle them there. Alternatively we could add objects for mount-points in the graph. BTW: E.g. ext4 knows its last mount point (try dumpe2fs).
// some debug output, nothing to comment, not sure if it is needed to // be public methods cout << "num_devices: " << devicegraph->num_devices()<< endl; cout << "num_holders: " << devicegraph->num_holders() << endl; cout << endl;
// validation of storage, easy and intuitive... does it raise exception // if failed? devicegraph->check();
My idea are exceptions for fatal errors where the graph is so broken that it cannot be used anymore, e.g. duplicate storage id. Such an error indicates a libstorage internal problem. For other things that the user can repair I think a list of issues should be returned, e.g. the user created a raid with level 6 but only added two drives. Here the user just has to add more drives, change the level or remove the raid.
// printing of object, fine and intuitive C++ code cout << devicegraph << endl; // printing graphiz image, easy and intuitive API call devicegraph->write_graphviz("test1.gv");
// looking for all filesystems that are mounted as root mountpoint // is confusing. why it do not return single filesystem? for (const Filesystem* filesystem : Filesystem::find_by_mountpoint(devicegraph, "/")) {
You can mount a device at several mount-points. With btrfs this is even standard, see https://github.com/openSUSE/libstorage/blob/master/doc/status-current-code.m....
Yes, I know that device can have multiple mountpoints, but here is logic reverse. It said that one mount point can have multiple devices ( or filesystem like used here ) which is at least for common usage without overlapper layered mount points not possible. So on "/" is one btrfs...of course you can get same btrfs also for /boot/grub2 etc.
// I am not sure if I can imagine what is ancestor of filesystem? // I hope there is better name for it // second note is boolean parameter, it is really hard to read it and // hard to remember what such parameter mean. see e.g //http://programmers.stackexchange.com/questions/147977/is-it-wrong-to-use-a-b... for (const Device* device : filesystem->get_ancestors(false)) {
get_ancestors is the base function in Device and thus is not specially named for filesystems. Otherwise the name is standard, e.g. https://en.wikipedia.org/wiki/Tree_%28data_structure%29.
Yes, name make sense if you know that it is tree structure, but it is inside POV, as user I try to read what api said to me and it said "get me ancestors for given filesystem" which is a bit confusing and require to know that filesystem is device and devices is stored in tree structure and then you understand what code want you to say. So more specialized call like filesystem->get_device() or get_partition ( even if I know that disk can be partitionless) can be more friendly for reader of code.
The bool parameter was already mentioned several times here and will be replaced by an enum.
good
// this a bit break polymophysm, but it is explained in design // document, so fine for me if (dynamic_cast
(device)) cout << "mount point \"/\" somehow uses a logical volume" << endl; } } delete devicegraph;
So in general, I think that we should now more focus on API and its usability as it is hard to change it in future. When having good API, some cleaning or refactoring of implementation later is easier ( current code in new libstorage is short and easy, but I worry in future with more features, we need to be prepared to clean it also).
We are focused on the API at the moment.
Good, that brings me two ideas. 1) I can do such API review for all examples in example directory if it make sense for you 2) maybe it make sense to write down expected use cases for library usage and write example code for such use cases which can be discussed. Josef
Regards, Arvin
-- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
Am 22.10.2015 um 08:59 schrieb Josef Reidinger:
The probing code must also be able to create the object
representing a disk. With the Image/Kiwi mode you can create a disk which is backed by a loop device.
What about using name "Disk::propose" for creating such disk?
Definitely not "propose". We are using that term in a completely
different meaning since more than ten years.
But I agree we will need a mechanism to make clear that a (usually)
physical device like a disk is created by
- hardware probing
- creating virtual devices (Kiwi etc.)
- creating pseudo devices for testing (i.e., mocking)
I am in the process of collecting and writing down my ideas and thoughts
for that. Stay tuned.
CU
--
Stefan Hundhammer
On Thu, Oct 22, 2015 at 08:59:52AM +0200, Josef Reidinger wrote:
You can mount a device at several mount-points. With btrfs this is even standard, see https://github.com/openSUSE/libstorage/blob/master/doc/status-current-code.m....
Yes, I know that device can have multiple mountpoints, but here is logic reverse. It said that one mount point can have multiple devices ( or filesystem like used here ) which is at least for common usage without overlapper layered mount points not possible.
It is possible, although likely stupid: cat /proc/mounts [...] /dev/mapper/system-abuild /mnt ext4 rw,relatime,commit=600 0 0 /dev/mapper/system-giant--xfs /mnt xfs rw,relatime,attr2,inode64,noquota 0 0 So the API must be able to handle the situation. Or do you prefer an exception during probing?
get_ancestors is the base function in Device and thus is not specially named for filesystems. Otherwise the name is standard, e.g. https://en.wikipedia.org/wiki/Tree_%28data_structure%29.
Yes, name make sense if you know that it is tree structure, but it is inside POV, as user I try to read what api said to me and it said "get me ancestors for given filesystem" which is a bit confusing and require to know that filesystem is device and devices is stored in tree structure and then you understand what code want you to say. So more specialized call like filesystem->get_device() or get_partition ( even if I know that disk can be partitionless) can be more friendly for reader of code.
The example in find1.cc does something special: It checks whether the filesystem *somehow* is located on a LVM logical volume. This is still the case even if first on the logical volume is an encryption device and then the filesystem. If you just want to know which block devices the filesystem is directly located on use filesystem->get_blkdevices().
1) I can do such API review for all examples in example directory if it make sense for you
Not yet or in other words the examples are not use-cases.
Regards,
Arvin
--
Arvin Schnell,
On Thu, 22 Oct 2015 17:04:35 +0200
Arvin Schnell
On Thu, Oct 22, 2015 at 08:59:52AM +0200, Josef Reidinger wrote:
You can mount a device at several mount-points. With btrfs this is even standard, see https://github.com/openSUSE/libstorage/blob/master/doc/status-current-code.m....
Yes, I know that device can have multiple mountpoints, but here is logic reverse. It said that one mount point can have multiple devices ( or filesystem like used here ) which is at least for common usage without overlapper layered mount points not possible.
It is possible, although likely stupid:
cat /proc/mounts [...] /dev/mapper/system-abuild /mnt ext4 rw,relatime,commit=600 0 0 /dev/mapper/system-giant--xfs /mnt xfs rw,relatime,attr2,inode64,noquota 0 0
So the API must be able to handle the situation. Or do you prefer an exception during probing?
I think it is two different things. 1) probing should handle such situation 2) common query should return only later as first one is overlaped, of course there can be specialized call to manipulate mount points knowing also about overlap or knowing that removing first mount point return to game previous one I do not look at API from probe POV, but from library user POV, so I query what device content is visible under /mnt, which answer is only second one.
get_ancestors is the base function in Device and thus is not specially named for filesystems. Otherwise the name is standard, e.g. https://en.wikipedia.org/wiki/Tree_%28data_structure%29.
Yes, name make sense if you know that it is tree structure, but it is inside POV, as user I try to read what api said to me and it said "get me ancestors for given filesystem" which is a bit confusing and require to know that filesystem is device and devices is stored in tree structure and then you understand what code want you to say. So more specialized call like filesystem->get_device() or get_partition ( even if I know that disk can be partitionless) can be more friendly for reader of code.
The example in find1.cc does something special: It checks whether the filesystem *somehow* is located on a LVM logical volume. This is still the case even if first on the logical volume is an encryption device and then the filesystem.
If you just want to know which block devices the filesystem is directly located on use filesystem->get_blkdevices().
1) I can do such API review for all examples in example directory if it make sense for you
Not yet or in other words the examples are not use-cases.
OK, fine for me. So I am looking forward for use case oriented examples as it is the most important for me, as it is something we should show potential users and it should be attractive API to convince them to use it. Josef
Regards, Arvin
-- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
Dne 23.10.2015 v 10:24 Josef Reidinger napsal(a): [...]
2) common query should return only later as first one is overlaped, of course there can be specialized call to manipulate mount points knowing also about overlap or knowing that removing first mount point return to game previous one
It seems that Libzypp has something similar for repository URLs. Each repository can have assigned multiple URLs and you can get all URLs via baseUrls() methods [1] or a single URL via url() method [2] (it's the first one from the list). The most common use case is just a simple url(), the list of URLs is usually not needed. [1] https://github.com/openSUSE/libzypp/blob/master/zypp/RepoInfo.h#L140 [2] https://github.com/openSUSE/libzypp/blob/master/zypp/RepoInfo.h#L127 -- Ladislav Slezák Appliance department / YaST Developer Lihovarská 1060/12 190 00 Prague 9 / Czech Republic tel: +420 284 028 960 lslezak@suse.com SUSE -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
On Fri, Oct 23, 2015 at 10:24:05AM +0200, Josef Reidinger wrote:
On Thu, 22 Oct 2015 17:04:35 +0200 Arvin Schnell
wrote: On Thu, Oct 22, 2015 at 08:59:52AM +0200, Josef Reidinger wrote:
You can mount a device at several mount-points. With btrfs this is even standard, see https://github.com/openSUSE/libstorage/blob/master/doc/status-current-code.m....
Yes, I know that device can have multiple mountpoints, but here is logic reverse. It said that one mount point can have multiple devices ( or filesystem like used here ) which is at least for common usage without overlapper layered mount points not possible.
It is possible, although likely stupid:
cat /proc/mounts [...] /dev/mapper/system-abuild /mnt ext4 rw,relatime,commit=600 0 0 /dev/mapper/system-giant--xfs /mnt xfs rw,relatime,attr2,inode64,noquota 0 0
So the API must be able to handle the situation. Or do you prefer an exception during probing?
I think it is two different things.
1) probing should handle such situation
2) common query should return only later as first one is overlaped, of course there can be specialized call to manipulate mount points knowing also about overlap or knowing that removing first mount point return to game previous one
Currently the ordering does not define that information. I had a different use-case in mind: If you want to delete /dev/mapper/system-abuild you first have to unmount it. Since umount(2) only supports unmounting the topmost filesystem you also have to unmount /dev/mapper/system-giant--xfs. You have to present that to the user. So you need all filesystems mounted at that place.
I do not look at API from probe POV, but from library user POV, so I query what device content is visible under /mnt, which answer is only second one.
In general you have to look at the API from both sides. After all
the API has to represent the system and not some theoretic
concept.
Regards,
Arvin
--
Arvin Schnell,
Am 23.10.2015 um 10:24 schrieb Josef Reidinger:
I think it is two different things.
1) probing should handle such situation
2) common query should return only later as first one is overlaped, of course there can be specialized call to manipulate mount points knowing also about overlap or knowing that removing first mount point return to game previous one
Not sure if the two of you are talking about the same things here. Maybe
this helps to clarify:
In general, it is not a good idea to enforce a consistency check after
each low-level call. There should be such a consistency check, of
course, but when is it triggered, and what consequences does this have?
Use case: The user is in the expert partitioner and wants to change
mount points because he discovered he made a mistake: He really wants
/home on his blazingly fast SSD /dev/sda and /data on the slower
rotating disk /dev/sdb, but he accidentially put /data on /dev/sda3 and
/home on /dev/sdb1. In effect, this is a classic "swap" operation.
So, from a user's point of view, I want to be able to:
- Change the mount point of /dev/sda3 from /data to /home.
So, for the moment, I have a /home mount point on both /dev/sda3
and /dev/sdb1.
- Change the mount point of /dev/sdb1 from /home to /data.
Voila, only one /home mount point left, everything okay.
If we force the consistency check after the first step, it will complain
about the two identical mount points, so we force the user to either
change the mount point of one of the two partitions to nothing
temporarily (maybe causing another error popup if this is checked, too)
or to invent a temporary fake mountpoint. One way or the other, this is
another operation the user has to do, and it's not very intuitive.
This serves to illustrate the point: We need to keep low-level
operations and consistency checks apart. Consistency checks should be
invoked at strategic points - either just before commiting / executing
all the changes, or explicitly triggered from app code when the logical
transaction is done - i.e. when the user tries to exit the expert
partitioner. This would be a good place to do the checks and to display
any warning or error dialogs to the user.
Any time before that and we are limiting the user's workflow, forcing
him into detours and thus distracting him from what he really wants to do.
This affects the real end user as well as any application code using
libstorage.
HTH
--
Stefan Hundhammer
On Wed, Oct 21, 2015 at 04:36:19PM +0200, Josef Reidinger wrote:
Now first note. I do not see in decisions why C++ is used as language for this library. I think it would be nice to document it why it is needed as currently from document I see that planned users are machinery ( which use ruby ), Yast (ruby) and kiwi (perl). Is there any performance reasons, availability of bindings, libraries or any other reason to use it?
Sure, I'll write something to the documentation.
As libstorage basically use CLI of other programs, so question is why not use more high level language.
Why should C++11 not be a "very" (not in the term of
https://en.wikipedia.org/wiki/Very_high-level_programming_language)
high level language? I fear an endless discussion coming.
Regards,
Arvin
--
Arvin Schnell,
Dne 21.10.2015 v 17:52 Arvin Schnell napsal(a):
As libstorage basically use CLI of other programs, so question is why not use more high level language.
Why should C++11 not be a "very" (not in the term of https://en.wikipedia.org/wiki/Very_high-level_programming_language) high level language? I fear an endless discussion coming.
Um, if I would start a complete new library I'd very likely use Ruby (unless another language would fit way better, I'd be willing to sacrifice some features to avoid learning yet another language...) But I do not want to start a flamewar, if libstorage developers are skilled in C++ and want to use it I'm fine with that. (It could be even worse, I know some worse languages than C++ ;-)) My concerns are mainly: - the code should be readable even for people who are not C++ experts or used C++ long time ago and forgot some C++ tricks - the code should be easily testable -- Ladislav Slezák Appliance department / YaST Developer Lihovarská 1060/12 190 00 Prague 9 / Czech Republic tel: +420 284 028 960 lslezak@suse.com SUSE -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
Am 21.10.2015 um 18:53 schrieb Ladislav Slezak:
- the code should be readable even for people who are not C++ experts or used C++ long time ago and forgot some C++ tricks - the code should be easily testable
Definitely yes on both issues. Both are design goals.
CU
--
Stefan Hundhammer
On Wed, 21 Oct 2015 17:52:40 +0200
Arvin Schnell
On Wed, Oct 21, 2015 at 04:36:19PM +0200, Josef Reidinger wrote:
Now first note. I do not see in decisions why C++ is used as language for this library. I think it would be nice to document it why it is needed as currently from document I see that planned users are machinery ( which use ruby ), Yast (ruby) and kiwi (perl). Is there any performance reasons, availability of bindings, libraries or any other reason to use it?
Sure, I'll write something to the documentation.
As libstorage basically use CLI of other programs, so question is why not use more high level language.
Why should C++11 not be a "very" (not in the term of https://en.wikipedia.org/wiki/Very_high-level_programming_language) high level language? I fear an endless discussion coming.
I do not want to start flame and I am fine with such explanation, I just said it should be documented ( and it will as you write above ). During my presentations I often get such question for yast. Why it is ruby and not python, js, go, whatever ( funny that noone mention C++ or perl, probably not enough sexy :). Josef
Regards, Arvin
-- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
Am 22.10.2015 um 08:37 schrieb Josef Reidinger:
I do not want to start flame and I am fine with such explanation, I just said it should be documented ( and it will as you write above ). During my presentations I often get such question for yast. Why it is ruby and not python, js, go, whatever ( funny that noone mention C++ or perl, probably not enough sexy:).
In most cases, this question can be answered simply:
"Because we wrote it and not you. We chose the tool we feel most
comfortable with."
The point is moot. There will always be yet another
$HYPED_PROGRAMMING_LANGUAGE_OF_THE_MONTH. But look at what became of
most of them, how much they are used for professional work of any kind,
how strong the community around them is, how much tool support there is,
how quickly they and their tools become obsolete, and if those tools
ever became even mature and stable enough to justify sustained
development for a non-trivial project.
IMHO anybody who seriously suggests to write anything the size of YaST
in any of Go, JavaScript, Haskell and whatnot either doesn't have any
clue of anything or is not seriously willing to make it work in all its
aspects -- and keep it working for decades.
Just my €0.02
--
Stefan Hundhammer
participants (4)
-
Arvin Schnell
-
Josef Reidinger
-
Ladislav Slezak
-
Stefan Hundhammer