Modelling an account manager in OOP I have this task of modelling a system where given a group of users each can keep track of their expenses. The basic requirements are as followed:


To be able to give credit to an user.
Find all the transactions of a given user.
Filter out the transaction where either user is borrower or spender.


I have tried few things but I am not convinced at all.

const trxn = new Array();

class Transaction {
    constructor(amount, from, to) {
      this.timestamp = new Date();
      this.amount = amount;
      this.from = from;
      this.to   = to;
      trxn.push(this);
    }

    toString() {
      let dd = this.timestamp.getDate();
      let mm = this.timestamp.getMonth();
      let yy = this.timestamp.getFullYear();
      return `[Transaction: ${dd}/${mm}/${yy}] ${this.from} Gives ${this.amount} to ${this.to}`;
    }
}

class Person {
    constructor(name) {
      this.name = name;
      this._transactions = [];
    }

    transfer(amount, to) {
      let t = new Transaction(amount, this, to);
      this._transactions.push(t);
    }

    transactions() {
      return this._transactions;
    }

    toString() {
      return `${this.name.charAt(0).toUpperCase() + this.name.slice(1)}`;
    }
}


function history(transactions, user) {
  return transactions.filter((t) =&gt; {
    return t.to.name === user.name || t.from.name === user.name;
  });
}


let amy = new Person('amy');
let foo = new Person('foo');
amy.transfer(500, foo);
amy.transfer(500, foo);
foo.transfer(200, amy);

for (let t of amy.transactions()) {
  console.log('Transaction by AMY');
  console.log(t);
}

for (let f of foo.transactions()) {
  console.log('Transaction by FOO');
  console.log(f);
}

console.log('Transaction history');
console.log(history(trxn, amy));


Output of the above logic:

Transaction by AMY
[Transaction: 22/10/2016] Amy Gives 500 to Foo
Transaction by AMY
[Transaction: 22/10/2016] Amy Gives 500 to Foo
Transaction by FOO
[Transaction: 22/10/2016] Foo Gives 200 to Amy
Transaction history
[Transaction: 22/10/2016] Amy Gives 500 to Foo,
[Transaction: 22/10/2016] Amy Gives 500 to Foo,
[Transaction: 22/10/2016] Foo Gives 200 to Amy


How can I make my code more flexible and robust following the OOP practices?
I would follow semantics.

Persons are not Accounts. A person may have multiple accounts. Either you rename Person to Account or you have a separate class "Account" so you have following semantic: Amy  transfers 500 from her Account 638423331 to an Account 747266783 that belongs to John.

Transactions are not bound to Accounts. They are on the level of the system which tries to ensure consistency. Sure you can have a list of transactions in each account the account was participant. But that is semantically redundant (denormalized) and has to be synchronized. So I suggest to introduce a class "Accountingsystem" that holds all transactions that keeps the whole consistent.

So my preferred model:

Accountingsystem knows all Persons, all Accounts and all transactions

An account knows its balance and its owner that must be one of the known Persons.

A Transaction knows the accounts participated and the debit/credit amount.

You can have convinience methods to filter transactions or which accounts belong to a person within the accountingsystem.