When do I need more than one TraceSource in code? - c#

If one application is writing all its activity data in one log file, is there any use of having more than one TraceSource? I am just curious about the uses cases where one will need more than one TraceSource in the code.

See these answers to other questions for a good starting point on using TraceSources:
can't understand .net 2010 tracing and app.config
How to use TraceSource across classes
I would say that any time you have more than one class you might (might) consider having more than one TraceSource.
One advantage to having more than one TraceSource is that it increases the granularity at which you can control your logging. For example, if you use a different TraceSource in every class, then you could control the logging down to the class level. You could turn on one (or more) specific classes and turn off all others.
This is a common pattern for users of NLog and log4net. Typical initialization of classes using those logging platforms will look something like this:
public class A
{
//NLog example
private static Logger logger = LogManager.GetCurrentClassLogger();
public F()
{
logger.Info("Inside F");
}
}
In this example, the logger for class A is named for the fully qualified name of the class (NLog does the hard work in GetCurrentClassLogger()).
To do something similar with TraceSource, you would do something like this:
public class A
{
private static TraceSource ts = new TraceSource(System.Reflection.GetCurrentMethod().DeclaringType.ToString();
public F()
{
ts.Information("Inside F");
}
}
If you did this in every class, you could easily control you logging by class.
I'm not so sure that this pattern is as common with TraceSource as it is with log4net and NLog. I think that you might more often see users of TraceSource get their TraceSources by functional area.
So, you might divide your app up into "Read", "Process", and "Write" functionality (or whatever makes sense for you). In that case, you could get the appropriate TraceSource in your classes based on the functional area in which they are used:
public class FileReader
{
private static TraceSource ts = new TraceSource("Read");
public F()
{
ts.Information("Hello from FileReader.F");
}
}
public class NetworkReader
{
private static TraceSource ts = new TraceSource("Read");
public F()
{
ts.Information("Hello from NetworkReader.F");
}
}
And so on.
Now you could turn logging on for "Read", and off for all other functional areas (or turn on verbose logging for "Read" and less verbose logging for all others).
In addition, one of the options with TraceListeners is to output the TraceSource name. So, in your output it will easier to make sense of your logging because you could, if you choose to do so, relatively easily find all logging messages that are generated from a particular functional area (or by a particular TraceSource).
If you have a good namespace naming convention, you could even consider getting the TraceSource for each class based on some node in the namespace hierarchy or even based on the assembly that the class lives in. There are .NET calls for a Type that will retrieve that information for you.
Since you are looking at TraceSources, I would encourage you to look at this project at codeplex:
http://ukadcdiagnostics.codeplex.com/
It is a nice project (based on TraceSource) that allows you to format your logging output in a similar fashion to what you can do with log4net and NLog.
I would also encourage you to take a look at this logging wrapper built around TraceSource from Castle.
https://github.com/castleproject/Castle.Core/blob/master/src/Castle.Core/Core/Logging/TraceLogger.cs
The interesting thing that they have done is to provide a hierarchy to TraceSource names. I have implemented something similar in the past. It works out pretty well.
My answer in this question provides an idea for how a TraceSource hierarchy can be beneficial:
What's the best approach to logging?
Good luck!

Related

Is it a good practice to have logger as a singleton?

I had a habit to pass logger to constructor, like:
public class OrderService : IOrderService {
public OrderService(ILogger logger) {
}
}
But that is quite annoying, so I've used it a property this for some time:
private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
This is getting annoying too - it is not dry, I need to repeat this in every class. I could use base class, but then again - I'm using Form class, so would need FormBase, etc.
So I think, what would be downside of having singleton with ILogger exposed, so veryone would know where to get logger:
Infrastructure.Logger.Info("blabla");
UPDATE: As Merlyn correctly noticed, I've should mention, that in first and second examples I am using DI.
I put a logger instance in my dependency injection container, which then injects the logger into the classes which need one.
This is getting annoying too - it is not DRY
That's true. But there is only so much you can do for a cross-cutting concern that pervades every type you have. You have to use the logger everywhere, so you must have the property on those types.
So lets see what we can do about it.
Singleton
Singletons are terrible <flame-suit-on>.
I recommend sticking with property injection as you've done with your second example. This is the best factoring you can do without resorting to magic. It is better to have an explicit dependency than to hide it via a singleton.
But if singletons save you significant time, including all refactoring you will ever have to do (crystal ball time!), I suppose you might be able to live with them. If ever there were a use for a Singleton, this might be it. Keep in mind the cost if you ever want to change your mind will be about as high as it gets.
If you do this, check out other people's answers using the Registry pattern (see the description), and those registering a (resetable) singleton factory rather than a singleton logger instance.
There are other alternatives that might work just as well without as much compromise, so you should check them out first.
Visual Studio code snippets
You could use Visual Studio code snippets to speed up the entrance of that repetitive code. You will be able to type something like loggertab, and the code will magically appear for you.
Using AOP to DRY off
You could eliminate a little bit of that property injection code by using an Aspect Oriented Programming (AOP) framework like PostSharp to auto-generate some of it.
It might look something like this when you're done:
[InjectedLogger]
public ILogger Logger { get; set; }
You could also use their method tracing sample code to automatically trace method entrance and exit code, which might eliminate the need to add some of the logger properties all together. You could apply the attribute at a class level, or namespace wide:
[Trace]
public class MyClass
{
// ...
}
// or
#if DEBUG
[assembly: Trace( AttributeTargetTypes = "MyNamespace.*",
AttributeTargetTypeAttributes = MulticastAttributes.Public,
AttributeTargetMemberAttributes = MulticastAttributes.Public )]
#endif
Good question. I believe in most projects logger is a singleton.
Some ideas just come to my mind:
Use ServiceLocator (or an other Dependency Injection container if you already using any) which allows you to share logger across the services/classes, in this way you can instantiate logger or even multiple different loggers and share via ServiceLocator which is obviously would be a singleton, some kind of Inversion of Control. This approach gives you much flexibility over a logger instantiation and initialization process.
If you need logger almost everywhere - implement extension methods for Object type so each class would be able to call logger's methods like LogInfo(), LogDebug(), LogError()
A singleton is a good idea. An even better idea is to use the Registry pattern, which gives a bit more control over instantiation. In my opinion the singleton pattern is too close to global variables. With a registry handling object creation or reuse there is room for future changes to instantiation rules.
The Registry itself can be a static class to give simple syntax to access the log:
Registry.Logger.Info("blabla");
A plain singleton is not a good idea. It makes it hard to replace the logger. I tend to use filters for my loggers (some "noisy" classes may only log warnings/errors).
I use singleton pattern combined with the proxy pattern for the logger factory:
public class LogFactory
{
private static LogFactory _instance;
public static void Assign(LogFactory instance)
{
_instance = instance;
}
public static LogFactory Instance
{
get { _instance ?? (_instance = new LogFactory()); }
}
public virtual ILogger GetLogger<T>()
{
return new SystemDebugLogger();
}
}
This allows me to create a FilteringLogFactory or just a SimpleFileLogFactory without changing any code (and therefore complying to Open/Closed principle).
Sample extension
public class FilteredLogFactory : LogFactory
{
public override ILogger GetLogger<T>()
{
if (typeof(ITextParser).IsAssignableFrom(typeof(T)))
return new FilteredLogger(typeof(T));
return new FileLogger(#"C:\Logs\MyApp.log");
}
}
And to use the new factory
// and to use the new log factory (somewhere early in the application):
LogFactory.Assign(new FilteredLogFactory());
In your class that should log:
public class MyUserService : IUserService
{
ILogger _logger = LogFactory.Instance.GetLogger<MyUserService>();
public void SomeMethod()
{
_logger.Debug("Welcome world!");
}
}
There is a book Dependency Injection in .NET. Based on what you need you should use interception.
In this book there is a diagram helping to decide whether to use Constructor injection, property injection, method injection, Ambient Context, Interception.
That's how one reasons using this diagram:
Do you have dependency or need it? - Need it
Is it cross-cutting concern? - Yes
Do you need an answer from it? - No
Use Interception
Another solution I personally find the easiest is to use a static Logger class. You can call it from any class method without having to change the class, e.g. add property injection etc. Its pretty simple and easy to use.
Logger::initialize ("filename.log", Logger::LEVEL_ERROR); // only need to be called once in your application
Logger::log ("my error message", Logger::LEVEL_ERROR); // to be used in every method where needed
If you want to look at a good solution for logging I suggest you look at google app engine with python where logging is as simple as import logging and then you can just logging.debug("my message") or logging.info("my message") which really keeps it as simple as it should.
Java didn't have a good solution for logging ie log4j should be avoided since it practically forces you to use singletons which as answered here is "terrible" and I've had horrible experience with trying to make logging output the same logging statement only once when I suspect that the reason for double logging was that I have one Singleton of the logging object in two classloaders in the same virtual machine(!)
I beg your pardon for not being so specific to C# but from what I've seen the solutions with C# look similar Java where we had log4j and we also should make it a singleton.
That's why I really liked the solution with GAE / python, it's as simple as it can be and you don't have to worry about classloaders, getting double logging statement or any design patterna at all for that matter.
I hope some of this information can be relevant to you and I hope that you want to take a look at I logging solution I recommend instead of that I bully down on how much problem Singleton get suspected due to the impossibility of having a real singleton when it must be instanciating in several classloaders.

Function? Class?

I'm writing an app (C#) and at times I will need to log to the Windows event log. So the first thing that comes to mind is to write a function in my one and only class and call it when I need it. Something like this:
private void Write_Event_Log(string log, string source, string message, EventLogEntryType type, int eventid)
{
if (!EventLog.SourceExists(source))
EventLog.CreateEventSource(source, log);
EventLog.WriteEntry(source, message, type, eventid);
}
A colleague of mine asked, "why didn't you just create a new class for your event log writer?" So my question is, why would I? And what would this class even look like? And why would I need it when my function works nicely? ok that's 3 questions but you get the point :)
why would I?
To encapsulate the logging functionality into its own class. Why? Single Responsibility Principle http://en.wikipedia.org/wiki/Single_responsibility_principle. Ny mixing it into your class you are making that class be responsible for at least two (2) things: whatever it does and logging.
And what would this class even look like?
public class LogWriter
{
public static Log(string log, string source, string message, EventLogEntryType type, int eventid)
{
if (!EventLog.SourceExists(source))
EventLog.CreateEventSource(source, log);
EventLog.WriteEntry(source, message, type, eventid);
}
}
And why would I need it when my function works nicely?
Think about when you are no longer responsible for the code. Think ahead to when the code grows. Eventually, in addition to logging it might have a host of other very helpful functions included in it. The next programmer would be much happier not having to refactor your work because the design precedent has been set.
This is a very general question about OO design. Your colleague is referring to separation of responsibilities; he doesn't think that the idea of an event log writer fits into the abstraction of the class you put it in, and it deserves its own.
If this is all you are ever going to use it for (this one method) and this program is simple enough that you are implementing it one class, there is no need to use another class to interact with your event writer. If you can conceive that your event writer might be used in a different way, or by a different class, in the future, then yes, absolutely make it is own class so that you avoid future problems where you have to change the source code that uses it.
The function you've written is a small function that doesn't keep state, so another class is not really necessary unless it's to avoid future problems.
Simple, what if you wish to use this method every where in all other parts of your code base? You again copy - paste. Instead have a helper or a Add in class, where just instantiate and keep calling.
Plus if its in a class, you can have more properties and provide more customization methods as well in logging data.
See if you can make use of built in eventlog/trace stuffs.
If it's a small application (which with one class it must be) then it probably doesn't matter.
But design wise in a larger application, you probably would want to consider having the logging functionality in a class by itself in order to keep each class as narrowly focused as possible.
For the same reason that someone put SourceExists(Source) and CreateEventSource(source, log) into their own class, so you could call them just by referencing the assembly that has that class defined, and writing
EventLog.SourceExists(source);
or
EventLog.CreateEventSource(source, log);
So if you will never ever need to write to the event log in any other application you ever write, then what you are doing is fine... but if you might ever need this again, then .....
I think you should have seperate class because if you are going to create more no.of classes in your application you can use same logging for all of them see below example
public static class Logger
{
private static string logFilePath = string.Empty;
public static void Log(string logMessage, TextWriter w)
{
w.Write( logMessage);
w.Flush();
}
public static void Log(string textLog)
{
string directoryString =
filepath+ #"\Logging";
Directory.CreateDirectory(directoryString);
logFilePath = directoryString + "\\" +
DateTime.Now.ToShortDateString().Replace("/", "") + ".txt";
StreamWriter sw = null;
if (!File.Exists(logFilePath))
{
try
{
sw = File.CreateText(logFilePath);
}
finally
{
if (sw != null) sw.Dispose();
}
}
using (StreamWriter w = File.AppendText(logFilePath))
{
Log(textLog, w);
w.Close();
}
}
I agree that you shouldn't create a new class for writing directly to the event log, but for another reason. That class already exists!
Consider using the built-in debug/tracing mechanisms in System.Diagnostics:
Debug output
Trace output
These are standard classes that dump information to a collection of TraceListener objects, of which many useful types already exist:
DefaultTraceListener - Dumps output to standard debug out, I believe via OutputDebugString().
EventLogTraceListener - Dumps output to the windows event log.
So this changes your output mechanism from a programmatic question into a configuration question. (Yes, if you're working in a straight-up managed app, you can populate your TraceListener collection via your app.config.) That means that everywhere you simply use the appropriate Trace.Write() or Debug.Write() call (Depending on if your want the output in a release build), and the configuration determines where the output goes.
Of course, you can also populate your TraceListener collection programmatically, it's fun and simple.
And this way you don't have to build up your own home-grown logging infrastructure. It's all built-in! Use it in good health! :D
If, on the other hand, you insist on rolling your own (a bad idea, I think), your colleague is right. It's a separate responsibility and belongs in a separate class. I would expect static methods for output because there's probably no concept instances of your debug log. In fact, I'd expect an interface very similar to System.Diagnostics.Debug, so yeah, just use that one instead.
Depending on your approach, you may run into a subtle gotcha' that's in the docs, but not immediately obvious without a careful reading. I found an answer for it elsewhere.

Which pattern to use for logging? Dependency Injection or Service Locator?

Consider this scenario. I have some business logic that now and then will be required to write to a log.
interface ILogger
{
void Log(string stuff);
}
interface IDependency
{
string GetInfo();
}
class MyBusinessObject
{
private IDependency _dependency;
public MyBusinessObject(IDependency dependency)
{
_dependency = dependency;
}
public string DoSomething(string input)
{
// Process input
var info = _dependency.GetInfo();
var intermediateResult = PerformInterestingStuff(input, info);
if (intermediateResult== "SomethingWeNeedToLog")
{
// How do I get to the ILogger-interface?
}
var result = PerformSomethingElse(intermediateResult);
return result;
}
}
How would you get the ILogger interface? I see two main possibilities;
Pass it using Dependency Injection on the constructor.
Get it via a singleton Service Locator.
Which method would you prefer, and why? Or is there an even better pattern?
Update:
Note that I don't need to log ALL method calls. I only want to log a few (rare) events that may or may not occur within my method.
I personally do a mixture of both.
Here are my conventions:
From a static context - Service Location
From an instance context - Dependency Injection
I feel this gives me the right balance of testability. I find it a little harder to setup tests against classes that use Service Location than use DI, so this is why Service Location ends up being the exception rather than the rule. I'm consistent in its use, though, so it's not hard to remember what type of test I need to write.
Some have raised the concern that DI tends to clutter constructors. I don't feel this is a problem, but if you feel this way, there are a number of alternatives that use DI, but avoid constructor parameters. Here is a list of Ninject's DI methods:
http://ninject.codeplex.com/wikipage?title=Injection%20Patterns
You'll find that most Inversion of Control containers have the same features as Ninject. I chose to show Ninject because they have the most concise samples.
Hopefully this is helpful.
Edit: To be clear, I use Unity and Common Service Locator. I have a singleton instance of my Unity container for DI and my implementation of IServiceLocator is simply a wrapper around that singleton Unity container. This way I don't have to do any type mappings twice or anything like that.
I also don't find AOP to be particularly helpful beyond tracing. I like manual logging better simply for its clarity. I know that most AOP logging frameworks are capable of both, but I don't need the former (AOP's bread and butter) most of the time. This is just personal preference, of course.
The logger is clearly a service that your business logic depends upon, and should thus be treated as a dependency the same way you do with IDependency. Inject the logger in your constructor.
Note: even though AOP is mentioned as the way to inject logging I do not agree that it is the solution in this case. AOP works great for execution tracing, but will never be a solution for logging as part of business logic.
My little rule of thumb:
If it's in a class library, use either constructor injection or property injection with a null-object pattern.
If it's in a main application, use the service locator (or singleton).
I find this applies pretty well when using log4net. You don't want class libraries reaching out to things that might not be there, but in an application program, you know that the logger is going to be there, and libraries like log4net are based heavily around the service-location pattern.
I tend to think of logging as something sufficiently static that it doesn't really need DI. It's extremely unlikely that I'll ever change the logging implementation in an application, especially since every logging framework out there is incredibly flexible and easy to extend. It's more important in class libraries when your library might need to be used by several applications which already use different loggers.
YMMV, of course. DI is great but that doesn't mean everything needs to be DI'ed.
Maybe this will be little offtopic, but why do we need injecting logger at all, when we can just type at the beggining of the class:
Logger logger = LogManager.GetLogger("MyClassName");
Logger doesn't change during development and later during maintenance. Modern loggers are highly customizable, so argument
what if I want to replace text logger with database?
is missed.
I don't negate using dependency injection, I'm just curious about your mind.
We switched all our Logging/Tracing to PostSharp (AOP framework) attributes. All you need to do to create logging for a method is add the attribute to it.
Benefits:
Easy use of AOP
Clear separation of concerns
Happens at compile time -> Minimal performance impact
Check out this.
I would prefer Singleton Service.
Dependency injection would clutter the constructor.
If you can use AOP, that would be the best.
You could derive another type e.g. LoggableBusinessObject that takes a logger in its constructor. This means you only pass in the logger for objects that will use it:
public class MyBusinessObject
{
private IDependency _dependency;
public MyBusinessObject(IDependency dependency)
{
_dependency = dependency;
}
public virtual string DoSomething(string input)
{
// Process input
var info = _dependency.GetInfo();
var result = PerformInterestingStuff(input, info);
return result;
}
}
public class LoggableBusinessObject : MyBusinessObject
{
private ILogger _logger;
public LoggableBusinessObject(ILogger logger, IDependency dependency)
: base(dependency)
{
_logger = logger;
}
public override string DoSomething(string input)
{
string result = base.DoSomething(input);
if (result == "SomethingWeNeedToLog")
{
_logger.Log(result);
}
}
}
DI would work nicely here. Another thing to look at would be AOP.
I'd recommend neither of these approaches. Better to use aspect-oriented programming. Logging is the "hello world" of AOP.

thoughts on configuration through delegates

i'm working on a fork of the Divan CouchDB library, and ran into a need to set some configuration parameters on the httpwebrequest that's used behind the scenes. At first i started threading the parameters through all the layers of constructors and method calls involved, but then decided - why not pass in a configuration delegate?
so in a more generic scenario,
given :
class Foo {
private parm1, parm2, ... , parmN
public Foo(parm1, parm2, ... , parmN) {
this.parm1 = parm1;
this.parm2 = parm2;
...
this.parmN = parmN;
}
public Bar DoWork() {
var r = new externallyKnownResource();
r.parm1 = parm1;
r.parm2 = parm2;
...
r.parmN = parmN;
r.doStuff();
}
}
do:
class Foo {
private Action<externallyKnownResource> configurator;
public Foo(Action<externallyKnownResource> configurator) {
this.configurator = configurator;
}
public Bar DoWork() {
var r = new externallyKnownResource();
configurator(r);
r.doStuff();
}
}
the latter seems a lot cleaner to me, but it does expose to the outside world that class Foo uses externallyKnownResource
thoughts?
This can lead to cleaner looking code, but has a huge disadvantage.
If you use a delegate for your configuration, you lose a lot of control over how the objects get configured. The problem is that the delegate can do anything - you can't control what happens here. You're letting a third party run arbitrary code inside of your constructors, and trusting them to do the "right thing." This usually means you end up having to write a lot of code to make sure that everything was setup properly by the delegate, or you can wind up with very brittle, easy to break classes.
It becomes much more difficult to verify that the delegate properly sets up each requirement, especially as you go deeper into the tree. Usually, the verification code ends up much messier than the original code would have been, passing parameters through the hierarchy.
I may be missing something here, but it seems like a big disadvantage to create the externallyKnownResource object down in DoWork(). This precludes easy substitution of an alternate implementation.
Why not:
public Bar DoWork( IExternallyKnownResource r ) { ... }
IMO, you're best off accepting a configuration object as a single parameter to your Foo constructor, rather than a dozen (or so) separate parameters.
Edit:
there's no one-size-fits-all solution, no. but the question is fairly simple. i'm writing something that consumes an externally known entity (httpwebrequest) that's already self-validating and has a ton of potentially necessary parameters. my options, really, are to re-create almost all of the configuration parameters this has, and shuttle them in every time, or put the onus on the consumer to configure it as they see fit. – kolosy
The problem with your request is that in general it is poor class design to make the user of the class configure an external resource, even if it's a well-known or commonly used resource. It is better class design to have your class hide all of that from the user of your class. That means more work in your class, yes, passing configuration information to your external resource, but that's the point of having a separate class. Otherwise why not just have the caller of your class do all the work on your external resource? Why bother with a separate class in the first place?
Now, if this is an internal class doing some simple utility work for another class that you will always control, then you're fine. But don't expose this type of paradigm publicly.

Using delegates instead of interfaces for decoupling. Good idea?

When writing GUI apps I use a top level class that "controls" or "coordinates" the application. The top level class would be responsible for coordinating things like initialising network connections, handling application wide UI actions, loading configuration files etc.
At certain stages in the GUI app control is handed off to a different class, for example the main control swaps from the login screen to the data entry screen once the user authenticates. The different classes need to use functionality of objects owned by the top level control. In the past I would simply pass the objects to the subordinate controls or create an interface. Lately I have changed to passing method delegates instead of whole objects with the two main reasons being:
It's a lot easier to mock a method than a class when unit testing,
It makes the code more readable by documenting in the class constructor exactly which methods subordinate classes are using.
Some simplified example code is below:
delegate bool LoginDelegate(string username, string password);
delegate void UpdateDataDelegate(BizData data);
delegate void PrintDataDelegate(BizData data);
class MainScreen {
private MyNetwork m_network;
private MyPrinter m_printer;
private LoginScreen m_loginScreen;
private DataEntryScreen m_dataEntryScreen;
public MainScreen() {
m_network = new Network();
m_printer = new Printer();
m_loginScreen = new LoginScreen(m_network.Login);
m_dataEntryScreen = new DataEntryScreen(m_network.Update, m_printer.Print);
}
}
class LoginScreen {
LoginDelegate Login_External;
public LoginScreen(LoginDelegate login) {
Login_External = login
}
}
class DataEntryScreen {
UpdateDataDelegate UpdateData_External;
PrintDataDelegate PrintData_External;
public DataEntryScreen(UpdateDataDelegate updateData, PrintDataDelegate printData) {
UpdateData_External = updateData;
PrintData_External = printData;
}
}
My question is that while I prefer this approach and it makes good sense to me how is the next developer that comes along going to find it? In sample and open source C# code interfaces are the preferred approach for decoupling whereas this approach of using delegates leans more towards functional programming. Am I likely to get the subsequent developers swearing under their breath for what is to them a counter-intuitive approach?
It's an interesting approach. You may want to pay attention to two things:
Like Philip mentioned, when you have a lot of methods to define, you will end up with a big constructor. This will cause deep coupling between classes. One more or one less delegate will require everyone to modify the signature. You should consider making them public properties and using some DI framework.
Breaking down the implementation to the method level can be too granular sometimes. With class/interface, you can group methods by the domain/functionality. If you replace them with delegates, they can be mixed up and become difficult to read/maintain.
It seems the number of delegates is an important factor here.
While I can certainly see the positive side of using delegates rather than an interface, I have to disagree with both of your bullet points:
"It's a lot easier to mock a method than a class when unit testing". Most mock frameworks for c# are built around the idea of mocking a type. While many can mock methods, the samples and documentation (and focus) are normally around types. Mocking an interface with one method is just as easy or easier to mock than a method.
"It makes the code more readable by documenting in the class constructor exactly which methods subordinate classes are using." Also has it's cons - once a class needs multiple methods, the constructors get large; and once a subordinate class needs a new property or method, rather than just modifying the interface you must also add it to allthe class constructors up the chain.
I'm not saying this is a bad approach by any means - passing functions rather than types does clearly state what you are doing and can reduce your object model complexity. However, in c# your next developer will probably see this as odd or confusing (depending on skill level). Mixing bits of OO and Functional approaches will probably get a raised eyebrow at the very least from most developers you will work with.

Categories

Resources