Software Architecture Suggestion: API + Web UI instead of Razor

It’s the simplest possible way to build a site, that works in the widest variety of situations, and IMO should absolutely be the default for all new projects, even in 2020.

10 Likes

We can use Razor pages along with an API.

Personally I’m a fan of having an API, but don’t think we need to scrap Razor pages

1 Like

In that regard, some of our messages in mid-October from the #programming-general channel…

The following quotes are all mine except where otherwise noted; follow links at the end for context and surrounding discussion.

In my opinion, one of the main reasons SO/SE works so well, runs fast and with a very small bug/annoyance count, and was developed/is maintained in a timely manner, was due to their choice of tech stack.

They run ASP.NET C#, Microsoft SQL Server, with queries through Linq to SQL. The front end is Razor Pages, if I’m not mistaken, with custom JS and Jquery as needed.

I would like to propose we keep as faithful as possible to their choices.
But in order to reduce server costs, my choices would be:

  • ASP.Net Core (C#)
  • Entity Framework 6.3 (in the near future, Entity Framework Core, if it works well enough and support seamless many-to-many relationships as well as a few other pain points that I’m unhappy with right now)
  • MariaDB as the RDBMS, even though I do prefer Microsoft SQL Server, it is unfortunately expensive
  • At some point, optimize critical points with MongoDB, ElasticSearch or similar.

What I would be very wary of, personally:

  • PHP
  • NodeJS
  • React, Angular, -some other fancy, “no true HTML” JS framework

(https://discordapp.com/channels/634104110131445811/634374616646811648/634446406521978905)

SPAs are just not how the web is supposed to work.

Think HTML (and HTTP[s]) etc

the H stands for Hypertext

One document leads to another

That’s how browsers have been made to work since their inception, and it works fine enough.

SPAs subvert this core principle
And this leads to all sort of weirdness across various domains, much more than I’d be willing to go over in here.

Anyway, they do have their place. But those applications are very specific.

(https://discordapp.com/channels/634104110131445811/634374616646811648/634477620632879114)

The web has evolved, many things are different to when I started, it used to be that browsers were a viewer only. but now they run an application sandbox

@staticvoid (https://discordapp.com/channels/634104110131445811/634374616646811648/634477993133342730)

Ok I see the validity of that argument, but still, HTML, CSS and JS have well-defined purposes to this day and web applications work much better when separation of concern (w.r.t these purposes) is respected.

Take AngularJS for instance. Sure, it works. I use a couple of sites made on it.

But I don’t enjoy using them. It’s non-natural from the browser point of view, and they behave “clunkily”

(https://discordapp.com/channels/634104110131445811/634374616646811648/634478976781516802)

6 Likes

Keeping a bit off the original topic but for good reason, I should also point out that this sort of discussion has spawned in Discord a few times (and, I suspect, will continue to), as well as in a few places here in our forums. There is even a closely related thread - Considerations about the tech stack and architecture. If you refer to post #21, I had this to say:

Also adding a relevant quote from @MasonWheeler from I have an SE clone. How do we feel about building on that? :


The older project members voted for/against an SPA approach

And for electing a tech stack:

Again, just to reinforce: Many of the collaborators who voted for C#/ASP.NET Core are (or were) NOT entirely familiar with that stack. The voting, and the decision, was made after very thoughtful discussion in our chat server, where arguments were proposed and evaluated for a few days’ worth.

These were educated decisions (obvious disclaimer, I campaigned for them myself - but that was way before being elected tech lead), and reverting them at this point must be done with at least equal amount of care, if not more (actually, more, for reasons Art has stated).

6 Likes

Just to clear my mind about something I never saw discussed, has the operational experience been taken in account or only the developer side ?

Keeping something live running has its own challenges and the the learning curve is often more steep than for coding.

I’m asking it openly as I’ve seen the point discussed extensively on the code side but not much on the “run” side and I’ve no idea how the team feels about maintaining a live system in .net core, so this may serve as historical data on this question.

2 Likes

If I have a statically-typed system that declares the type of a function’s arguments etc.

Yes but that’s a false dichotomy IMO.

Because when I tried my “prototype of StackOverflow using React.js”, then I used TypeScript rather than JavaScript.

It’s compatible with and compiles to JavaScript – and I like it much better than JavaScript (also better than using Google’s closure compiler)

  • For defining the signatures of functions and especially during any refactoring (e.g. during incremental development)
  • For defining data i.e. the elements of an object (an object type or interface, e.g. to define what page data elements are retrieved via an API, i.e. the input data to the rendering code which creates the DOM).

The debugger is widely acclaimed and the IDE offers more-than-decent refactoring tools.

I used VS Code (with Google Chrome), the “debugging” experience seemed to me perfect – and the IntelliSence. There’s even no explicit compile step IIRC, the compiler and loader are doing automatic incremental compilation and reloading, so it’s immersive (and the VS Code UI isn’t too cluttered but is full-featured and quick, I like that too).

Another benefit (of JSON plus client-side rendering) is integrating the code which updates the page when an update is received (pushed from the server), which is necessarily on the client, with the code which creates the page in the first place.

Your (i.e. “you” plural) other objection here to JSON plus client-side rendering was wanting to support browsers whose users have disabled JavaScript. A potential fix for that was “universal” code which runs the same code-base on the server and/or in the client. And running a browser without JavaScript seems to me for luddites anyway (and perhaps some of the dumber bots too), and the UI they want is simpler (like “static” HTML, maybe fewer links, maybe read-only access to the site).

Aaah, so you are ChrisW on Discord. I had a hard time trying to find that implementation you did, but now I got it.

Valid point there and I certainly agree with you on TypeScript.

I used VS Code (with Google Chrome), the “debugging” experience seemed to me perfect – and the IntelliSence. There’s even no explicit compile step IIRC, the compiler and loader are doing automatic incremental compilation and reloading, so it’s immersive (and the VS Code UI isn’t too cluttered but is full-featured and quick, I like that too).

I haven’t, but great to know the experience is seamless. Might try it sometime. That aside, and in any case, I’ve yet to find anything that comes even close to the VS 2017/2019 C# debugger. Even more so with IntelliTrace and now this new feature called Time Travel Debugging, but these are luxury available only in the Enterprise edition so I don’t get to use them day-to-day.

(…) A potential fix for that was “universal” code which runs the same code-base on the server and/or in the client. (…)

I remember @DoctorJones proposing the same idea! Not sure if here or on Discord.

2 Likes

It was here, and here. I wasn’t really proposing it, just explaining the concept. Although I do think isomorphic rendering is highly desirable, the point is moot if we’re not developing a SPA.

1 Like

IIRC I did something like this – https://www.google.com/search?q=create-react-app+typescript

Some of the magic is in CRA, reloading into the browser when the source is changed, and some of it is in VS Code, incrementally recompiling when the TypeScript is edited.

Cool. Well I was wondering how they made that fast enough – then I read, “You can expect about a 10x-20x performance hit in typical recording scenarios”, so perhaps that explains that.

Some software I wrote previously couldn’t support a debugger – hard-real time, live systems, and embedded systems. I do like a type-safe language, so “debugging” happens before the software is run (not to mention logs).

There’s an apocryphal story, of Richard the Lion Heart’s comparing swords with Saladin – the English king in all his armour demonstrates that his sword can break an iron bar – to which, Saladin tosses a bit of silk in the air, and slices that in two with his sword.

The debugging with VS Code (of code running in the browser) seemed good enough – like Chrome’s built-debugger (which VS Code was presumably using, headless), breakpoints and the call stack and watching variables – except happening in the VS Code window, and mapped to the TypeScript source code.

And I found it’ll do, for debugging Node.js code too.

1 Like

I see your point.

But now, do you have an idea how well that works with Blazor?

It’s C# compiled to webassembly. So it’s faster than JS AND all the (usually JS-) interactivity can be done in C# - and as such, it can directly use the domain model classes (preventing a bunch of conversion errors during dev).
Honestly, my mouth is watering a bit at the thought of what they’re doing with Blazor, but the problem is always that browser support for webassembly is… well, pretty good already, but not enough yet.

Now with that though of isomorphic rendering, in combination with template inheritance in razor, I see quite the potential there.

1 Like

Isomorphic rendering isn’t supported in Blazor yet. Their server only and client only modes are very different, and work in completely different ways, which IMO is a mistake. We will just have to wait and see what direction it goes in, but yeah, I love Blazor, it has loads of potential.

1 Like

Just tuning in… I also think that a SPA with isomorphic rendering is the way to go nowadays. My choice of client-side library would be React (or a clone thereof), since it provides a solid experience and also does support isomorphic rendering.

Also, as for client-side development, using TypeScript (without Babel) en lieu of JavaScript + Babel would also be my choice. It adds a lot in terms of coding experience, code correctness and maintainability, so if there is a JS transpiler in the build anyways (e.g. Babel), then why not directly opt for TS instead of Babel?

We are using a similar tech stack (.NET with C# server, REST API, TypeScript with corejs on the client, SPA with React, and also implemented server-side rendering for the initial page load) at my company and I can only recommend it.

I’m experienced with React - and I do a lot of paid work with it.

My main issue is this - for the amount of JS we need in this project - we can probably have all of our JS resources downloaded, parsed and executed in the time it would take just to download and parse React itself, let alone react dom and then our app code. It just seems too much for what we need it to do. We wont require half of the features that React offers.

Which then begs the question - why go with React on the server if you dont have it on the front end? Isomorphic is great and all but its just not for every app. I dont think it is right for this app.

Have the site render from the server, all features should work without JS, detect if JS is loaded by running a small script at the top of the page, if js is running replace hard links (a tags etc) where appropriate, with buttons that execute more advanced behaviour instead.

Doing it this way means that we can fully develop the app work entirely without any JS. I personally think this approach is rock solid but just not popular in 2020. I dont think that means the site is dated or is inefficient or a poor user experience.

10 Likes

I personally think this approach is rock solid but just not popular in 2020.

Yep, for all the wrong reasons if you ask me (not always, but very often).

Fully agree with what you said there.

5 Likes

A server rendering data to static HTML without JS works just great, doesn’t it, until you need to push new data from the server to the client without the user’s explicitly telling the browser to “page reload”.

That pushing of data is kind of important, isn’t it, in an interactive web site – i.e. where users are meant to be able to interact with other users in soft real time. So features like, see votes changing, new answers or comments added to a page, new topics added to the list of topics, chat, new notifications to your inbox, etc.

Perhaps these are all v2 features.

I fear you implement render-to-HTML on the server for v1 – and soon after that, when you implement support for pushing data in v2, then suddenly you’re all, “dang, now we have render everything again, but on the client this time – so ‘now you have two problems’ (i.e. client- and server-side code).”

Seems to me that @mattjbrent isn’t saying “no JS at all”, but “should work okay without JS”, and we can enhance things if JS is available, to get the things like data push in.

8 Likes

Perhaps you’re right. The example was, “buttons that execute more advanced behaviour instead”, e.g. a fancy interactive picker for tags, instead of just an input text box.

It seemed to me though that supporting pushed data is an argument for rendering that data on the client – and a lot of the the UI elements on a page are updatable via push, maybe almost all the data on a page, except the CSS and the some navigation element, and maybe user profile stuff – but anything related to messages and topics and votes and notifications, all the main stuff.

@cwellsx yeah you missed my point there. Probably because I was inferring and not explicit. I’m all for JS rich experiences. I really am. I’ve worked on fully interactive scroll based animation sites and all that jazz. I get it I really do.

What I’m saying is we can perform a lot of the functionality we need with less js. Where we need data pushed from the db great. That’s why we’re architecting an API. We can even look at other options around sockets or some kind of polling or whatever it is for more responsive interactive experiences. I have ux ideas that beat the snot out of anything I’ve used in similar apps.

But it can all be done in a surprisingly small footprint.amd only when we need it At my job I just finished before I left architecting and leading the implementation of a fully dynamic design system the js was a fully fledged OO component library that handled full level of DOM interaction. An abstracted event system that interfaces with components and the native browser event system a full API for ease of development AJAX and an animation interface. Worked in all the latest browsers I got to implement it in 4 sites in production before I left and it was around 30kb gzipped. It was the same size as jquery but had soooo much more. The sites it was used on were so much faster and had a richer experience because of it. That’s nothing special it’s just what happens when you don’t just keep adding libraries and frameworks.

It worked with server rendered HTML and it was great. It was very freeing actually not battling with a framework. I think something less robust - a little more tailored to what we need is the way to go for us I really do

6 Likes

Just a dumb user here, but I find those kind of “features” rather annoying. I hate it when a web page changes asynchronously to me having done anything, or I’m in the middle of typing, or whatever. There is really no excuse for a Q&A site to force real time updates on me. I expect to be seeing a static view until I move to another page, or refresh, or deliberately do something. Anything jumping around on the current page is really annoying.

4 Likes

Slightly off-top topic, in the future I hope all voting happens on the forum instead of Discord. The forum is much more SFW. I’m happy for discussions to take place wherever, but the key points should be quoted and presented here, so that Discourse becomes the “source of truth”.

4 Likes