Skip to content

Instantly share code, notes, and snippets.

@calexandrepcjr
Last active May 22, 2020 17:56
Show Gist options
  • Save calexandrepcjr/a8fc5a976cae6b7cdc04a939232c261e to your computer and use it in GitHub Desktop.
Save calexandrepcjr/a8fc5a976cae6b7cdc04a939232c261e to your computer and use it in GitHub Desktop.
Inspired by Michael Feathers
/**
* UNCONDITIONAL CODE EXAMPLE - INSPIRED BY Michael Feathers
*
* https://www.youtube.com/watch?v=AnZ0uTOerUI
*/
// OLD CODE
enum MessageType {
EXTERNAL = "external",
INTERNAL = "internal",
REPORT = "report",
NOTIFICATION = "notification",
}
interface Publishable<T> {
messageType: MessageType;
data: T;
}
class Queue {
public constructor(private readonly queue: unknown[] = []) { }
public add(element: unknown): void {
this.queue.push(element);
}
public clean(): void {
this.queue.length = 0;
}
public toArray(): unknown[] {
return this.queue;
}
}
abstract class BaseMessageService {
public constructor(public readonly queue: Queue = new Queue()) { }
public publish<T>(message: unknown): void {
this.queue.add(JSON.stringify(message));
}
}
class OldMessageService extends BaseMessageService {
public publish<T>(message: Publishable<T>): void {
super.publish(this.parse(message));
}
private parse<T>(message: Publishable<T>): unknown {
switch (message.messageType) {
case MessageType.EXTERNAL:
return {
externalData: message.data,
};
case MessageType.INTERNAL:
return {
internalData: message.data,
};
case MessageType.REPORT:
return {
reportData: message.data,
};
case MessageType.NOTIFICATION:
return {
notificationData: message.data,
};
default:
return message.data;
}
}
}
interface Nameable {
name: string;
}
abstract class OldWhisperMessage implements Publishable<Nameable> {
abstract readonly messageType: MessageType;
protected constructor(public readonly data: Nameable, nameWordQuantity: number = -1) {
this.data.name = this.data.name.split(" ", nameWordQuantity).join(" ");
}
}
class OldWhisperExternalMessage extends OldWhisperMessage {
public readonly messageType: MessageType = MessageType.EXTERNAL;
public constructor(data: Nameable) {
super(data, 2);
}
}
class OldWhisperInternalMessage extends OldWhisperMessage {
public readonly messageType: MessageType = MessageType.INTERNAL;
public constructor(data: Nameable) {
super(data, 1);
}
}
class OldWhisperReportMessage extends OldWhisperMessage {
public readonly messageType: MessageType = MessageType.REPORT;
public constructor(data: Nameable) {
super(data);
}
}
class OldWhisperNotificationMessage extends OldWhisperMessage {
public readonly messageType: MessageType = MessageType.NOTIFICATION;
public constructor(data: Nameable) {
super(data, 3);
}
}
// INSIDE A RANDOM OLD LISTENER
const dataReceivedByListener = () => { return { name: "Carlos Alexandre Pires de Carvalho Junior" } };
const externalMessage = new OldWhisperExternalMessage(dataReceivedByListener());
const internalMessage = new OldWhisperInternalMessage(dataReceivedByListener());
const reportMessage = new OldWhisperReportMessage(dataReceivedByListener());
const notificationMessage = new OldWhisperNotificationMessage(dataReceivedByListener());
const oldQueue = new Queue();
const publisher = new OldMessageService(oldQueue);
publisher.publish(externalMessage);
publisher.publish(internalMessage);
publisher.publish(reportMessage);
publisher.publish(notificationMessage);
console.log("QUEUE OLD STATE", oldQueue.toArray());
// NEW UNCONDITIONAL CODE
interface Jsonable {
toJSON(): object;
}
abstract class WhisperMessage implements Publishable<Nameable>, Jsonable {
abstract readonly messageType: MessageType;
protected constructor(public readonly data: Nameable, nameWordQuantity: number = -1) {
this.data.name = this.data.name.split(" ", nameWordQuantity).join(" ");
}
public abstract toJSON(): object;
}
class WhisperExternalMessage extends WhisperMessage {
public readonly messageType: MessageType = MessageType.EXTERNAL;
public constructor(data: Nameable) {
super(data, 2);
}
public toJSON(): object {
return {
externalData: this.data,
};
}
}
class WhisperInternalMessage extends WhisperMessage {
public readonly messageType: MessageType = MessageType.INTERNAL;
public constructor(data: Nameable) {
super(data, 1);
}
public toJSON(): object {
return {
internalData: this.data,
};
}
}
class WhisperReportMessage extends WhisperMessage {
public readonly messageType: MessageType = MessageType.REPORT;
public constructor(data: Nameable) {
super(data);
}
public toJSON(): object {
return {
reportData: this.data,
};
}
}
class WhisperNotificationMessage extends WhisperMessage {
public readonly messageType: MessageType = MessageType.NOTIFICATION;
public constructor(data: Nameable) {
super(data, 3);
}
public toJSON(): object {
return {
notificationData: this.data,
};
}
}
class MessageService extends BaseMessageService {
public publish<T>(message: Publishable<T>): void {
super.publish(message);
}
}
// INSIDE A RANDOM OLD LISTENER
const newExternalMessage = new WhisperExternalMessage(dataReceivedByListener());
const newInternalMessage = new WhisperInternalMessage(dataReceivedByListener());
const newReportMessage = new WhisperReportMessage(dataReceivedByListener());
const newNotificationMessage = new WhisperNotificationMessage(dataReceivedByListener());
const newQueue = new Queue();
const newPublisher = new MessageService(newQueue);
newPublisher.publish(newExternalMessage);
newPublisher.publish(newInternalMessage);
newPublisher.publish(newReportMessage);
newPublisher.publish(newNotificationMessage);
console.log("QUEUE NEW STATE", newQueue.toArray());
/**
* QUEUE OLD STATE
(4) […]
0: "{\"externalData\":{\"name\":\"Carlos Alexandre\"}}"
1: "{\"internalData\":{\"name\":\"Carlos\"}}"
2: "{\"reportData\":{\"name\":\"Carlos Alexandre Pires de Carvalho Junior\"}}"
3: "{\"notificationData\":{\"name\":\"Carlos Alexandre Pires\"}}"
length: 4
<prototype>: Array []
main-3.js line 1239 > eval:106:9
QUEUE NEW STATE
(4) […]
0: "{\"externalData\":{\"name\":\"Carlos Alexandre\"}}"
1: "{\"internalData\":{\"name\":\"Carlos\"}}"
2: "{\"reportData\":{\"name\":\"Carlos Alexandre Pires de Carvalho Junior\"}}"
3: "{\"notificationData\":{\"name\":\"Carlos Alexandre Pires\"}}"
length: 4
<prototype>: Array []
main-3.js line 1239 > eval:173:9
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment