SOLIDna Architektura

Andrzej Kopeć
Czy w ogóle potrzebujemy wzorców projektowych? Zasad?
SOLID? A co to w ogóle jest?
Single Responsibility Principle
export class JSONFileConfigurationLoader {
constructor (fsp, configFilePath) {
this._fsp = fsp;
this._configFilePath = configFilePath;
}
getRaw () {
return this._fsp.readFile(this._configFilePath)
.then(JSON.parse);
}
}
import * as _ from 'lodash';
export class Config {
constructor (loaders) {
this._config = {};
this.readyPromise = Promise.all(loaders.map(loader => loader.getRaw()))
.then(rawConfigs => this._init(rawConfigs))
.then(_ => this);
}
_init (rawConfigs) {
_.merge(this._config, ...rawConfigs);
}
get (property) {
return _.get(this._config, property);
}
}
Liskov Substitution Principle
interface Uploader {
uploadData(data: Stream|Buffer|string, type: string): Promise<string>;
checkFile(filename: string): Promise<FileDescription>;
getAuthenticatedUrl(filename: string): string;
}
class S3Uploader implements Uploader {}
class FilesystemUploader implements Uploader {}
Interface Segregation Principle
interface Iterable {
Symbol.iterator: Iterator;
}
interface Collection extends Iterable {
entries(): Iterator;
values(): Iterator;
}
function forEach (collection: Iterable, callback: Function) {
for (let item of collection) {
callback(item);
}
}
Dependency Inversion Principle
interface Uploader {
uploadData(data: Stream|Buffer|string, type: string): Promise<string>;
checkFile(filename: string): Promise<FileDescription>;
getAuthenticatedUrl(filename: string): string;
}
class S3Uploader implements Uploader {}
class FilesystemUploader implements Uploader {}
function uploadData (uploader: Uploader, data: Stream|Buffer|string, type: string) {
return uploader.checkFile(data)
.then((fileDescription) => {
if (!fileDescription.exists) {
return uploader.uploadData(data, type);
} else {
return fileDescription.filename;
}
})
.then(filename => uploader.getAuthenticatedUrl(filename));
}
Po co w ogóle o tym mówię?
Jakość kodu ma wpływ na tempo rozwoju
Parę słów o historii projektu
Nasze decyzje
- Zaczynamy z samym frontendem
- Migracja na backend
- Ogłupienie frontendu
Ale kod to nie wszystko...
Jeszcze potrzebna jest architektura
Backend
- Service registry
- Moduły
- Fasada per moduł
- Kontroler per moduł
- Kontroler korzysta tylko z fasady
- Inne moduły korzystają tylko z fasady
- Moduły wraz z relacjami między nimi tworzą drzewo
Frontend
- Komponenty
- Service registry
- SRP
- "Lekkie" moduły definiowane przez główne komponenty
Efekty
- Kod łatwy w rozwoju
- Architektura umożliwiająca skalowanie
- Architektura ułatwiająca dodawanie nowych funkcji