Wzorce organicznej architektury
Pamiętnik szaleńca
Kim jestem
work://chief_architect@lumesse
owner://symentis.pl
twitter://j_palka
blog://geekyprimitives.wordpress.com
scm:bitbucket://kcrimson
scm:github://kcrimson
Co społeczeństwo myśli o mnie?
Co moja żona myśli o mojej pracy?
Co ja tak naprawdę robię?
~ 8 firm w przeciągu 16 lat
~ 26 projektów
… i tylko jeden projekt budowany od podstaw ...
Jak się z tym czuje?
I am feeling I am feeling lucky!lucky!
Czego się dziś nie dowiem?
Która kombinacja wzorców, xDD, języków, frameworków i paradygmatów gwarantuje
sukces
Dowiem się za to jak nie oszaleć...
Pracując z monolityczną, odziedziczoną, masą kodu, który zbliża się do granic wytrzymałości,
by za chwilę zapaść się pod własnym ciężarem, tworząc czarną dziurę, która pochłonie
wszystkich żywych programistów w okolicy
We are living in a ...
Big Ball of Mud
Autogenerated StovepipeStovepipe Enterprise
JumbleStovepipe System
Cover Your AssetsVendor Lock-In
Wolf TicketArchitecture by Implication
Warm BodiesDesign by Committee
Swiss Army KnifeReinvent the Wheel
The Grand Old Duke of York
Co łączy te wszystkie przypadki?
Złożoność
Dowód?
„I fucking love science”
Myślenie systemowe
System dynamics
Teorie złożoności
Strange Attractor
The Gap
Jak organizacje sobie z tym radzą?
Może by tak zatrudnić więcej studentów?
Przepiszmy to wszystko...
(najlepiej w technologi i na platformę o której nie mamy zielonego pojęcia)
Dlaczego?
Czas?
Kilka „extra feature” na które wszyscy czekali?
Nadmierna wiara w siłę sprawczą technologii?
Projekty często postrzegane jak czysto techniczne?
Ignorancja?
Arogancja?
A może by tak?
The Gap
Wzorce organicznej architektury
Architektura to proces który ma na celu
transformację twojego systemu
Architektura to proces który ma na celu
transformację twojego systemu
Architektura to proces który ma na celu
transformację twojego systemu
Gap
↓
Context
↓
Constraints
You can't control what you can't measureTom DeMarco,
Controlling Software Projects,
You can't Reason about what you can't measure
Miara jakości architektury?
Complexity Resilience
Source code the truth will
tell you
Listen to the system
you must
SCM
Bug tracker
Continous integration
Static code analisys
Znajdźmy stabilne obszary systemu
# count complexity per each filefind . -iname jacoco.csv | xargs tail -q -n +2 | awk -F , '{gsub("\.","/",$2);print ($1"/src/main/java/"$2"/"$3".java"),$10+$11}' | sort > coverage.txt
# count number of changesecho 'changeset="{files}"' > files.style; echo 'file="\n{file}"' >> files.style
hg log --style files.style | sort | uniq -c | awk '{print $2,$1}' > changes.txt
# merge changes join coverage.txt changes.txt
Michael Feathers Quadrant
public enum Quadrant {
/* * * low complexity, little changes - simple utilities. * / tools,
/* * * simple yet frequently touched area of your code. Core of it, yet done well * and expanding. New features grow, new classes are extracted, complexity * is kept at bay. Keep it that way! * / breedinggrounds,
/* * * Ugly files but stable - written once for specific purpose, which they * fulfill well enough. High complexity makes them risky to touch, but is * there any need to? * * Ugly Stables also because of Hercules and Augias's stables... ;-) * / uglystables,
/* * * Code fitting here is fraught with complexity and changed often. Meaning, * you either didn't got the client's needs r ight and need to make lotsa * changes now, or you mis-designed and now have to work around it. * Or there's simply a number of bugs... * / designflaw
}
tools
uglystables designflaw
breedinggrounds
Znajdźmy kruche obszary systemu
#fetch all jobsjobs_rsp = requests.get("https://primitive.ci.cloudbees.com/job/roadrunner/api/python")#all builds urlsbuild_urls = [x['url'] for x in eval(jobs_rsp.content)['builds']]
pairs = []for build_url in build_urls: build = eval(requests.get("%sapi/python" % (build_url)).content) result = build['result']
changeSetItems = build['changeSet']['items'] if changeSetItems and not result == 'SUCCESS': affectedPaths = build['changeSet']['items'][0]['affectedPaths']
for i in itertools.permutations(affectedPaths,2): pairs.append(i)
counter = collections.Counter(pairs).most_common(5)for pair in counter: print pair
(('.../cli/CliConfigurationBuilderTest.java', '.../cli/RunTest.java'), 3)(('.../cli/RunTest.java', '.../cli/CliConfigurationBuilderTest.java'), 3)(('.../cli/CliConfigurationBuilderTest.java', '.../cli/BenchTest.java'), 3)(('.../cli/BenchTest.java', '.../cli/RunTest.java'), 3)(('.../cli/RunTest.java', '.../cli/BenchTest.java'), 3)
Czy ja to wszystko dobrze spakowałem?
Package principles
aka
Coś tu za chwilę wyleci w powietrze
(echo "<changes>" && hg log --template "<changeset>
{files % '<file>{file}</file>\n'}</changeset>\n"
&& echo "</changes>") > out.xml
+Neo4j
neo4j-sh (?)$ MATCH (a)-[c:`changeset`]->(b) RETURN labels(a),c.times,labels(b) order by c.times desc limit 5; +-----------------------------------------------------------------------------------------------------------+ | labels(a) | c.times | labels(b) | +-----------------------------------------------------------------------------------------------------------+ | [".../listeners/SummaryScenarioListener.java"] | 13 | [".../listeners/LoggingScenarioListener.java"] | | [".../listeners/LoggingScenarioListener.java"] | 13 | [".../listeners/SummaryScenarioListener.java"] | | ["pom.xml"] | 12 | ["roadrunner-core/pom.xml] | | [".../cli/BenchTest.java"] | 12 | [".../cli/RunTest.java"] | | [".../cli/RunTest.java"] | 12 | [".../cli/BenchTest.java"] | +-----------------------------------------------------------------------------------------------------------+
To gdzie te wzorce organicznej architektury?
Zasiej i pielęnguj
„aka” refactoring
kompulsywny „refactoring” to zło
unikaj „historyjek” typu „zrefaktoryzować X”
zanim zaczniesz, zastanów się czy warto
nie pytaj o pozwolenie, raczej proś o przebaczenie
nadaj „technical debt” znaczenie
„visual management”
wyznacz tylko kilka miar jakości
Tylko te które wspierają twoje cele
ponieważ
„You get what you measure”
Zasiej i zbierzZasiej i zbierz
„aka” modularyzacja
modularyzuj do stabilnych elementów systemów
zanim jednak zaczniesz ...
… zbuduj „framework” ...
Architektura to proces który ma na celu
transformację twojego systemu
… musisz mieć jasno określony cel …
… strategia dobrana do potrzeb i możliwości …
… daj sobie przestrzeń na zmianę zdania …
nie daj się znowu sparaliżować „big design (tm)”
… gdyż twój cel może się zmienić ...
co jeśli twój „big design (TM)”
wyglądałby tak...
procesy wsadowe (batch) odseparowane
moduły komunikują się ze sobą asynchronicznie
Użytkownicy widzą system jako jedność
i komunikują się synchronicznie
Jedyne co współdzielimy w systemie to mentalny model
mvn clean install < 60 sekund
Każdy moduł musi dziedziczyć kontekst i ograniczenia
Może też wprowadzać specyficzne, lokalne ograniczenia w kontekście poszczególnych
modułów
Kompostowanie
Czasami mimo wysiłków, pracy...
i szczerych chęci
Którymi piekło jest wybrukowane
Complex
ity
Czy wiesz jak twoi użytkownicy korzystają z systemu?
Czy wiesz że twój „kluczowy” klient nie korzysta już z systemu od 5 lat?
Czy wiesz że „killer feature” nie zachwycił rynku a ty ciągle utrzymujesz ten kod?
Skąd ja mam to wiedzieć?
/var/log/httpd/access.log
Zinstrumentuj kod?
Aspekty?
Byteman?
Bug tracker?
Ludzie z utrzymania?
Nie inwestuj w drogie narzędzia
Będziesz czekał miesiącami na „approval”
A potem narzędzie i tak zawiedzie twoje oczekiwania :)
Zainwestuj w kreatywność
Tylko proszę bez „wykomentowania” kodu
Twój SCM będzie pamiętał
… po prostu wyrzuć to...
Czas podsumowań
Hierarchy
↓
Self-Organization
↓
Resilience
System's resilience is often sacrificed for purposes of
short-term productivity and stability.
Productivity and stability are theusual excuses for turning creative human beings
into mechanical adjunctsto production processes.
Or for establishing bureaucracies and theories of knowledge that
treat people as if they were only numbers.
Donella Meadows, thinking in systems a primer
Dziękuję!!!