FRACTIONAL CTO · 16 MIN READ ·

Rails Technical Due Diligence: De Fractional CTO-Checklist voor Kopers en Investeerders

Rails technical due diligence checklist van een fractional CTO. Wat te auditen voor je een Rails-app koopt of erin investeert — code, infra, team, risico.

Rails Technical Due Diligence: De Fractional CTO-Checklist voor Kopers en Investeerders

Een boutique PE-firma uit Amsterdam belde me afgelopen maart op een dinsdag over een Rails-SaaS die ze binnen tien dagen wilden overnemen. De pitch deck van de verkoper claimde €4,2M ARR, 28 enterprise-klanten en “een moderne, schaalbare Rails 7 codebase”. De prijs was €18M. De PE-partner had twee vragen: was de technologie echt waard wat ze ervoor betaalden, en wat zou er in de eerste negentig dagen na closing kapotgaan. Ik gooide mijn agenda leeg, vloog de volgende ochtend naar Utrecht en bracht vier dagen door in hun staging-omgeving, hun GitHub-org, hun AWS-console en de hoofden van de vier engineers die het ding hadden gebouwd. We sloten op €13,2M met een escrow van €1,8M voor migratiekosten. Die vier dagen Rails technical due diligence bespaarden de koper €4,8M.

Na negentien jaar Rails-systemen bouwen en de laatste zes jaar als fractional CTO kopers, investeerders en oprichters adviseren, is technical due diligence de week werk met de hoogste hefboomwerking die ik doe. De prijs die je voor een softwarebedrijf betaalt, wordt bepaald door een spreadsheet. De kosten van het bezitten ervan worden bepaald door wat er daadwerkelijk in de codebase zit. Deze post is exact de checklist die ik gebruik, in exact de volgorde waarin ik hem doorloop, met de vragen die ik stel en de rode vlaggen die ik weiger te negeren.

Waarom Rails Technical Due Diligence Anders Is

Een standaard tech DD verloopt als een financiële audit: lees de code, tel de tests, vink hokjes af, schrijf een rapport. Dat geeft je een momentopname van het asset op de dag dat je ernaar keek. Het vertelt je niet wat het kost om te beheren, wat het kost om uit te breiden, of wat er gebeurt op de ochtend dat de lead engineer drie weken na closing zijn ontslag indient.

Rails technical due diligence moet vier operationele vragen beantwoorden, in volgorde van prioriteit: kunnen we het licht aanhouden, kunnen we de roadmap shippen, overleven we het wanneer het team verloopt, en tikt er iets dat in het eerste jaar gaat ontploffen. Alles in de checklist hieronder rolt op naar één van die vier vragen. Als een bevinding mijn antwoord op geen van die vier verandert, gaat het niet in het rapport. Kopers betalen mij niet om ze te vertellen dat de inspringing inconsistent is.

Ik werk ook anders dan een code-audit shop. Ik geef de engineers geen cijfer. Ik calculeer een transitie. Dezelfde codebase is een ander risicoprofiel afhankelijk van of de koper het oprichtersteam behoudt, het op een bestaand platform bolt, of het over twee jaar herbouwt. De checklist is hetzelfde, het oordeel niet.

Het Vierdaagse Schema Dat Ik Daadwerkelijk Draai

Ik draai Rails technical due diligence als een vierdaagse fixed engagement met een vijfdaagse optie voor complexe platforms. Dag één is toegang regelen, repo clonen en het interview met de senior engineer. Dag twee is codebase en infrastructuur. Dag drie is security, compliance en incidenthistorie. Dag vier is het team en het rapport. De vijfdaagse optie voegt een klantimpact-beoordeling toe die productanalytics, supportvolume en de top drie open tickets erbij trekt.

De deliverable is een rapport van vijftien tot vijfentwintig pagina’s met een executive summary van één pagina, een rood/oranje/groen-scoregrid over twaalf dimensies, een gecalculeerd remediatieplan voor alles wat rood en oranje is, en een aanbevolen prijsaanpassing. De exec summary is de enige pagina die de deal-partner zal lezen. De rest moet die ene pagina verdedigen.

Het Scoregrid van Twaalf Dimensies

Twaalf is geen magisch getal. Het is waar ik op uitgekomen ben na ongeveer zestig van deze trajecten. Elke dimensie krijgt rood, oranje of groen, elke bevinding krijgt euro-kosten om te herstellen, en de kosten rollen op naar één enkele prijsaanpassingsaanbeveling. De dimensies zijn: codebase-gezondheid, testdekking en betrouwbaarheid, Rails- en dependency-actualiteit, databaseontwerp en performance, security-positie, infrastructuur en deployment, observability en incidenten, third-party afhankelijkheden, IP en licensing, team- en kennisconcentratie, klantimpact-risico, en roadmap-haalbaarheid.

