Consulting, code reviews, small projects

.Invoke(Method)

Senior Software Engineer

24 years of .NET — UI, integrations, and the application layer between them. Industrial is where it got tested; enterprise is where it had to scale.

24 Years of .NET
15+ Major .NET versions
Fortune 500 Enterprise scale

// About

Twenty-four years of .NET. Industrial was the pressure test.

The work itself looks about the same regardless of domain: desktop or cross-platform UI, C# services behind it, and the integrations that connect everything to whatever the business already runs on. A lot of mine has landed in industrial — historians, HMIs, DCS — because that's where the demands stack highest. The engineering travels.

Currently Senior Software Engineer at Capstone Technologies (a Voith company), developers of dataPARC — a process historian and real-time analytics platform used across pulp & paper, oil & gas, chemicals, and power generation. Previously CTO at B-Scada.

What I care about, in order: separation of concerns, code the next engineer can read without a tour guide, and UI that doesn't leak memory or drop frames after it's been running for a week.

// Expertise

Eight areas I've spent enough time in to have opinions.

01

Frontend & Cross-Platform UI

Desktop UI on Windows, macOS, and Linux. WPF when the target is Windows-only, Avalonia or Uno when it isn't. Same XAML I was writing before Microsoft had a designer for it.

  • .NET
  • WPF
  • XAML
  • Avalonia
  • Uno Platform
  • XBAP
  • Silverlight
  • MVVM
  • Custom controls
  • Gestures
  • Dynamic UI
  • Windows
  • macOS
  • Linux
02

Backend & Application Logic

C# services, async pipelines pulling from multiple historians and enterprise systems at once, and the batching patterns that cut server load when clients ask for more data than the server expected. Not glamorous, but it's where most of the bugs live.

  • C#
  • Services
  • Async pipelines
  • Data clients
  • Historian aggregation
  • Call batching
  • Timers
  • Object models
  • Conversion pipelines
03

Enterprise & Industrial Integrations

The connective tissue between the control room and everything upstream — historians, DCS, HMI, MES, ERP, lab/quality systems, auth, and whatever the vendor is calling their API this year. My daily work at Capstone Technologies on the dataPARC platform.

  • dataPARC
  • PI Vision
  • ProcessBook
  • Proficy
  • IP.21
  • Honeywell
  • AVEVA
  • DeltaV
  • WinCC
  • IOTA
  • MOPS
  • OPC UA
  • OPC DA
  • OPC HDA
  • XML-DA
  • MQTT
  • PLCs
  • MES
  • ERP
  • LIMS / QMS
  • Keycloak
  • REST & APIs
  • SQL
  • Web Services
04

Infrastructure & Dev Tooling

Builds, workflows, local tooling, and the dev environment that keeps everything else working. Boring on purpose.

  • GitHub workflows
  • macOS / Linux
  • Launch services
  • Networking
  • Build tooling
05

Architecture & Performance

What I end up doing when things get slow, grow too big, or start behaving in ways nobody intended. Architecture, SoC, TDD, memory leaks, weak references, event-graph cleanup, XAML conversions, and WebAssembly perf.

  • Clean architecture
  • Separation of concerns
  • TDD
  • Legacy refactoring
  • Call batching
  • Memory leaks
  • Weak references
  • Event handling
  • Dashboard performance
  • XAML conversion
  • WebAssembly perf
06

Parser Pipelines & Language Tooling

Lexer, parser, transformer, divisor, emitter. I've used this pipeline to convert seven industrial graphic formats — IOTA, DeltaV, PI, ProcessBook, PI Vision, WinCC, MOPS — into XAML that renders in WPF, Avalonia, and Uno.

  • Lexers
  • Parsers
  • AST transforms
  • Code generation
  • DSLs
  • XAML conversion
  • Deterministic output
07

Real-Time Process Data & Analytics

The live-data layer that sits on top of historians and has to keep rendering while tags are still streaming in: dashboards, trends, KPIs, statistical process and quality control, smart alarms, predictive models and soft sensors, downtime tracking, batch analysis, and root-cause workflows. My day-to-day work at Capstone Technologies on the dataPARC platform.

  • Real-time dashboards
  • Trending
  • KPIs
  • SPC / SQC
  • Smart alarms
  • Predictive modeling
  • Soft sensors
  • Downtime tracking
  • Batch analysis
  • Root-cause analysis
  • Reporting
08

Time-Series Data & Historian Engineering

The storage and query layer under the dashboards — how tag data is stored, compressed, queried, and aggregated at scale. Tag metadata, batch contexts, calculated tags, backfill, and the compression that keeps decades of one-second data still queryable.

  • Time-series storage
  • Tag management
  • Compression
  • Query engines
  • Aggregation
  • Calculated tags
  • Batch data
  • Backfill
  • Historian APIs

