Talk:Aspect oriented programming: Difference between revisions

m
Thundergnat moved page Talk:Aspect Oriented Programming to Talk:Aspect oriented programming: Follow normal task title capitalization policy
m (Thundergnat moved page Talk:Aspect Oriented Programming to Talk:Aspect oriented programming: Follow normal task title capitalization policy)
 
(11 intermediate revisions by 5 users not shown)
Line 1:
== What is the task here? ==
What is the task here? --[[User:Rdm|Rdm]] 19:10, 9 June 2011 (UTC)
:While it does have some code examples, I think this is supposed to be more of an informational page. It's not marked as a task, but it was made by an anonymous user who probably didn't know the process. --[[User:Mwn3d|Mwn3d]] 20:39, 9 June 2011 (UTC)
Line 26 ⟶ 27:
=== A Possible Task ===
 
Task: Write an example of a factorial function with a logging feature which may be toggled on or off, preferably at compile time, and if possible without altering the original code.
Task: Write some code which provides an optional feature which may be enabled or disabled as the developer desires, at as high a level as possible in the language. If possible, keep the feature code separate, and avoid polluting the original code. The task could be to write a factorial function which logs each iteration it takes only when the LOGGING feature is enabled.
 
Output of factorial(4) when LOGGING is enabled:
Line 34 ⟶ 35:
2 x 1!</lang>
 
A runtime solution for Javascript which avoidsallows us to enable logging at runtime, without polluting the original code:
 
<lang javascript>
###factorial.js###
function factorial(n) {
return ( n==1 ? 1 : n*factorial(n-1) );
}
 
###LOGGING.js###
// Overwrite existing global factorial function with a logging version
Line 45 ⟶ 51:
};
 
###LOGGING_generalised.js###
// This couldcan be generalised into a decorator that can add logging to any given function.
function addLoggingTo(parent,name) {
var oldFn = parent[name];
Line 56 ⟶ 63:
</lang>
 
This might be considered preferable to #ifdefsa whichbunch getsof if-statements mixed into the code. The aspect is separate from the original source. However, since it works by function-rewriting, it may not always be possible, for example if we want to attach to a function that we cannot reference.
 
Some general fallbacks exist for a wide range of languages which have no higher-level support. A simple if (LOGGING) check should always work. Some applications mutate existing code at runtime using a plugin or module framework, in which case the LOGGING feature could be a plugin that may or may not be present to consume log events.
 
In Java, libraries such as Log4j and ApacheLogging are used, but these pollute the code with conditions. So the AspectJ solution is preferable, although it is not pure Java. (Actually the output is pure bytecode, but the build process is not.)
 
In C, I think we are stuck polluting the code using #ifdefs or the LOG(...) example I gave in the article. I suppose we could avoid polluting the code by having the preprocessor switch certain functions for logging versions at compile time, but as I see it that would require parallel preprocessor code for every function we might want to log, so would be even more painful to maintain!
 
-- OP,--[[Special:Contributions/82.32.24.201|82.32.24.201]] 05:11, 19 October 2011 (UTC)
Line 72 ⟶ 83:
:That said, it's often good coding practice to modify the original when introducing pervasive changes. This can make later maintenance much simpler. But we can have tasks here that ask for examples of bad coding practices. But we do not have to pick the variant that uses a task implementation not designed for AOP.
 
:Another variant, then, would be to take an existing task, instrument it with inflection points, and then add the optional AOP code. --[[User:Rdm|Rdm]] 10:56, 21 October 2011 (UTC)
 
:: Interesting! I have been working on the assumption that we ''do not'' want to alter the original! It would be helpful to work out under which situations this is good or bad practice...
 
::: I think in the case of logging it is obvious that separating this concern is useful. Other positive examples were mentioned above: security (validating/sanitising input/output across one level of the application), caching, and tracking transactions.
 
::: When it is not useful: If it impacts the ability to debug an application, because you are looking at the code but you can't see that in fact some code defined elsewhere is being triggered. (We could argue that this problem already exists when reading Java, if you think you have problems with class X, but actually at runtime you were given buggy class Y child of X! Runtime debugging helps to unwrap these problems.)
 
::: In different frameworks the relationships with external code can be more or less obvious. For example when using plugins, a number of hooks may exist in the original code, to call any plugins which are loaded; in this case the path of execution is clear. (However the hooks might make this a less-pure example of AOP-or-whatever-we-are-calling-this.) Event driven frameworks are an alternative view, where the code triggering the event has no idea which handlers have been registered; the developer is unsure what will be executed.
 
::: Other than clarity when reading the code, what other issues can make this bad practice?
 
:: My main objectives here are modularity. We want to break stuff up as much as possible, so we can separate concerns and deal with each part independently, and easily remove or replace parts. Clarity is desirable when possible, but may be a secondary concern.
 
:: Whilst I am not seeking bad examples, I think this paradigm is useful enough that having a working method for all languages is desirable, even when sub-optimal. You may wish your application to have features that can be enabled or disabled at compile time, even if it does mean adding a lot of messy #ifdefs throughout the code!
 
:: Thank you all for your feedback. --[[Special:Contributions/82.32.31.166|82.32.31.166]] 23:20, 20 November 2011 (UTC)
 
::: Note that in C, for example, it's probably best practice to use #ifdefs when setting up #defines in your headers, as opposed to putting them in .c files. --[[User:Rdm|Rdm]] 14:57, 21 November 2011 (UTC)
 
== Updated task? ==
 
What should be logged, in the updated task? --[[User:Rdm|Rdm]] 10:08, 24 October 2011 (UTC)
 
: It would be good to refine the task. Logging may be too trivial an example to make the paradigm stand out. I like the idea of (optionally) adding a mutex around certain parts of code. Is this a rich enough example to demonstrate all the requirements we have? Other possible examples were mentioned earlier.
 
: Before considering the task, I will try to present all the requirements I would like to satisfy (use-cases for this paradigm):
 
:: Adding features to a program which can be enabled or disabled at runtime. (Ideally not polluting the original code, but sometimes unavoidable.)
 
:: Keeping code related to different features in a separate file/module (e.g. inheritance), or at the very least relate all the feature code using some unique identifier (e.g. #ifdefs).
 
:: Reducing the size of the code. Often by generalizing a common concept we can encapsulate repeated patterns in the code and reduce the overall footprint. For example, AspectJ can manipulate methods across many classes, with a few lines of code.
 
: Do you think we need to separate these goals, given that the first two can conflict? Perhaps clarity/modularity should be one goal, and enabling/disabling features another. --[[Special:Contributions/82.32.31.166|82.32.31.166]] 00:03, 21 November 2011 (UTC)
 
:: In some languages, mutex is implicit. --[[User:Rdm|Rdm]] 19:35, 5 December 2011 (UTC)
 
::: And some languages are single-threaded (at least in terms of basic model). –[[User:Dkf|Donal Fellows]] ([[User talk:Dkf|talk]]) 15:23, 27 April 2014 (UTC)
 
:::: Exactly. Also, computers are getting to be cheap enough that often you are running clusters of machines (requiring many instances of the language rather than threads within the language). And once you get into that territory, language integrity checks start failing in the sense that communication failures, hardware failures, version drift and data and storage integrity across time become dominant issues. Plus, of course, having an adequate supply of yummy food. --[[User:Rdm|Rdm]] ([[User talk:Rdm|talk]]) 17:20, 27 April 2014 (UTC)
10,327

edits