Ik loop hieronder door de zware. De lichte (IP, licensing) krijgen een paragraaf in het rapport als het schoon is en een sectie als dat niet zo is.

Codebase-gezondheid: Het Eerste Uur Vertelt Je Alles

Het eerste uur dat ik alleen met een repo ben, is het meest voorspellende uur van het hele traject. Ik clone de repo, draai bin/setup en klok hoe lang het duurt om een groene testsuite op mijn laptop te krijgen. Als bin/setup niet bestaat of niet werkt, is dat een gele vlag voordat ik één regel applicatiecode gelezen heb.

Daarna draai ik een reeks snelle metingen die ik in een klein scriptje heb geautomatiseerd. Aantal regels Ruby. Aantal modellen. Aantal controllers. Aantal background jobs. Gemiddelde lengte van controller-acties. Grootste model. Aantal # TODO- en # FIXME-comments. Aantal bestanden dat in twee jaar niet is aangeraakt. Aantal bestanden dat door precies één auteur is aangeraakt.

# script/dd_metrics.rb — draai tijdens due diligence
require "find"

stats = Hash.new(0)
single_author = []

Find.find("app", "lib") do |path|
  next unless path.end_with?(".rb")
  stats[:files] += 1
  stats[:lines] += File.foreach(path).count
  authors = `git log --format='%ae' -- #{path}`.split("\n").uniq
  single_author << path if authors.size == 1
end

stats[:single_author_files] = single_author.size
stats[:largest_model] = Dir["app/models/*.rb"].max_by { |f| File.size(f) }
stats[:todos] = `git grep -c "TODO\\|FIXME" -- '*.rb'`.split("\n").size

pp stats

Een gezonde mid-stage Rails-codebase heeft ergens tussen de 30.000 en 120.000 regels Ruby, een handvol modellen boven de 500 regels, een single-author-concentratie onder de 25 procent, en een bin/setup die op een schone machine werkt. Alles buiten die bandbreedtes is een vraag, nog geen probleem.

De echte rode vlag is de single-author-concentratie. Als 60 procent van de codebase ooit alleen door één engineer is aangeraakt, koop je geen bedrijf, je koopt een persoon. Dat verandert de hele dealstructuur. Je hebt retentiebetalingen nodig, je hebt een kennisoverdrachtsplan nodig, en je moet modelleren wat er gebeurt als ze toch in maand vier vertrekken.

Rails- en Dependency-actualiteit

Ik check vier dingen in deze volgorde: de Rails-versie, de Ruby-versie, het aantal verouderde gems met een achterstand van een major-versie, en of er iets in de Gemfile zit dat niet meer onderhouden wordt.

bundle outdated --strict
bundle exec ruby -v
grep '^ruby' Gemfile
cat Gemfile.lock | grep -A1 RUBY

Een Rails-app die twee minor-versies achterloopt is normaal. Drie is oranje. Vier is rood en wordt geprijsd. Een Ruby-versie meer dan één major achter end-of-life is rood — je koopt nu een security-migratie op dag één. Een Gemfile met meer dan vijf niet-onderhouden gems (geen commit in 24 maanden, geen release in 18) is oranje en krijgt een remediatiebudget.

Ik kijk ook naar de geschiedenis van upgrades. Een team dat succesvol van Rails 6 naar 7 naar 7.1 is gegaan, heeft laten zien dat ze het opnieuw kunnen. Een team dat sinds 2021 op dezelfde major-versie zit, heeft dat niet. De kosten van de volgende upgrade zijn veel hoger als niemand in het team er ooit één gedaan heeft. Dat reken ik mee.

Databaseontwerp en Performance

Hier vind ik de duurste verrassingen. Open een production-equivalente psql-sessie en draai een handvol queries: de grootste tabellen op rij-aantal, de grootste tabellen op disk-grootte, de indexen die nooit gescand zijn, de tabellen met een sequential-scan-to-index-scan-ratio boven 10:1, en de langstlopende queries in pg_stat_statements.

SELECT relname, n_live_tup
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC LIMIT 10;

SELECT indexrelname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC LIMIT 20;

Als pg_stat_statements niet aanstaat, is dat op zichzelf al een bevinding — ze draaien dit ding zonder query-level zichtbaarheid. Zet het een week aan en kom terug.

Ik zoek naar drie patronen. Ten eerste, een tabel boven 100M rijen zonder partitionering en zonder archiveringsstrategie — dat is een toekomstig incident met een bekende datum. Ten tweede, de top tien queries op totale tijd, inclusief elke ongebonden scan zonder LIMIT — dat is een geheugen- en timeout-probleem dat wacht op een verkeerspiek. Ten derde, ontbrekende migraties die het team met de hand op productie heeft gedraaid via psql-sessies — dat breekt de audit trail en je vermogen om het schema te reproduceren.

