In C++, there isn't a de-facto standard logging tool. In my experience, shops roll their own. This creates a bit of a problem, however, when trying to create reusable software components. If everything in your system depends on the logging component, this makes the software less reusable, basically forcing any downstream projects to take your logging framework along with the components they really want.
IOC (dependency injection) doesn't really help with the problem since your components would need to depend on a logging abstraction. Logging components themselves can add dependencies on file I/O, triggering mechanisms, and other possibly unwanted dependencies.
Does adding a dependency to your proprietary logging framework sacrifice the reusability of the component?
Yes. But dependency injection will help in this case.
You can create an abstract logging base-class and create implementations for the logging-frameworks you want to use. Your components are just dependent on the abstract base-class. And you inject the implementations along with al their dependencies as needed.
Yes, Mendelt is right. We do exactly this in our products. Everything depends on the ILogger abstract interface, but it does not depend on anything else. Typically an executable or a high-level DLL will be the one to construct an actual implemented Logger interface and inject it.
If you are looking to build libraries which wont be recompiled, but want to provide a logging interface then perhaps a good way is to allow the user (of the library) to provide a callback.
On initialising logging with your library, they would need to specify the callback, and then the glue-code is up to them to make it play well with whatever they have.
If you can make the signature of the callback look like a standard function they might always have available to them, it provides them an easy default option if they dont actually have a logger.
Additionally the caller might have instanced components from the library multiple times, and for resource contention or threading issues, want to provide a different logger callback for each one.
Related
I am planning a c++ project using dependency injection via boost di. In my opinion I will need a mechanism for dynamically loading libraries too, to be able to realy benefit of dependency injection.
Therefore I consider using boost dll to use a platform independent shared library mechansim.
For dependency configuration I think about using INI-files via boost property tree.
Do you see any major drawback in this approach?
Or is there another platform independent mechanism/library?
Thanks for your opinions
Andreas
There is a mechanism to decide during runtime what implementation to use. But due to the compile time approach of Boost DI it seems by design not intended to use it with dynamic libraries.
For a pure compile time injection it looks very smart and nice to use. For my problem, it seems not the right solution.
During C++ projects development, I had to find a C++ DI framework.
After some investigation and evaluations and based on our requirements (detailed below), we found out that Hypodermic framework suits our needs.
Our criterions (except the basic one that the framework shall recursively inject instances !!) were:
Non-intrusive (do not require to dirty existing code with 'decorations' macros...) as Google fruit and or other libs require.
Support singleton instance
Support of configurable instantiation (using a lambda)
Support of container\injector composition
Generic Shareable container\injector in order to support modules (static or dynamic). BTW, I agree with
Boost-DI, as answered by Andreas, is not suitable because it is heavily templated and as answered in this question.
Boost-DI does not allow real composition of containers at run-time and even not at compile-time unless you share the header files with the root injector. It violates the 'privacy' of modules (as you need to publish them to be able to inject them).
Hypodermic allows to configure containers and create sub-containers. Container is agnostic to type (not template) therefore it is possible to share it at run-time.
BTW, this solves also this question
My answer to this question would be "no." But my coworkers disagree.
We're rebuilding our product and have a lot of critical decisions to make in the near-term.
While doing some of my own work I noticed that we've got some in-house C++ classes to abstract some of the POSIX API (threads, mutexes, semaphores, and rw locks) and other utility classes. Note that these classes are basic, and haven't been ported from Linux (portability is a factor in the rebuild.) We are also using POCO C++ libraries.
I brought this to the attention of my coworkers and suggested that we ditch our in-house classes in favour of their POCO equivalents. I want to take full advantage of the library we're already using. They suggested that we should implement our in-house classes using POCO, and further abstract additional POCO classes as necessary, so as not to depend on any specific C++ library (citing future unknowns - what if we want to use a different lib/framework like QT or boost, what if the one we choose turns out to be no good or development becomes inactive, etc.)
They also don't want to refactor legacy code, and by abstracting parts of POCO with our own classes, we can implement additional functionality (classic OOP.) Both of these arguments I can appreciate. However, I argue that if we're doing a recode we should go big, or go home. Now would be the time to refactor and it really shouldn't be that bad especially given the similarity between our classes and those in POCO (threads, etc.) I don't know what to say regarding the second point - should we only use extended classes where the functionality is necessary?
My coworkers also don't want to litter the POCO namespace all over the place. I argue that we should pick a library/framework/toolkit, and stick with it. Take full advantage of its features. Is this not typical practice? The only project I've seen that abstracts an entire framework is Freeswitch (that provides its own interface to APR.)
One suggestion is that the API we expose to each other, and potential customers, should be free of POCO, but it would be present in the implementation (which makes sense.)
None of us really have experience in these kinds of design decisions, and it shows in the current product. Having been at this since I was young, I've got some intuition that has brought me here, but no practical experience either. I really want to avoid poor solutions to problems that are already solved.
I think my question boils down to this: When building a product, should we a) choose a dominant framework on which to base most of our code, and b) expect that framework to be tightly coupled with the product? Isn't that the point of a framework? (Is framework or library more appropriate for POCO?)
First, the API that you expose should definitely be free of POCO, boost, qt, or any other type that is not part of the standard C++ library. This is because the base libraries have their own release cycle, distinct from the release cycle of your library. If the users of your library also use boost, but a different, incompatible, version, they would need to spend time to resolve the incompatibility. The only exception to this rule is when you design a library to be released as part of a wider framework - say, an addition to the POCO toolkit. In this case the release of your library is tied to the release of the entire toolkit.
Internally, however, you should avoid using your own wrappers, unless the library that you are abstracting out is a true "commodity library"1. The reason for this is that when you hide an external library behind your classes, most of the time you mimic the level of abstraction of the library that you are hiding. The code that uses your wrapper will program to the level of abstraction dictated by the external library. When you swap the implementation behind your wrapper for a different framework, it is very likely that you would either (1) adapt the new framework to fit the level of abstraction of the old framework, or (2) will need to change the way in which you use your wrapper. Both cases are highly suspect: if you do (1), perhaps you shouldn't switch in the first place, and if you do (2), then your wrappers prove to be useless.
1 By "commodity library" I mean a library that provides a level of abstraction commonly found in other libraries that serve a similar purpose.
There are two situations where I think it's worth having your own wrappers:
1) You've looked at several different mutex implementations on different systems/libraries, you've established a common set of requirements that they can all satisfy and that are sufficient for your software. Then you define that abstraction and implement it one or more times, knowing that you've planned ahead for flexibility. The rest of your code is written to rely only on your abstraction, not on any incidental properties of the current implementation(s). I have done this in the past, although not in code I can show you.
A classic example of this "least common interface" would be to change rename in the filesystem abstraction, on the basis that Windows cannot implement an atomic rename-over-an-existing-file. So your code must not rely on atomic rename-replacement if you might in future swap out your current *nix implementation for one that can't do that. You have to restrict the interface from the start.
When done right, this kind of interface can considerably ease any kind of future porting, either to a new system or because you want to change your third-party library dependencies. However, an entire framework is probably too big to successfully do this with -- essentially you'd be inventing and writing your own framework, which is not a trivial task and conceivably is a larger task than writing your actual software.
2) You want to be able to mock/stub/sham/spoof/plagiarize/whatever the next clever technique is, the mutex in tests, and decide that you will find this easier if you have your own wrapper thrown over it than if you're trying to mess with symbols from third-party libraries, or that are built-in.
Note that defining your own functions called wrap_pthread_mutex_init, wrap_pthread_mutex_lock etc, that precisely mimic pthread_* functions, and take exactly the same parameters, might satisfy (2) but doesn't satisfy (1). And anyway, doing (2) properly probably requires more than just wrappers, you usually also want to inject the dependencies into your code.
Doing extra work under the heading of flexibility, without actually providing for flexibility, is pretty much a waste of time. It can be very difficult or even provably impossible to implement one threading environment in terms of another one. If you decide in future to switch from pthreads to std::thread in C++, then having used an abstraction that looks exactly like the pthreads API under different names is (approximately) no help whatsoever.
For another possible change you might make, implementing the full pthreads API on Windows is sort of possible, but probably more difficult than only implementing what you actually need. So if you port to Windows, all your abstraction saves you is the time to search and replace all calls in the rest of your software. You're still going to have to (a) plug in a complete Posix implementation for Windows, or (b) do the work to figure out what you actually need, and only implement that. Your wrapper won't help with the real work.
I have a multithreaded dynamic library which exposes a basic API and which I use in a
couple of applications. Currently I'm using a custom(as in legacy) implementation of some basic threading and synchronization primitives with which I'm not happy at all as it does not provide much flexibility, features and it's also a hassle to maintain(has implementations for both Linux and Windows).
I would like to replace that with some existing threading library but I would also like to provide some flexibility, meaning that I would like to be able to try out a bunch of libraries to see how they perform on different platforms I build my library for(I would like to try boost::thread, Poco::Thread and the new C++0X thread implementation) or even let the user to which I provide my library to fit it's own thread custom implementation if wanted, so that the library and the user's app would be able to use the same threading infrastructure - ideally I would have a config file or something on those lines to let the user specify its desired implementation or use a default provided one.
I was thinking of the following:
making a thin wrapper(pimpl style) to be used inside my library that will use a dynamic class loader to fit the desired implementation at runtime. But how could I handle the case of the C++0X threads? These are in the standard library which will already be linked against my library so no point in custom loading it at runtime.
using a dynamic loader coupled with the Prototype design pattern. But the pattern requires the implementation of the clone() method which would mean changing the threading library code. I might have poorly understood the pattern and I might be mistaking about this, so please correct me if I'm wrong.
As you can see I don't have many ideas to work with right now(but it's a start) so any pointers on the following would be of great help:
Is providing such a functionality a good idea? Do you see any caveats?
Is the dynamic loading facility a feasible idea? What are the downsides?
Any pointers/links on how to properly implement that?
If I'm going the "thin wrapper" way would it be a good idea to expose it as part of my library's API?
Are there any alternatives/patterns to achieve the same kind of functionality(I mean to achieve the same result but without dynamic loading)?
What is the benefit of providing the ability to dynamically or delay load of a threading solution? Ideally you would pick a threading solution and create a library which has an API interface and if the solution was later found to be insufficient you could write a new library using the same interface but a different underlying solution. I would even consider statically linking such a library although a DLL is fine as well. I wouldn't bother with the ability to make it interchangeable at runtime or anything like that.
I highly recommend Boost threads. Cross platform and based off POSIX it's very easy to implement in a variety of ways. I believe that C++0x threads were marginally based off this solution however since C++0x is not finalized or fully supported by all compilers yet I would only consider it as a replacement for boost in the future.
I think that by providing a wrapper for the threading library, and initializing it at runtime, you are limiting yourself to the lowest common denominator. That is, your interface into the thread library calls will need to include operations that are implemented by all of the libraries.
If this is acceptable, then you should look into using the Adapter Pattern to handle calls into the thread library that is chosen by the user. Basically, you would use the config file to determine which thread library is in use, and then wrap it in an adapter class that implements your threading operations methods interface and delegates the calls the appropriate methods on the underlying library. You could also use the adapter to make up for unimplemented functionality in certain library (i.e. by implementing reader/writer locks using the mutexes provided by a library, etc.)
..for an out-of-process-server, or can I call a dispatch interface without registering a proxy/stub?
The interface in question is very high level, so performance is a non-issue, and I could make the whole thing registration-free, which is a big plus
I'm pretty sure you don't need to provide a custom proxy/stub dll if you limit your interface(s) to automation-compatible types. In that case, the system can use the automation marshaler and doesn't need any additional help. I believe the automation-compatible types are the types that can fit into a VARIANT, e.g. simple POD types, BSTRs, and the like.
I found this KB article which has some discussion of the automation marshaler, although it's not specifically targeted at your question. It does list the compatible types, at the very least. It also mentions that you need to specifically identify the automation marshaler in the registration for your component, but in my experience this isn't necessary - your mileage may vary.
Lastly, you may need to implement IProvideClassInfo as well; I usually use the implementation provided by ATL.
You only need a proxy/stub dll if your interface needs to be marshalled. This means if your COM server is in process, and the interface is not passed between apartments, and you aren't going to be calling it from .Net or any other situation that would require it to be marshalled, then you do not need a proxy/stub dll.
Assume that you work only in the C++ world (cross-language interop is not required). What advantages/inconvenients do you see in using COM instead of a plain basic DLL? Do you think using COM is worth the trouble if you are not going to use the interface from different languages?
Everybody is mentioning things that are in COM's plus column. I'll mention a couple of detractions.
When you implement your system using COM, you need to register the COM 'servers' (be they in-proc or out-of-proc) at setup and unregister them at uninstall. This could increase the complexity of your setup system slightly and tends to require a reboot unless the user carefully tears down running processes first.
COM is slow compared to other standard ways of doing the same thing. This comment will probably generate a lot of hate and maybe some downvotes, but the fact of the matter is that at some point you will need to marshall data, and that is expensive.
According to the Rules of COM, once an interface has been published it can never be changed. That in itself is not a negative, and you might even argue that it forces you to do thorough design before shipping the interface. But the truth is there's no such thing as never, and in production code interfaces change. You will undoubtedly need to either add methods or change the signatures of existing methods. In order to accomplish this you have to either break the rules of COM -- which has bad effects -- or follow the rules of COM which are more complicated than just adding a parameter to a function like you would with a astraight DLL.
COM can be useful in plain old C++ for:
Interprocess communication
Plugin architectures
Late binding scenarios
"Much, much, more..." (tm)
That said, if you don't need it, don't use it.
With DLL you can get much closer coupling, while COM limits interactions very precisely. This is the root of both the advantages and the disadvantages!
You get more power and flexibility (e.g. inherit from classes defined in the DLL, not feasible in COM) but the dependency is thereby much stronger (need to rebuild the user for certain changes to the DLL, etc).
Often especially galling is that all DLLs and the EXE must use the same kind of runtime library and options (e.g. all dynamically linked to the non-debug multithreaded version of msvcrt* for example -- can't rebuild just one to use the debug version without incurring very likely errors!).
The looser coupling of COM is therefore often preferable, unless you really need the closer-coupling kinds of interactions in a specific case (e.g., a framework, which definitely requires user-code to inherit from its classes, should be a DLL).
If you can avoid don't use it. In my last project COM brought pretty much limitations into C++ interfaces being used. Just imagine, that you can't simply pass a std::string but have to use an array of characters. In that case you build the string, an then copy it to an array which can be handled by COM.
You also can only use very limited set of fundamental types, have casts and proprietary memory management. You can't use new/delete, but have to use COM own functions.
You also can't simply throw an exception, but have to initialize some COM interface IErrorInfo, which will be rethrown at the other end.
So if you don't need, don't use it. It will definitely screw your design. And if you need it, try to evaluate other interop possibilities: boost::interprocess, zeroc ice...
Regards,
Ovanes
Registration and discovery
Out-of-process
Remote invocation
are the few extra features that you would have got. Even transactional support can flow without the need for COM support these days.
The IUnknown interface is a good base level to support anyway -- gets you a way to add features without breaking old clients (QueryInterface) and pervasive reference counting. You can implement this without buying into everything in COM.
Then, whenever you are adding a feature to a class, if you use the COM interface for it, you at least get an interface that is known -- for example IDispatch if you want reflection features.
Your only delta away from being able to be called by another language would then be the registration and the class factory.
Because interfaces are independent of any particular DLL, at its simplest level, a COM like approach at the very least frees you to change the dll serving an interface under the hood, without having to recompile your app against the new dll name.
Using Full COM with MIDL defined interfaces and proxy stub dlls means that you can use COM to manage thread safety in-process, interprocess comms on the same PC, or even connect to the COM server object on a remote PC.