Aspect Oriented Programming, or AOP for short, is a paradigm aimed at separating so called cross-cutting concerns in our software. You can take an in depth look at what this paradigm is all about, in my post here, https://steemit.com/steemstem/@prometheus21/introduction-to-aspect-oriented-programming, where I have explained this concept. In this tutorial, my aim is to provide a somewhat realistic scenario for AOP use, more so than you would find in a hello world you would find in most documentations. I wanted to get started in experimenting with the steemit API, and I wanted to do an AOP tutorial after my introduction post on the matter, so what better way than to solve two problems in with one solution! If you want to skip right ahead to the end, here is the finished project: Code
My script connects to the steemit api, retrieves the account history (number of transactions are also specified ) for an account of your choice. Than, it parses these transactions, extracting the names of those who upvoted you. Every time a new name is found, another method is called, a stub method, wrapped by a JavaScript object, which simply writes the name of the person found to the console. Than, I define an 'advice', in which, I will add additional behavior that is executed before and after the stub method I previously mentioned. In order to keep things simple, this additional behavior is just writing some text to the console, but it can be retooled to write logs to a file for example.
Firstly, let's import the necessary libraries for our project, the steem API library and the aspects library:
var steem = require('steem');
const around = require('aspectjs').around;
As far as constants go, we specify the number of transactions we want the API to fetch and the targeted account. The default values I have set up are 15 and the target account is mine 😃
// tell the api how many tranzactions you want fetched
const NUMBER_OF_TRANZACTIONS = 15;
// write your account name, or any other account here :)
const NAME = 'prometheus21';
In our api object, we add a function, getUpvotes, that fetches from the API the last n tranzactions, where n is our NUMBER_OF_TRANZACTIONS constant we have defined. Here is the code for that:
var api = {
getUpvotes : function() {
steem.api.getAccountHistory(NAME, 99999999, NUMBER_OF_TRANZACTIONS, function(err, accountHistory) {
if (err) throw err
for (var i=0; i < accountHistory.length; i++) {
var name = process_tranzaction(accountHistory[i]);
if (name) {
upvoteObject.add(name)
}
}
});
},
}
We invoke our API using the constants defined, get an array of transactions in the accountHistory variable. We than process each transaction in a for loop.
We use an auxiliary function, process_tranzaction, to parse the each transaction, which is simply a JSON object and extract the account that upvoted you. You can do console.log(accountHistory[i]) to see how a transaction looks like.
Seeing the data, helps us build the auxiliary function I was mentioning, process_tranzaction. Here we check if the transaction is a voting transactions and return the name of the person who upvoted, if that person was not the target account.
Every time we find a name, we call upvoteObject.add(name). Now, this is a trivial method, a stub, that only prints out the name. However, we can imagine other logic being integrated there, for example upvoting a post for that name, or following that account, or any other use case one is interested in. Here is the code for the stub:
var upvoteObject = {
add: function(supporter){
console.log('I have an upvote by ' + supporter)
},
};
For our final part, we shall use the aspectjs to override the call our upvoteObject makes to add. We insert our code before and after the function call. In this case the custom code inserted will be just some console logs.
var advice = {
override: function(invocation) {
console.log('Hey, I can do something cool before I find a new upvote')
invocation.proceed();
console.log('Hey, I can again do something cool, after I have found the upvote')
console.log("************")
}
};
We add our advice to the upvoteObject like this:
around(upvoteObject, "add").add(advice, "override");
With this line, we basically add some extra functionality to our add function, without modifying our add function, which is crucial when we want to separate concerns in our software.
First of all, I want to post the full code again, if you skipped to this part of the post : Code. As this is my first tutorial, feedback would be much appreciated.