Clean architecture with Streamlit?

What are some examples of programming models that are similar to Streamlit?

My current strategy has been to store “view” controls in a separate module, and then just calling view.put_button_here() while behind the scenes I’m doing state.control = st.button(), and from anywhere else I call state.control whenever I need that state, and then I springle some old school layering on top, like a Repository class to clean up the data access.

Besides that I have really no idea what an ideal architecture should look like.

I don’t have much experience outside of Python. Would SwiftUI be a similar analogy to follow? Streamlit projects I’ve looked at are mostly teeming with “backend logic”, and really only have a slider and a graph on the frontend, so they don’t really have to deal with any of these issues.

2 Likes

Hey @komodovaran

Blockquote

I mean that’s sort of the whole point of Streamlit, isn’t it? Instead of having to implement design patterns like MVC within complex frameworks, you can just sprinkle a few Streamlit calls throughout your script and you’ve got an app. That’s the power.

However, I do think your question is interesting because I have also found myself asking, “where does it end?” How do I strike a balance between preserving the simplicity of what Streamlit was intended to accomplish, and not ending up with poorly-designed code? As much as I want to embrace the “Streamlit way”, if you’re working on a larger project it’s very easy to end up with a 500 line script, and that’s just not good practice.

What I’ve been trying out in the app I’m working on (code here), is somewhere in-between a single script and full-blown MVC: a separation of concerns by use of modules.

main.py
The script which is run. All Streamlit calls here. Acts a bit like view and controller combined. This is where the app is put together.

data_processor.py
All pandas stuff in here. Data cleaning and manipulation, building DataFrames etc.

data_scraper.py
API calls and data scraping done here. Async functions for speedier API calls in here also.

plotter.py
I style my plots here with plotly express. Not necessary if you’re not going to do any fancy plot styles.

For the most part, the latter three don’t talk to each other, except trough main.py.

I may add a text.py module too, to store long Strings that I write to the app in main.py.

I’m still getting a feel for it, but I think the question is pertinent. I’m worried that an unintended side effect of this paradigm could be poor code design.

If I work out a more general framework/structure for larger apps I’ll definitely share it!

1 Like

I mean that’s sort of the whole point of Streamlit, isn’t it? Instead of having to implement design patterns like MVC within complex frameworks, you can just sprinkle a few Streamlit calls throughout your script and you’ve got an app. That’s the power.

True true. But it’s also becoming a framework of its own as more features are added. It’s fast and tempting to create more and more complex applications, but like any project they end up becoming pretty messy without a more stringent measures :stuck_out_tongue:

For example, I like the separation of conerns in your example, but dislike how state must be massaged and managed around by the data_processor. It quickly blows up if you have e.g. several checkboxes and conditionals to manage.

I guess one could study some of the state-management philosophies associated with React, since it feels quite similar to Streamlit (without actually having used it, ever) :slight_smile:

1 Like

Good point, although I haven’t run into any difficulties yet. Think of data_processor.py - and all files except main.py - as a helper function module.

Any checkboxes and/or conditionals will be managed exclusively in main.py.