Wednesday, December 12, 2018

My One Issue with Git

I've been using Git for a year and a half now. I like it. I'm not going to stop using it. But there is one issue that bothers me. I like to save my work remotely, multiple times per day, just in case my hard drive dies. With Git, I don't see a good way to do so.

TFS has the shelveset option. I loved that. I could shelve my code every 20 minutes if I wanted to.

One option, with Git, is to push often. Although not ideal, I was doing that, and I was content. However, when I create a PR, there are sometimes 10+ commits in it. I'm also fine with that, BUT, my current team likes to have just one commit for an entire story of work. This allows us to revert that one commit if it's interfering with a release.

Another option is to push often, then squash my changes into one, so the PR has just one commit. There are two issues with this: 1) it's tedious, manual work to do so (not a big deal), and 2) sometimes there will be merges from develop mixed in with my commits. Apparently squashing over merges can't be done, or it's difficult. That is a big deal in that I can't hit my goal of one commit per PR.

I started looking into options like mirroring a repo, or creating another branch for my backups. And I kept coming back to thinking: "Really? It's this hard to save a remote copy of my work?"

The only other thing I can think of at the moment is to throw a USB drive in my laptop and do a manual copy/paste backup. I think that's unfortunate.

If someone has a better approach, please let me know. Otherwise, TFS (with shelvesets) has at least one advantage over Git.

Thursday, January 11, 2018

A Simple Blockchain in JavaScript

// To run this, do this at a bash shell:
// node main.js

// Source: https://www.youtube.com/watch?v=zVqczFZr124

// Ran this to use SHA56: npm install --save crypto-js

const SHA256 = require('crypto-js/sha256');

class Block {
  constructor(index, timestamp, data, previousHash = '') {
    this.index = index;
    this.timestamp = timestamp;
    this.data = data;
    this.previousHash = previousHash;
    this.hash = this.calculateHash();
  }

  calculateHash() {
    return SHA256(this.index + this.previousHash + this.timestamp +
      JSON.stringify(this.data)).toString();
  }
}

class Blockchain {
  constructor() {
    this.chain = [this.createGenesisBlock()];
  }

  createGenesisBlock() {
    return new Block(0, '1/1/2018', 'Genesis block', '0');
  }

  getLatestBlock() {
    return this.chain[this.chain.length - 1];
  }

  addBlock(newBlock) {
    newBlock.previousHash = this.getLatestBlock().hash;
    newBlock.hash = newBlock.calculateHash();
    this.chain.push(newBlock);
  }

  isChainValid() {
    // Don't need to check the genesis block
    for(let i = 1; i < this.chain.length; i++) {
      const currentBlock = this.chain[i];
      const previousBlock = this.chain[i - 1];

      // Verify the hashes are correct
      if (currentBlock.hash !== currentBlock.calculateHash()) {
        return false;
      }

      // Verify the current block points to the correct previous block
      if (currentBlock.previousHash !== previousBlock.hash) {
        return false;
      }
    }
    return true;
  }
}

let blockchain = new Blockchain();
blockchain.addBlock(new Block(1, '1/2/2018', { amount: 4 }));
blockchain.addBlock(new Block(2, '1/3/2018', { amount: 10 }));

console.log(JSON.stringify(blockchain, null, 4));

console.log('Valid chain: ' + blockchain.isChainValid());

// Tamper with the blockchain by changing an amount
blockchain.chain[1].data = { amount: 100 };

console.log('Valid after tampering: ' + blockchain.isChainValid());