// Selected work

A few specific things.

Anonymized where it has to be. Concrete otherwise.

01 Current

Shipping on dataPARC.

Current engineering work at Capstone Technologies (a Voith company) on the dataPARC platform — the real-time analytics and process historian layer used across pulp & paper, oil & gas, chemicals, and power. The work spans C# services, XAML UI, historian and enterprise-system integrations, and the visualization pieces that have to keep rendering while tags stream in. Ongoing.

02 XAML conversion

Seven industrial graphic formats, converted to XAML.

IOTA, DeltaV, PI, ProcessBook, PI Vision, WinCC, and MOPS — seven vendor formats with seven different opinions about how a display should be structured, all parsed and emitted as XAML that renders in WPF, Avalonia, and Uno. This is where the pipeline on card 06 came from.

03 Performance

Legacy codebases pulled back into shape.

Client-side render paths refactored for measurable performance wins. Server load cut by batching calls that previously ran per-item. Architecture restored to actual separation of concerns — the kind of cleanup where the diff looks small and the runtime doesn't.

04 Leadership

CTO, B-Scada.

Ran the development team building industrial SCADA software. Made the architecture calls, set the review standards, and was the one the team called when something broke in production. Twenty-four years of .NET includes the stretch where I was responsible for the people shipping it too.

05 Early XAML

Aurora XAML Designer — shipped before Blend existed.

Back when WPF was still codenamed Avalon, the company I worked at shipped Aurora XAML Designer — the first dedicated XAML designer on the market. Microsoft's Blend came later. I've since shipped on XBAP, Silverlight, WPF, Uno, and Avalonia. Microsoft has deprecated most of the early list by now. The code mostly still runs.

// Engineering principles

How I actually write code.

The rules I follow — not generic "clean code" advice, the specific things I won't compromise on.

code.md 01

Code

The code that ships is the rule. Style guides are the floor, not the ceiling.

  • Production code on the first pass — no pseudo-code, no TODO: implement, no sample-project scaffolding left in place.
  • Smallest change that fully resolves the problem. A fix that leaves the next bug obvious isn't complete.
  • var when the right-hand side already names the type. Explicit types only when they clarify intent the expression doesn't.
  • No comments. A comment is a symptom that the code's names aren't telling the reader enough.
  • Preserve existing behavior. If a refactor changes behavior, it isn't a refactor.
performance.md 02

Performance & allocations

The profiler tells you where to look. It doesn't tell you what to do.

  • Low-allocation first in hot paths. Every allocation is a future GC pause waiting to happen.
  • No LINQ in code the profiler touches. Deferred execution hides allocations an explicit foreach doesn't.
  • No closure captures, boxing, or intermediate collections in loops that run per tag, per frame, or per message.
  • Unfold the loop when in doubt. Readable beats clever; measured beats assumed.
strings.md 03

Strings & constants

A string the compiler can't see is a refactor the compiler can't help with.

  • string.Empty over "". Two ways to say the same thing is one too many.
  • No magic strings where the compiler could have helped — property names, event names, route keys, setting IDs, command names.
  • Named constants for tokens, keys, identifiers. If it appears twice, it's a constant. If it appears once and carries meaning, it's still a constant.
  • Strongly typed constructs — enums, records, nameof — over string-based coordination. The compiler catches what grep can't.
architecture.md 04

Architecture & SoC

Separation of concerns isn't a preference. It's what lets the rest of this list work.

  • Views don't know about storage. Storage doesn't know about validation. Nothing knows about more than it needs to do its job.
  • Layers named for what they do — parsing, orchestration, persistence, validation, presentation — each with its own place and its own tests.
  • Types named for their responsibility. Factories make, stores hold, orchestrators coordinate, transformers reshape, emitters output. Pick one.
  • If a component can't be tested in isolation, its boundaries are wrong. Move them.
mvvm.md 05

MVVM & UI

The view is the least important layer. That's exactly why it gets the least logic.

  • Binding over code-behind event wiring. Code-behind is a last resort, not a first tool.
  • ICommand for user actions. View-models expose intent; views wire it up.
  • Binding proxies when DataContext inheritance breaks down — which it will, in any non-trivial view.
  • Views handle presentation and interaction. Logic belongs in the view-model, and a unit test should be able to prove it.
lifetimes.md 06

Events & lifetimes

Lifetimes are the hard part of .NET. Treat them that way.

  • The object that subscribes owns the unsubscribe. Every += needs its matching -= on a lifecycle boundary — not "when convenient."
  • No delegates or callbacks living past the object that registered them. Memory leaks in .NET almost always come down to this.
  • Timers, subscriptions, long-lived references: deliberate setup, deliberate teardown. IDisposable when the lifecycle is explicit; weak references when it can't be.
  • Anonymous subscriptions only when the caller never needs to unsubscribe. If there's any chance you will, name the handler.
