There has been some discussion about the pros and cons of CLI-backends for GUI-applications.
I am studying computer science and one of my interests is component technology (although I am really not an expert in it), and there are a few points that came to my mind which I would like to share:
Case 1: CLI-backends for GUI-progs:
The CLI-app is reused for the GUI-app, by itself a good thing. I suppose that many apps are written as CLI-apps first - the tradition is an older one - and then, the people that care about usability and user-friendliness for non-programmers use this CLI-app as a basis for a GUI-frontend. I assume that in many cases, the CLI-app is developed independently of the GUI-frontend, so the good point is that of modularity (frontend and backend that can be developed independently) and information-hiding (the frontend programmer does not have to care about the implementation details of the backend and vice versa). In fact, we already have characteristics of a component approach (in a wider sense) here.
A drawback is that since the interface between the front- and backend is only the CLI, a change in the usage (command line options etc) of the backend or a change in its semantics or just a bug in any of the programs can easily lead to runtime errors and - really bad!!! - also to ones that are not immediately apparent. The textual, untyped representation of the command line arguments and the untyped info that is returned by the backend are more error prone and errors are harder to find (esp. if there is no rigogous protocol for the information flow between front- and backend and no detailed analysis of the data coming back from the backend).
Case 2: A separate component/library and, written in the same language, a CLI- and a GUI-frontend, respectively, that both use the component:
Let us say a library, say, in C++ (as we commonly use them in BeOS), is what we call our component (maybe there exist a much preciser idea about components in BeOS - here I simply lack expertise). Now, generally said, the gain is that the level of integration of the front- and backends is higher. This means:
- the interface between frontend and backend is typed, meaning that, say, each operation that the app should carry out corrsponds to a method in the API of the component. The type-checker of the programming language makes sure that arguments are of the correct type and also that the return value is handled in a type-correct manner. This rules out some potential errors at compile-time.
- as people told me (I have not really experienced it myself) it is easier to debug source-code that is written in one language, as oposed to several parts in different languages. Also, when you are debugging a single program (as it is when using a library) as opposed to several distinct ones (written in whatever language) debugging is, as I assume, easier because you can trace the threads really into each and every method that is used (directly or indirectly), in contrast to having a boundary between distinct programs that makes it more difficult to comprehend the overall control flow.
- the parts of the implementation that, on the one hand, convert parameters into the textual, untyped CLI-format and the parts that parses it and write it back into typed data structures is not necessarily needed when using such a component directly. This should reduce parts of the implementation (therefore potential errors and some runtime and space overhead), the work that they would need and also tricky dependencies: whenever the CLI-interface changes, a change in the frontend is necessary.
- within a single language (or, as you can say, within a single framework of components) certain aspects of a program's implementation can be handled homogeneously, one of them error-handling. A component can, for example, make good use of exceptions and alike, opposed to textual error messages that need to be parsed or integer error codes (that can only convey a limited amount of info). This makes error-handling easier and more transparent and again, saves implementation parts for parsing error messages or so.
A well-designed component framework usually also standardizes and, ideally, also automates compatibility tests (i.e. tests, if components can work together or if some need to be updated) and .. dream :-) ... possibly also the update part (e.g. if a component is obsolete, the new one is automagically downloaded and installed from the internet...).
Enough of that... if there is anything I want to say it is that, with a well-desgined concept for components, programming can be really fun!!!
I hope there was some interesting point.