Migratieveiligheid en Deployment-risico

Ik lees de migraties van de afgelopen twee jaar. Ik zoek bewijs dat het team strong_migrations of een equivalent gebruikt, dat ze ooit een zero-downtime migratie op een niet-triviale tabel hebben gedaan, en dat er geen migratie in de geschiedenis is die een productietabel langer dan 30 seconden zou hebben gelockt.

# Een migratie zoals deze in de geschiedenis is een rode vlag
class AddIndexToOrders < ActiveRecord::Migration[7.1]
  def change
    add_index :orders, :customer_id
  end
end

Die migratie heeft geen algorithm: :concurrently, geen disable_ddl_transaction!, en op de orders-tabel van 80M rijen waar ik naar kijk zou hij de tabel 90 seconden hebben gelockt. Of het team had geluk, of ze hebben een outage gehad en niet gedocumenteerd. Ik vraag het.

Security-positie

Ik draai bundle audit, brakeman, en een handmatige scan op de gebruikelijke Rails-valkuilen: params.permit! in controllers, ruwe SQL met interpolatie, protect_from_forgery-uitzonderingen buiten de API-namespace, to_s op user-input dat zonder escaping in HAML of ERB gerenderd wordt, en system of backticks die op iets afgeleid van user-input worden aangeroepen.

Ik check authenticatie. Als ze het zelf hebben gebouwd, lees ik het. Ik check session-opslag. Ik check dat er geen secrets in de repo zitten (git log --all -S 'AKIA', git log --all -S 'BEGIN RSA', git log --all -S 'sk-'). Ik check dat de productiedatabase niet bereikbaar is vanaf het publieke internet. Ik check dat Rails.application.credentials daadwerkelijk gebruikt wordt en niet alleen een staging-only conventie is.

Alles wat ooit als secret in git-history heeft gestaan, is een rode vlag met vaste kosten — rotatie over elke klant en integratie. Als de codebase van vóór 2018 stamt en uitsluitend ENV-vars gebruikt, ga ik ervan uit dat er minstens één leak in iemands dotfiles heeft gezeten en prijs ik dienovereenkomstig.

Infrastructuur en Deployment

Ik wil de runbook zien die uitlegt hoe een nieuwe engineer voor het eerst deployt. Als die niet bestaat, zit de runbook in iemands hoofd en weten we nu in wiens. Ik wil zien hoe een rollback werkt, wanneer de laatste rollback plaatsvond, en hoe lang die duurde. Ik wil de boot-tijd van de productie-app zien — als het 90 seconden duurt om een worker op te starten, beperkt dat elke deployment-beslissing die de koper het komende jaar gaat nemen.

Ik check de CI-pipeline. Tijd tot groen op een gemiddelde PR. Kosten per maand. Flakiness-ratio over de laatste 200 runs. Een groene pipeline van 45 minuten is oranje en vertraagt het team met misschien 20 procent. Een testsuite met een flake-rate van 15 procent is rood en leert het team stilletjes om falende tests te negeren.

Ik check wat er daadwerkelijk in productie draait. De infrastructure-as-code repo zou moeten overeenkomen met wat er draait. Als terraform plan tegen productie een diff van 400 regels geeft, is de IaC niet de bron van waarheid en heeft het team handmatig in de AWS-console zitten klikken. Dat is een bevinding.

Observability en Incidenthistorie

De allerbeste vraag aan een engineering lead tijdens DD is “loop me door je laatste drie productie-incidenten heen”. Als ze diep moeten nadenken, zijn er óf geen incidenten geweest (onwaarschijnlijk voor een bedrijf met betalende klanten) óf er is geen incidentproces. Beide zijn bevindingen.

Ik wil error-rates in Sentry of equivalent zien. Ik wil de top tien errors op volume zien en hoe lang elk al afgaat. Een exception die zes maanden lang 40.000 keer per dag wordt gegooid, is geen error meer — het is een feature die het team is overeengekomen te negeren. Dat is een cultuurbevinding, geen codebevinding, en het vertelt je iets over hoe de engineering-org afwegingen maakt.

Ik check uptime-historie. Ik check de mean time to recovery. Ik check of er iemand on-call is en hoe die rotatie werkt.

Team- en Kennisconcentratie

Dit is de meest consequente sectie van het rapport en degene die kopers het liefst overslaan. Ik interview elke engineer minimaal 30 minuten, niet om ze een cijfer te geven maar om in kaart te brengen wie wat daadwerkelijk weet. Ik bouw een heat map van waar kennis zit. Als drie van de vier engineers “dat moet je aan Marcus vragen” zeggen als ik naar het billing-systeem vraag, is Marcus nu een key-person risk en heeft de deal een retentieplan voor hem nodig.