parsers.md 07

Parser pipelines

Pipelines with explicit stages beat monolithic parsers every time the input shape changes — which it will.

  • Staged pipelines: lexer → parser → transformer → divisor → emitter. Each stage does one job and owes the next stage a clean contract.
  • Explicit token models. Deterministic control flow. No input.StartsWith("…") sprinkled across layers — that's what tokens exist for.
  • Transformers are stateless. Explicit inputs, explicit outputs. A transformer that touches globals isn't a transformer; it's a bug.
  • Divisors partition, emitters output, parsers parse. If one type is doing two of those, it's doing one of them wrong.
testing.md 08

Testing

Tests describe the contract. If they don't, they're just slow.

  • Tests move when behavior moves. If the test doesn't change when the production code does, one of them is lying.
  • One production type per test file. MiscTests.cs is an anti-pattern — it means nobody knows where the test should live.
  • Test structure mirrors production structure: same namespace, same folder shape, same file name with a Tests suffix.
  • Unit, integration, parser, transformer, emitter tests kept distinct. Mixing them means the slow ones drag down the fast ones.
dependencies.md 09

Dependencies

Every dependency is a bet that the cost of maintaining it stays below the cost of writing it yourself.

  • .NET and the BCL already do more than most projects use. Add a dependency only when the platform genuinely can't — and you've verified it can't.
  • No third-party libraries without approval. Every one is a future supply-chain risk, a future breaking change, and a future licensing conversation.
  • Reuse what the repo already accepts before adding anything new. Two libraries doing the same job is a migration you'll be running later.

// How I work

How I actually work.

The stack is table stakes. This is the part behind it.

01

Root-cause debugging

I'd rather spend three hours figuring out why something broke than ten minutes making it stop. Logs, runtime behavior, framework internals, reproduction in isolation — whatever gets to the actual cause.

02

Architecture & SoC

Separation of concerns, responsibility boundaries, and thinking about who maintains this in three years. That person is usually me.

03

Performance & allocations

Allocation patterns, async behavior, rendering cost, startup time, WebAssembly limits — the things that quietly add up until someone files a ticket.

04

Enterprise XAML at scale

WPF, Uno, Avalonia, and the parts of XAML where bindings, dependency properties, gestures, and dynamic loading actually matter.

05

Systems integration

Getting UI, data, auth, APIs, add-ins, and vendor platforms to behave like one application. Most of the interesting bugs live between the boxes.

06

Pragmatic judgment

Smallest safe change most days. Full rewrite when the smallest change would be the fifth patch on the same broken pattern.

07

Ownership & follow-through

I pick up the things nobody else wants to touch and finish them. Work moves without being chased.

08

Cross-domain fluency

C#, XAML, WebAssembly, macOS services, build and dev infra. I don't need a specialist to make a decision in any of them. Currently poking at security tooling and local AI workflows for the same reason.

09

Clear communication

I can explain technical constraints to engineers, vendors, and non-technical stakeholders in ways all three can act on.

// Industries

Where this has actually run.

Not greenfield demos.

01

Oil & Gas

Operational tooling where every minute of downtime has a dollar figure on it.

02

Pulp & Paper

Process-heavy plants with historians, thousands of tags, and operator dashboards that can't afford to freeze.

03

Fortune 500

Review cycles, compliance sign-offs, and the kind of scale that makes every decision expensive.

04

Industrial Automation

HMI and SCADA integrations, and the application layer sitting on top of them.

05

Nuclear Energy

HMI and SCADA monitoring for nuclear operations — the kind of deployment where failure modes aren't theoretical.

06

Public Transit

Monitoring systems for rail and transit operations, including a subway deployment in South Korea. Uptime requirements that don't need explaining.

// Clients

Names I've shipped for.

Directly, through consulting, or via the platforms they run on.

  • Schlumberger Oilfield Services
  • Emerson Process Automation
  • Saudi Aramco Oil & Gas
  • Chevron Oil & Gas
  • Siemens Industrial Automation
  • Rockwell Industrial Automation
  • Yokogawa Process Automation
  • GE Industrial
  • AVEVA / Schneider Electric Industrial Software
  • Samsung Electronics
  • Areva Nuclear Energy
  • Matrikon OPC Platforms
  • ICONICS HMI / SCADA
  • Advantech Industrial Computing
  • Honeywell Process Automation
  • Mitsubishi Industrial Automation
  • Kepware OPC Platforms
  • General Dynamics Aerospace & Defense

// Contact

.Invoke(Me)

Consulting, code review, and small projects only — I already have a day job. If you're dealing with something hard in .NET, UI, or industrial integration — or something that used to work and doesn't anymore — send an email.

invokemethod@gmail.com
// build succeeded · 0 warnings · 0 errors