Republic of Türkiye Ministry of Interior — Digital Forensics Software Engineer
2019–Present
Since 2019 — High-volume and real-time digital-forensics, AI and large-scale software systems spanning Java/Spring, Oracle, C/C++, Python, ASR, image/face processing, reverse engineering and performance engineering.
Since 2019, I have worked as a Digital Forensics Software Engineer at the Republic of Türkiye Ministry of Interior. This is the professional period in which my earlier experience in robotics, embedded systems, computer vision and performance engineering converged with high-volume enterprise systems that run continuously and include real-time requirements.
My work spans digital forensics, artificial intelligence, large-scale data processing, speech and audio technologies, image processing, reverse engineering, relational data systems and performance engineering. Java/Spring Boot, C/C++, C#/.NET and Python are the main development environments I use at different layers, together with Oracle-centered relational systems, Linux and performance-sensitive native components.
Public professional descriptions omit internal project names, code structures, schemas/tables, datasets, server or network topology, authorization models, operational rules and distinguishing security details. The sections below therefore stay at the level of public-safe problem classes, engineering methods and my own technical scope.
Large-Scale Enterprise Software Systems
I develop high-volume backend and service software with Java and Spring Boot. The difficult part of these systems is rarely just accepting an HTTP request and writing a row. Concurrent workload, multiple data sources, long-lived services, recovery after failure and low user-visible latency have to be considered inside the same architecture.
A component being fast in isolation is not enough. Optimizing CPU code has little effect while requests wait for database connections. Adding threads can make the situation worse when file I/O or another bounded resource is already saturated. Small application-level optimizations may be invisible when network delay dominates.
I therefore treat the system as a measurable end-to-end processing path. Design decisions are evaluated through latency, throughput, concurrency, resource bounds and failure behavior.
Real-Time and Long-Running Services
For a real-time system, "fast" is not a sufficient requirement. Work has to complete within a predictable time and the system has to preserve acceptable behavior under sustained load.
Long-running services expose problems that short benchmarks often hide: connection-pool saturation, gradual memory growth, unbounded queues, thread starvation, retry storms and temporary failures in dependencies propagating across the service.
I avoid architectures that implicitly assume resources are infinite. Queues, connections, threads and parallel work require explicit capacity limits. As saturation approaches, the system should provide controlled backpressure and contain failures as locally as possible.
Reliability does not merely mean that the process has not crashed. A service can remain alive while queue age grows continuously, user requests time out or background data accumulates faster than it can be processed. Operational stability has to be measured.
Java, Spring and Concurrency
In Java/Spring services I do not leave the concurrency model entirely to framework defaults. CPU-bound versus I/O-bound work, transaction duration, connection-pool capacity and the amount of useful concurrent work have to be evaluated together.
Increasing thread count does not automatically increase capacity. When the bounded resource is the database or an external service, more concurrency can simply create a longer queue.
I use current Java concurrency mechanisms, traditional pools and, where appropriate, virtual-thread approaches according to the workload. The technology comes after a more important question: which resource is actually bounded and where does the system wait under load?
Concurrency failures are not limited to classic race conditions. Starvation, lock contention, timeout chains and unnecessary context switching can also shape system behavior. Adding a lock may be correct, but its holding time and waiting population still need measurement.
Oracle, Data Access and Transaction Boundaries
Long-term work with Oracle-based enterprise data systems made it clear that a large portion of application behavior is determined by data access.
A SQL statement must do more than return the correct result. Execution plans, index use, cardinality estimates, row volume, transaction scope, locking and the amount of time a connection remains occupied all matter.
An ORM or repository layer does not remove that cost; it only abstracts it. I therefore evaluate Java-side entity and query behavior together with Oracle's actual execution model.
Oversized transactions can extend lock and connection occupancy. Transactions that are fragmented too aggressively can break atomicity and business consistency. The correct boundary follows the real unit of work rather than a framework habit.
Production data also has to be treated as it actually exists. Duplicate or historical records cannot simply be dismissed because an ideal schema would prevent them. Reading, ordering, deduplication and failure behavior have to reflect the real data contract.
Connection Pools and Capacity Management
Connection pools are a critical capacity boundary in high-traffic systems. A larger pool does not create more database capacity and can increase contention by allowing more simultaneous SQL execution. A pool that is too small creates avoidable application-side waiting.
I therefore evaluate pool size together with transaction duration, query latency, concurrent work, database capacity and failure behavior.
Pool saturation also has to be observed together with application threads. When a bounded resource is exhausted, explicit timeouts and controlled failure are more reliable than indefinite waiting.
A high active-connection count is not automatically a problem. The more useful indicators are waiting work, operation duration and the database's actual ability to serve the offered concurrency.
Performance-Sensitive Processing in C and C++
For dense data, signal and media processing, I use C and C++ where more direct control over memory, SIMD, parallel execution or native libraries is justified.
Algorithmic complexity is the first performance question. After that come memory access, allocation, copying, cache behavior and parallel scheduling.
An optimization is applied only after the bottleneck is measured, the change is isolated and the system is measured again without compromising proven behavior.
A low-level loop optimization is irrelevant when upper layers copy the same data repeatedly. Likewise, vectorizing a function that occupies only a small fraction of total execution time may not change user-visible latency. This is the practical meaning of Amdahl-style reasoning.
IBM POWER9, SIMD, OpenMP and CUDA
I have worked with heterogeneous computing and different processor architectures for performance-sensitive digital-forensics and AI workloads. My IBM POWER9 AC922 work is one public example where CPU-side AltiVec/VSX and OpenMP were evaluated together with CUDA/Tesla V100 acceleration.
The useful question is not simply "CPU or GPU?" Data size, vectorization opportunities, memory bandwidth, transfer cost and other concurrent work all influence the answer.
Some workloads benefit strongly from a GPU. Small or irregular operations can have lower end-to-end latency on the CPU. I select the compute path according to the structure of the algorithm rather than the prestige of the hardware.
Compilation and dependency behavior also matter across architectures. A native component that works on x86 should not be assumed to behave identically on ppc64le or another SIMD target. Compiler, ABI, library version and platform capability are part of production behavior.
Artificial Intelligence Is Not a Model File
Production AI work includes data preparation before inference and result handling after it, together with queueing, validation, resource sharing and failure management; the model is one component of the larger system.
A strong model can still produce poor system behavior when preprocessing is inconsistent. Fast inference does not help when requests spend most of their time waiting in a queue. Efficient GPU execution can still be throughput-limited by CPU preprocessing.
For that reason, AI components are measured as part of an end-to-end data pipeline. Model latency is not end-to-end latency, and model throughput is not necessarily system throughput.
A model update can also change behavior through preprocessing, tokenization or runtime differences even when the API stays the same. Model and data contracts therefore need compatible versioning.
Automatic Speech Recognition
Automatic speech recognition has been one of my long-running technical areas. Sending audio to a model and receiving text is only a small part of a production ASR system.
Format validation, channel handling, sampling, voice activity detection, segmentation, inference, timing information, result merging and error handling have to cooperate.
Segment boundaries directly affect quality and latency. Very short segments lose context; excessively long segments increase waiting time and memory use. A few hundred milliseconds in speech endpointing can become user-visible latency.
My public notes on Whisper architecture and speech recognition focus on model and algorithmic concepts, while my production work also treats segmentation and system behavior around the model as first-class problems.
Real-Time Factor, Queueing and Capacity
RTF is useful for ASR performance, but it is not identical to system capacity. RTF < 1 may show that one stream is processed faster than media time. Under concurrent load, queueing, GPU sharing, CPU preprocessing and I/O determine sustainable capacity.
I therefore separate media duration from processing duration and do not confuse inference time with user-visible end-to-end latency.
A faster model can consume more memory and reduce the number of workers that fit on the same hardware. System-level decisions come from total capacity and latency objectives, not from a single inference benchmark.
Queue length is also incomplete without age. A queue can appear stable while long-running jobs are repeatedly delayed. Real-time and historical work placed in the same unbounded FIFO can allow backfill to increase latency for current data.
Speaker Recognition and Audio Processing
My work also includes speaker recognition, speech enhancement and general signal processing.
For speaker recognition, embedding quality is only one variable. Segments must contain the intended speaker, include enough speech and be evaluated with channel and noise conditions in mind. Bad segmentation can invalidate even a strong matching model.
Audio enhancement also has to preserve the information required by downstream ASR or forensic algorithms. An output that sounds cleaner to a human listener is not automatically a better model input.
Sampling rate, channel layout, PCM representation and time reference need explicit contracts between processing stages. If different layers compute time independently, segment and playback alignment errors appear.
Image Processing and Face Recognition
Image processing, face detection and face recognition are also part of my professional work. I evaluate detection, alignment, feature extraction/embedding, similarity and decision thresholds as separate stages.
Benchmark accuracy alone does not describe the behavior of a face-recognition system. Image quality, face size, pose, illumination, detector errors and threshold selection all influence the final result.
Similarity search is also a systems problem. Search speed has to be considered together with recall, memory use, update cost and concurrent query behavior.
False-match and missed-match costs are not always symmetrical. Threshold choice follows the operational error model rather than one universally optimal number.
Data Preparation and Media Processing
In AI systems, data preparation often consumes significant resources outside the model. Audio/video decoding, channel conversion, resampling, frame extraction, scaling and normalization consume CPU and I/O.
In Python pipelines built around tools such as FFmpeg, OpenCV and native libraries, I try to reduce unnecessary conversion and copying. Re-decoding the same media or repeatedly writing temporary data to disk can dominate throughput.
The choice between streaming and loading complete objects into memory is also explicit. For large media, bounded buffers can improve both memory predictability and failure recovery.
Digital-Forensics Data Processing and Provenance
In digital forensics, the result of an algorithm is only part of the engineering requirement. The relationship between input, transformations, intermediate data and output should remain traceable.
"Same file, different unexplained result" is difficult to accept in forensic software. When an algorithm or model is nondeterministic, its limits, version and parameters need to be explicit.
Data integrity and reproducibility are therefore production design criteria, not only academic concerns.
Provenance should not mean duplicating sensitive data unnecessarily. Traceability and data minimization have to be designed together.
File Carving and Custom Formats
My work includes file carving, binary structures, custom file formats and data recovery.
Simple header/footer scanning is not always enough. Fragmentation, false positives, large files, integrity checks and structural validation inside the format can matter.
For undocumented formats, useful analysis often comes from comparing multiple samples, observing the producing application's behavior and testing hypotheses about changing byte regions.
Parsers also have to expect malformed or deliberately adversarial input. Blindly trusting length fields can lead to uncontrolled allocation or out-of-bounds behavior.
Reverse Engineering
My reverse-engineering work includes static and dynamic software analysis, data-format and protocol analysis and, when required, reimplementing observed behavior in another language or runtime.
The goal is not always to completely decompile a binary. Often the practical requirement is to determine what output a given input produces, how data is encoded or which fields make up a protocol message.
Behavior-oriented analysis can be more effective when integrating with legacy or undocumented systems.
Test vectors are especially important when reimplementing observed behavior. Comparing old and new outputs for the same inputs provides evidence that the relevant contract has been preserved.
Network Traffic and PCAP Analysis
PCAP and network-traffic analysis form another part of forensic and reverse-engineering work. I treat packets as flows, sessions and message structures rather than isolated rows in a protocol analyzer.
Standard protocols can be compared with their documentation. Custom protocols require inference from recurring fields, lengths, sequence values and request-response relationships.
The capture point and timing are part of the evidence. A packet not being visible in one capture does not automatically mean that it was never transmitted.
For very large captures, materializing every packet as an in-memory object can be the wrong design. Streaming and indexed access may be necessary for the analysis to scale with file size.
Cryptology and Secure Data Processing
I work with cryptographic hashes, encryption, authentication and access-control mechanisms. Security is not a feature added after the data path has been designed.
A hash is not encryption. Encryption alone does not guarantee integrity. Authentication and authorization solve different problems. Keeping these boundaries explicit prevents systems from being described as secure while using the wrong primitive.
Keys, secrets and identifying institutional security mechanisms are not included in public descriptions.
Secure processing also includes secondary channels such as logs, error messages and temporary files. Encrypting the main data store is insufficient if debugging output exposes the same sensitive content.
Reliable Failure Handling and Retry
In distributed and database-oriented systems, not every error is retryable. Network failure, timeout, explicit transaction rollback, validation failure and authorization denial require different policies.
For writes, an ambiguous result can make blind retry unsafe because the first attempt may already have produced a side effect. Idempotency, operation identifiers, bounded retry, backoff and total time budgets therefore belong to the failure model.
I discuss these ideas in public technical writing on safe retry design in critical systems.
Retry does not create capacity. When a dependency is saturated, additional attempts can increase queue and connection pressure. Retry, backpressure and circuit-breaker-style protection therefore belong to the same failure strategy.
File Systems, NFS and Atomic Publication
For long-running data-processing systems, file-system behavior is part of application architecture. A file name becoming visible does not prove that all data is durably stored, and local filesystem semantics do not automatically map to NFS.
Temporary-file publication, flush/sync, rename and directory durability matter when another process can consume the output.
I discuss these general issues in my public article on atomic file publication, without exposing internal directory structures or operational layouts.
Publication semantics also interact with idempotency. A repeated job needs a defined policy for target files, and consumers should not observe partially written output.
Observability and Measurement
More logging does not automatically create observability. Each metric should answer a system question.
Latency distributions, throughput, queue depth, connection wait time, error class, saturation and processing duration are examples of measurements I use to explain behavior. Averages alone can hide tail latency and short periods of saturation.
Logs also have confidentiality constraints. Sensitive or personal data should not be emitted merely for debugging convenience.
Observability itself has a cost. Excessive hot-path logging or uncontrolled high-cardinality metrics can create a new performance problem while attempting to measure the old one.
Deterministic and Reproducible Behavior
For critical systems, the same input should produce the same result and side-effect model whenever practical. Concurrency, randomness, time dependencies and external services can make that difficult.
Deterministic ordering, explicit timeouts, bounded retry, idempotency and version tracking therefore become part of design.
Absolute determinism may not be possible for every AI component. In that case, the nondeterministic region and the acceptable tolerance should be known rather than ignored.
Testing also has to include failure paths: timeouts, partial inputs, duplicates, resource saturation and restart behavior. Critical-system reliability cannot be inferred from the happy path alone.
Balancing Performance and Reliability
The fastest isolated implementation is not always the best production design. An optimization can improve throughput while increasing memory footprint or failure blast radius.
For me, performance engineering means making system behavior more predictable under expected load, not merely winning a benchmark. Latency, throughput, resource use, failure behavior and maintenance cost have to be considered together.
Unnecessary abstraction or allocation is removed from hot paths when measurement supports it, without trading proven correctness for an unmeasured micro-optimization.
In critical systems, a deterministic and understandable implementation can be more valuable than a marginally faster alternative with uncertain operational behavior.
Pragmatic Technology Selection
Java/Spring Boot, C/C++, C#/.NET and Python serve different parts of the system according to runtime, integration and performance requirements.
Java is strong for large enterprise services and concurrency. C/C++ provides control for native and performance-sensitive processing. Python is productive for AI and data workflows. C#/.NET remains useful for analysis, desktop and user-facing tools.
The engineering objective is to combine them across as few boundaries as necessary while controlling data copies and operational complexity.
A technology should be selected because it fits correctness, performance, maintenance and operations, not simply because it is newer.
Relationship with Academic and Technical Writing
My professional work and technical writing are connected without exposing internal systems. In public articles I generalize recurring production engineering problems into reproducible examples and support version-dependent claims with technical sources.
My academic work on speech, image and audio processing, the Image and Audio Processing book chapter, and my graduate work in digital forensics and cybersecurity address the same problem space from research and educational perspectives.
Academic sources explain mechanisms and boundaries; production experience reveals which assumptions fail under real data, sustained load and operational constraints. I try to use the two forms of evidence without conflating them.
Confidentiality Boundary
I do not publish internal project names, exact operational figures, datasets, schema or topology details, or identifying security information. The underlying engineering can still be described through the problem class, data flow, failure model, measurement method and the generalizable design decision.
When I generalize a public example, I remove identifying detail rather than replace it with invented detail. This keeps the engineering behavior intact without disclosing information that would identify a protected system.
Engineering Approach
Although the languages, models and infrastructure have changed since 2019, my troubleshooting method has remained fairly stable. I start with an observable symptom, measure where the bottleneck or failure boundary actually is, change as few variables as possible, and compare the result again.
The same discipline applies to an Oracle query, an ASR queue or a GPU kernel. For production work, I treat an optimization as useful when it makes the system more predictable without weakening behavior that has already been proven correct.