Ik vraag elke engineer ook twee dingen: wat is het onderdeel van het systeem waar je je het meest zorgen over maakt, en wat zou je anders bouwen als je opnieuw kon beginnen. Engineers vertellen in deze gesprekken de waarheid op een manier die ze niet aan oprichters vertellen. De gecombineerde antwoorden zijn de meest accurate roadmap van de komende twee jaar aan remediatiewerk.

Een nuttig gerelateerd stuk over waar je op moet letten bij een sterke engineer is de senior Rails engineer interview rubric die ik gebruik voor hiring — veel van dezelfde signalen gelden bij het beoordelen van een geërfd team.

Het Rapport en de Prijsaanpassing

Elke bevinding krijgt remediatiekosten in euro’s en een prioriteit — must-fix in de eerste 90 dagen, fix in het eerste jaar, fix wanneer het uitkomt, accepteer het risico. Ik tel de must-fix bucket op, vermenigvuldig met 1,5 voor uitvoeringsrisico, en dat is de prijsaanpassings-aanbeveling. De eerste-jaar bucket gaat in een operationele kostenprognose die de koper kan gebruiken om het post-close engineering-budget te plannen.

Op de Utrecht-deal waarmee ik opende, was de must-fix bucket €3,1M (Rails 5.2-upgrade, Postgres 11-upgrade, secrets-rotatie, vervangen van een zelfgebouwd billing-systeem dat drie maanden van breken af stond onder nieuwe EU-btw-regels). De uitvoeringsrisico-multiplier bracht het op €4,65M. De verkoper ging akkoord met €4,8M van de prijs af plus een escrow van €1,8M. Iedereen liep prima de deur uit. De PE-firma is nu twee jaar in eigendom en het platform heeft de omzet verdrievoudigd.

FAQ

Hoe lang duurt Rails technical due diligence?

Voor één Rails-app onder de 200.000 regels code is vier werkdagen van een senior fractional CTO genoeg om een betrouwbaar rapport te produceren. Multi-app platforms, microservice-opstellingen of apps met substantiële React- of mobile front-ends hebben doorgaans vijf tot zeven dagen nodig. Alles dat als een eendaagse audit wordt aangeboden, is een checklist-scan en zal de dingen missen die de prijs daadwerkelijk verschuiven.

Wat kost Rails technical due diligence?

Een vaste vierdaagse engagement in de EU loopt doorgaans van €12.000 tot €25.000, afhankelijk van platformcomplexiteit en hoeveel toegang de engineer moet achterna jagen. Dat is afrondingsverschil tegen een acquisitie van €5M+ en verdient zich standaard tien tot vijftig keer terug in prijsaanpassing of vermeden verrassingen na closing.

Wie zou technical due diligence op een Rails-overname moeten doen?

Iemand die persoonlijk minstens tien jaar productie-Rails heeft geshipt en gedraaid, die minstens vijf eerdere DD-trajecten heeft gedaan, en die onafhankelijk is van zowel de verkoper als elke vendor die de koper voor remediatiewerk zou kunnen gebruiken. Een fractional CTO met operationele ervaring produceert een nuttiger rapport dan een algemeen tech-audit bureau, omdat het rapport beoordeeld wordt op operationele beslissingen, niet op codestijl.

Kan technical due diligence een deal kelderen?

Ja, en dat zou ook moeten als de bevindingen het rechtvaardigen. Ruwweg één op de acht trajecten die ik draai eindigt in een aanbeveling om weg te lopen of de deal fundamenteel te herstructureren. De vaker voorkomende uitkomst is een prijsaanpassing en een gecalculeerd remediatieplan waar beide partijen vóór closing mee akkoord gaan. Het punt is niet om redenen te vinden om nee te zeggen — het is om er zeker van te zijn dat de koper weet wat hij koopt.

Overweeg je een acquisitie of investering in een Rails-bedrijf? TTB Software draait gestructureerde technical due diligence trajecten voor kopers, PE-firma’s en investeerders. Negentien jaar Rails, zestig-plus eerdere trajecten, vaste-prijs vierdaagse oplevering. Neem contact op voor je de LOI tekent, niet erna.

#rails-technical-due-diligence #fractional-cto-checklist #software-acquisition-audit #rails-code-audit #startup-due-diligence #investor-tech-review #tech-debt-assessment

Related Articles

Laatste sectie. Bel dan alsjeblieft.

Het is een telefoongesprek. Erger dan dat kan het niet worden.

Geen discovery-deck. Geen 45-minuten "kwalificatiegesprek." 30 minuten, jouw probleem, mijn mening. Als we een fit zijn weet je dat in minuut 12.

Directe lijn — Roger neemt zelf op
+31 6 5123 6132
Ma–vr, 09:00–18:00 CET · Nu beschikbaar

OF
info@ttb.software