SQL makes me uncomfortable.
Source: Dev.to
Introduction
In my working (not theoretical) understanding, object‑oriented programming is not merely an alternative to the traditional functional paradigm but often feels like a step ahead. I think of it as functional programming with state management. In practice, classes behave like functions with some inherent memory that lasts for the runtime of the program, making it possible to build better stateful abstractions that model real‑world logic and concepts.
When I tried React’s functional components, I instinctively thought of a webpage as a tree—parent components built from smaller ones, with the root being the final component to be displayed. Reusable components become analogous to abstractions such as interfaces or abstract classes in OOP. For these components to be meaningful, they must hold data, and the UI must update when the data changes. At this point, the components that hold and react to data feel analogous to the “stateful abstraction” interpretation of classes.
This is why it made a lot of sense to think of UI as an Object Tree. Traditional mobile UI frameworks reinforce this idea: Android with Java/Kotlin and iOS with Swift/Objective‑C model UI as hierarchies of objects. Why, then, did React abandon this model in favor of functional components, delegating state management almost entirely to the framework and giving developers far less explicit control?
The answer isn’t really about functions vs. objects; it’s about imperative vs. declarative programming. Declarative UI describes what the interface should look like for a given state, letting the framework handle how to achieve it. Modern mobile UI frameworks like SwiftUI and Jetpack Compose follow the same idea.
UI Frameworks: Imperative vs. Declarative
Traditional UI Kit (Imperative)
class CounterViewController: UIViewController {
var count = 0
let label = UILabel()
let button = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
label.text = "Count: 0"
button.setTitle("Increment", for: .normal)
button.addTarget(self, action: #selector(increment), for: .touchUpInside)
}
@objc func increment() {
count += 1
label.text = "Count: \(count)"
}
}
Modern SwiftUI (Declarative)
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}
React (Declarative)
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Similarities Between SwiftUI and React
| SwiftUI | React |
|---|---|
@State var count | const [count, setCount] = useState(0) |
count += 1 | setCount(count + 1) |
body | return (…) |
View (struct) | Function component |
| Recompute body | Re‑render function |
These parallels show how both frameworks let you declare the UI output and let the framework handle re‑evaluation when state changes.
Imperative vs. Declarative Programming
- Imperative UI: You describe how to build and modify the UI step by step (e.g., classic UIKit, old Android). This gives direct control but often leads to boilerplate, complex state management, and manual updates as the app grows.
- Declarative UI: You describe what the UI should look like for a given state. The framework determines the necessary steps to achieve that state, resulting in simpler, more readable code that reacts automatically to state changes.
Personal Discomfort with Declarative Paradigms
I experience a certain discomfort with this paradigm, similar to my unease with SQL and my preference for PyTorch over TensorFlow. The trade‑off is between explicit control and ease of implementation. Declarative abstractions make code less verbose and more elegant—TensorFlow’s model.fit() is a perfect example—but they also obscure when and how often code runs. Bugs become tied to state transitions rather than specific lines, making them harder to locate.
Declarative programming asks us to stop thinking like engineers issuing commands and start thinking like designers describing constraints. As a beginner in software, I don’t claim that functional components or declarative programming are inherently bad. They clearly work and are probably better suited for building systems at scale. For many developers, that is a price worth paying. For me, however, it remains an uncomfortable trade‑off. I can work within declarative systems and understand their value, but I still miss the loss of explicit control.