There is one part of it that is mildly interesting (on the site itself) which is the RSS reader capability here:
There is one part of it that is mildly interesting (on the site itself) which is the RSS reader capability here:
- Can’t open any of the pages in a new tab.
- Can’t go back.
- Can’t close the page without an “unsaved changes” prompt even though I didn’t interact with it at all.
- Doesn’t maintain state when restarting the browser or navigating through history.
- Doesn’t keep my scroll position when switching between tabs. Very painful if I clicked one accidentally.
- Doesn’t seem to be possible to focus or activate tabs via keyboard.
- Takes 3 seconds to load on my network. This is mostly up to latency, but making 119 requests totalling nearly 3 MB with no design to speak of yet probably doesn’t help.
- Takes a further 7 seconds to start fading in (why does it fade in?) on my device (2012 MacBook Pro 13") on a cold start, 4 seconds if just hitting Enter in the address bar.
- “Processing request” flashes on for a fraction of a second with an animated progress bar. How many progress states are there?
And it doesn’t even do anything in this state except let you flip between tabs. If things that are not this way are obsolete, I will gladly hang back and be obsolete with them.
But hey, the menu animation is very smooth!
> The architecture is state-of-the-art.
You should also probably back this statement up with something. Right now it appears to be a lot of self-horn-tooting.
But hey, sure, let’s spend the same half-minute to talk about the code. I open to a random TypeScript file – thank goodness you’re using TypeScript, because the JavaScript you’ve put under version control for some reason would make any non-vendor code in the language difficult to find in this time – https://github.com/Clay-Ferguson/meta64/blob/d9f3740118e8099....
declare var Dropzone;
Oh okay I guess we’re not using types here let config: Object = {
⋮
var submitButton = document.querySelector("#" + thiz.id("uploadButton"));
This… this isn’t how you reference elements in your “state-of-the-art” architecture, right? if (!submitButton) {
console.log("Unable to get upload button.");
}
submitButton.addEventListener("click", function(e) {
I guess the state of the art means you can’t use your browser’s debugger. Or it’s just for consistency given that you’re circumventing the rest of the browser too. this.on("queuecomplete", function(file) {
meta64.refresh();
});
What? I have no idea what this does (`meta64` isn’t declared, I guess because this file is allergic to modules. it also appears to be a singleton or global, neither of which particularly screams “good design” when named in reference to your app) but it looks like some kind of indiscriminate state update given that nothing is being passed to it. Maybe it’s not that, but no time to find out. We’re running out of seconds here.Wait, back up a moment:
submitButton.addEventListener("click", function(e) {
//e.preventDefault();
dropzone.processQueue();
});
Isn’t a major aspect of most of these fancy SPA frameworks that you don’t have to do this? $("#" + this.id("dropzone-form-id")).dropzone(config);
> This… this isn’t how you reference elements in your “state-of-the-art” architecture, right?oh no it is. Bonus points for kebab-case when the other two we’ve seen so far are camel. I’m nitpicking style because a meaningless literary device involving cars made me irritable. Sorry.
let ret: boolean = false;
for (let file of this.fileList) {
if (file["name"].toLowerCase().endsWith(".zip")) {
return true;
}
}
return ret;
That was a useful variable! I would write this: return this.fileList.some(isZipFile);
and then probably not write this in the end because it’s a filename check but we’re here to talk about architecture or something, not that: const isZipFile = /\.zip$/i!test;
`!` is a macro for bound property access in my state-of-the-art architecture. runButtonEnablement = (dropzoneEvt: any): void => {
if (dropzoneEvt.getAddedFiles().length > 0 ||
dropzoneEvt.getQueuedFiles().length > 0) {
$("#" + this.id("uploadButton")).show();
}
else {
$("#" + this.id("uploadButton")).hide();
}
}
I would think a F1 racer ninja rockstar architecture would be able to bind the visibility of this button to some state. More bonus points for not using `toggle()` and the same select-by-id antipattern. $("#" + this.id("uploadPathDisplay")).html("Path: " + render.formatPath(attachment.uploadNode));
Select-by-id again. I’ve suppressed the urge to gag by this point. `.html()` instead of binding this to some appropriate component? Nothing new. Mysterious global `render` due to declaring things allergy? Par for the course.Let me know if you would like a review of any other files so I can decline and spare my mental health thanks
You need to get off your high horse. Not even Jon Skeet thinks he creates perfect code.
Your project is nowhere near "great example of modern architecture in a web app". You depend on mysterious global variables everywhere, mix jQuery with HTML tags hard coded in strings (with classes and everything) and have no unit or E2E tests. I applaud your overconfidence though. Most people are ashame of their code, even when it's ten times better than this.
Serious tip: invest time in learning React+Redux/MobX or Vue. I promise you it will make your life much better once you realize your shortcomings.
Regarding the generating of the presentation code being done in pure JS/TS rather than a bunch of template files rendered on the server is actually another innovation in disquise. This app is so dynamic that even if it were template-based the templates themselves would be 90% logic, which is why just generating presentation code on the client is ideal. This IS mainly a client-side app, that consumes a server-side JSON API, rather than getting any actual HTML from the server. Yes it's inverted from the way the rest most people are still doing it, but what I'm doing is the future. Learn a bit about microservices and RESTfull stuff and you might begin to see the light, about how a browser can consume an API that sends back JSON DATA rather than rendered HTML. It's the future. I'm doing it right. You just don't get it yet. And if you're irked by my confidence, frankly that makes me happy.
> Learn a bit about microservices and RESTfull stuff and you might begin to see the light, about how a browser can consume an API that sends back JSON DATA rather than rendered HTML. It's the future.
RESTful APIs are great but you are 10 years late to the party.
Using RESTful APIs is exactly the same thing web services were back 15 years ago with XML.
Also, singletons are simply bad practice so that's just another sign that your code is far from "state of the art".
> Yes it's inverted from the way the rest most people are still doing it, but what I'm doing is the future.
Of course you consume JSON through a REST API and let the client handle HTML generation when building an SPA. "The future" you're speaking of has been industry standard for 10 years. Nothing radical or innovative about it. How do you think React, Vue or Angular work?
I think it was about line 8 in this file:
https://github.com/Clay-Ferguson/meta64/blob/master/src/main...
That's funny that you don't like singletons. Not sure how you got brainwashed about them, but they are good and VERY widely used today by all major codebases. Singleton is literally the "default scope" for all Spring Beans, so you are so completely clueless about that.
There are a few use cases for singletons but using them as globals to avoid passing dependencies around is simply bad practice. Your code is a tightly coupled and untestable mess at its current state.
It's funny that you arrogantly just dismiss every single person in this thread as idiots. You need to take a step back and consider that you might actually be wrong.
Having a naming convention is no reason not to do proper dependency management. This global approach just obscures things and makes it untestable.
The code will easily convert to modules if I ever decide to. For now I'm just keeping it simple. (i.e. no circular-reference risk, etc) It's easy to throw rocks at a design, but if you spent a day working in meta64 you'd realize how intuitive it is. Obscure is never the word you'd use.
I'm not sure why you would assume no one could find faults in the code when they even have comments right there about said faults.
So the mere fact that you said "giant global variable" is proof beyond any doubt that you don't know jack about namespaces, and all you were barely able to do was notice the lack of module loaders at the top of my files.
You may not even know this, but packaging an app into a single downloadable JS file (modules not even necessary) is actually the modern approach. It lends itself to better compression+minification. Once installed in a browser cache it's usable just like an 'installed' piece of software. But I thank you for the phrase "giant global variable". I'll be laughing at that for years to come.
Which is part of why I haven't used JQuery in ages. The last time I saw someone mention JQuery as a best practice example was arguably a decade ago, if not longer than that. If you are doing things by a book, it's not a book that was written any time recently.
At this point, any library I see that uses a global variable and doesn't support proper module loading is a code smell and a sign that the library is probably not well maintained.
«You may not even know this, but packaging an app into a single downloadable JS file (modules not even necessary) is actually the modern approach. It lends itself to better compression+minification.»
Actually, this has changed a lot in recent years, and your ignorance of how module systems work also shows up here. First of all, you can have compression+minification and modules. Even in the bad old RequireJS days when AMD loaders were state of the art there were good AMD bundlers. With modern EcmaScript 2015 modules (ES2015) there are a lot of great bundler options, Webpack being a particular darling right now, but there's also others.
This sort of bundling, compression, and minification is now seen as the last step in the chain, the job of the application/website developer and no longer something that every JS library under the sun needs to do bespoke. A big reason for this is developer experience (it's easier to debug when everything is a large collection of modules), but it also makes for a better user experience (the final application knows more precisely what modules it needs to operate [tree shaking], and in what order [optimizing bundles for specific use cases/first impressions]).
Overall, frontend web development is shifting to share modules with more backend operations and the node ecosystem's npm (and relatives that piggyback on it like jspm and yarn) has become the package/module management ecosystem of choice. This is great for developer experience, whether or not you are doing your backend development in Node, because you have an easier access to a larger ecosystem of libraries, an increasing number of which are "universal"/"isomorphic" running just as well in the browser as on a server running Node (or app running in Electron or an app running in Cordova).
Furthermore, for some of these platforms bundling+compression+minification isn't even necessary, such as an app or server loaded directly from the filesystem instead of shipped to a browser via HTTP. Even that is changing best practices because HTTP/2 mitigates a lot of the reasons that you even need to bundle in the first place (HTTP/1.x often can only handle a single file per connection while HTTP/2 was designed from the start to bulk download a collection of files in a single connection; the connection overhead being the biggest reason to bundle in HTTP/1.x).
There's a lot of great stuff to learn about the current state of the art with respect to modules and ES2015 and modern frontend development ecosystem if you thought to give it a try instead of sticking to old practices now long considered harmful (not just in JS, even, but in about any language: giant global stateful singletons like JQuery are a miserable antipattern any time they show up in any language in the history of programming).
I'm using Google's minification:
There's a lot of scattered Medium articles and "Awesome Lists" I've seen from time to time, but I don't seem to have any organized bookmarks on the matter.
I did not say bundling+compression+minification is "obsolete", I said things had shifted in how front-end development uses those things as tools in their toolbelt. It's a very different world these days in JS and lot of "must" best practices became "when needed" best practices. All I was trying to point out was that you don't start with bundling+minification+compression, you pull in those tools as and if you need them.
As for JQuery, I'm not the only engineer that sees it as a problem. It's the second sentence of the Wikipedia article summary on the Singleton pattern, for instance:
« There are some who are critical of the singleton pattern and consider it to be an anti-pattern in that it is frequently used in scenarios where it is not beneficial, introduces unnecessary restrictions in situations where a sole instance of a class is not actually required, and introduces global state into an application. »
-- https://en.wikipedia.org/wiki/Singleton_pattern
Google for "Singleton anti pattern" for many pages of articles on the subject, if you care.
2) JQuery: Any JS library is better when it adds only a single variable to global scope. JQuery uses $. My app uses 'm64'. Anyway what is the better DOM-manipulation API I should be using? Do tell. It has to be an actual competitor to JQuery (i.e. lightweight pure JS library with same DOM capabilities.)
3) Singletons: I use Spring Beans on the server side to be sure I have singletons 'correct', and I use TypeScript namespaces on the browser side. The most common way people screw up singletons is related to the instantiation issues, and circular-references. By using Spring @Component and TypeScript namespaces, I avoid the exact issues you are concerned about. Based on my architecture it's literally IMPOSSIBLE to encounter those issues even if I tried.
> Any JS library is better when it adds only a single variable to global scope.
No, this is how you use jQuery in 2017:
import $ from "jquery";
Simple as that. Just stop using global variables.What are your thoughts on for example React, Vue or Angular? Any reason you didn't go that route instead?
I have been waiting for React to emerge as a clear winner before using it. I only use libraries, APIs, languages, databases, etc. that I've concluded will still be around 10yrs into the future. I don't like Angular, and don't know Vue. If React doesn't replicate some future plans Google has for Polymer ecosystem i might try it.
> Based on your definition of "giant global variable" the $ in JQuery is also precisely that.
jQuery’s `$` and `jQuery` are giant global variables when you include jQuery as a <script> or by concatenation. When you load it as a module, it adds no globals, which is rather nice. Look at https://www.npmjs.com/package/jquery’s “Babel” section, which is also how you use it with TypeScript.
You also seem to be under the impression that polluting the global namespace is the only bad thing about globals. It’s one factor, but it’s also just generally an indicator of bad design. Organizing global mutable state into singletons and namespaces doesn’t help with this. You’re also crowing about TypeScript but throwing away many of its benefits by not using modules or typings for the libraries you depend on.
> You may not even know this, but packaging an app into a single downloadable JS file (modules not even necessary) is actually the modern approach. It lends itself to better compression+minification.
(ES6) modules actually quite necessary if you want your minifier/bundler to be able to remove unused code reliably. Closure Compiler can only do so much.
I think if an SPA can achieve all of these http://rauchg.com/2014/7-principles-of-rich-web-applications...
with minimal additional payload, then it's good.
Also, edge swipe from right or left on iPhone completely doesn't work.
Compare your site to Wikipedia for example. Which feels smoother, especially on a mobile page?
A javascript application is like a computer program running in your browser. Whether you realize it or not, every page reload is a 'restart' of that app. Do you think an app needs to RESTART just because someone changes screens or soemthing? It's insane right? Without an SPA that is that is genuinely whats really happening.
I agree you can get into a slightly weird situation if you hit the back button after composing a new comment but your site would suffer the same.
BTW even hacker news has a 'back functionality' that sucks. You have to go back then refresh. Meta64 is already vastly superior to other online social media experiences including wikipedia and including better than this HN site.
Also, serious question: if I navigate your rss outline, how do I go back and chose a different section to browse? Right now you are stuck in the section you chose and the back button closes the app.
Perhaps, where this goes is that Single Page Apps and web browsers aren't a good fit together?
It exists in quite a few dekstop apps (explorer and control panel on windows to name a couple). Android also has an ubiquitous back button.