User:Evad37/Scripting Q&A

From Wikipedia, the free encyclopedia

From User talk:Evad37/Archive 7 § Seeking words from the wise (you).... Questions by The Transhumanist.


Which JavaScript books have you studied that you recommend?
I haven't used any books – just websites, youtube videos, and looking at other people's code
Which are your go-to JavaScript-related websites?
MDN JavaScript References W3Schools JavaScript References, stackoverflow (usually from a google search), jQuery API documentation, Regex101 (with the "flavor" on the left set to javascript)
What tools do you use for script development?
Notepad++ is my text editor with JSHint plugin for linting; and Chrome's devtools for debugging.
What does a script/gadget developer for WP need to know about MediaWiki?
Not sure if these are 'need' to know - probably more 'good' to know:
(a) Quite a bit of the hard work is done for you, with lots of info available in mw.config, and lots of function available in ResourceLoader modules
(b) There are lots and lots of preferences and gadgets that change the way a page renders for users – what you see is not the same as everyone else, and you have to account for it if you want other people to be able to use your script. The main ones I've come across are skins, watchlist/recent changes preferences, and table of content preferences.
(c) With just a little bit of care, scripts can be made to work across all wikis.
What is your approach for writing scripts?
There's a few different approaches, and what works best really depends on the type of problem.
  • Currently, my preferred approach is to basically break the problem into a series of high-level steps. And depending on the complexity of the problem, those can be broken into a series of sub-steps. And so on, if needed. It can help to draw a flow-chart. Also, you can figure out what inputs each step needs, and the outputs it should produce. That basically forms a basis for writing the steps as functions. And substeps might be a series of logical steps within a function, or they might be subfunctions, or a higher-level function (to avoid code duplication if similar functions would otherwise have the same or very similar subfunctions).
    This fits in nicely with function-style programming, and if you follow the other functional programming concepts of immutable data (once a variable is set, you never change its value – instead you set a new variable to a changed value) and pure functions (functions only take in inputs, process the data, and return a value, without making any other changes to the state of the program), then your code can be easier to test and debug – because for a given input, each function is guaranteed to produce the same output.
    User:Evad37/TextDiff.js is a script where I took this approach.
  • Sometimes, it useful to work from an object orientated approach, where everything is a certain type ("class") of "object" – a blob of bits of data, with built in methods (functions) for setting/updating, retrieving, or doing something with those bits of data. So for example if you had a class for templates, the bits of data would be the template name, parameters names, and parameter values. This means that when modifying or using the data elsewhere in your code, you don't need to know the implementation for how to update a parameter value, or format it as a string of wikitext – you just use the methods from the object. So you might have some code like var someTemplate = new Template('name', {'para1':'value1', 'para2':'value2'}); and then later someTemplate.setParamValue('para1', 'foo'); to change the value set for 'para1'. And later someTemplate.makeWikitext(); to produce the string {{name|para1=foo|para2=value2}}.
    This separates the implementation from the usage, so that (a) its reusable, and debugging only needs to happen in one spot (b) its obvious that code like var newWikitext = someTemplate.makeWikitext() + currentWikitext; is adding the wikitext representation of the template to the start of the current wikitext (without concern as to how the template object is turned into wikitext).
    You also have something called "inheritance", where a more specific class of object can reuse the setup for a more general type of object, and just add some additional bits of data and methods. A template is a specific type of page, so you might have a more general Page class with methods such as making a wikilink to the page, that work for any type of page including templates.
    So with this sort of approach, you break the problem down breaks down into generating objects from inputs, working out how those objects are going to be manipulated, and then how you construct an output from those objects.
    User:Evad37/rater.js is a script where I took this approach.
  • A third approach is just to work out what steps need to be taken, and write the code sequentially to do just that – just storing data in variables, and without worrying about immutable data, pure functions, or objects and their classes. This is okay for simple scripts, but its actually much harder to do and maintain complicated scripts this way.
How do you go about fixing bugs?
Think about where the bug may be coming from, and use Chrome's devtools to evaluate what's going at that point of the code: https://developers.google.com/web/tools/chrome-devtools/javascript/
Or you can insert console.log() statements to find out what variable values are at certain points in the code, but you have to either be fairly certain of where the bug is coming from or litter them all over the place to try to catch the bug. (But the devtools debugger is more powerful, and easier since it doesn't require source code modifications that are purely for debugging)
What were your hardest learned lessons?
Always test your code before deploying it. It doesn't take much to completely or partially break stuff. The way I work is to have a developental, sandbox version of the script at "scriptname/sandbox.js". Which starts off as a copy of the main script, maybe with a couple of overrides so it only edits pages in my userspace, or so that I see what the script would show an admin. Then I can make incremental changes to the sandbox.js version, without affecting anyone who has installed the main varsion of the script, and run it to see if the changes do what they were intended to do. More recently, I've started doing unit testing for my scripts in a /test.js file, but I'm still new to this sort of testing.
If you were to start all over again, what would you do differently?
I'd try to do as much as possible in a functional style (once you get used to it, it just makes sense).
What other pointers can you provide?
  • You can avoid deeply-nested if-else statements by doing some reverese logic – instead of checking conditions are met:
    function foo (whatever) {
        if ( condition1 ) {
            if ( condition2 ) {
                if ( condition 3 ) {
                    //code if everything is okay
                } else {
                    //code if #3 fails
                }
            } else {
                //code if #2 fails
            }
        } else {
            //code if #1 fails
        }
    }
    
    you check if conditions aren't met:
    function foo (whatever) {
        if ( !condition1 ) {
            //code if #1 fails. The return below stops any further code being processed.
            return;
        }
        if ( !condition2 ) {
            //code if #2 fails
            return;
        }
        if ( !condition3 ) {
            //code if #3 fails
            return;
        }
        //code if everything is okay
    }
    
  • A shorthand for if-else statements is the ternary operator, which is super useful when doing variable assignment:
    var foo;
    if ( condition ) {
        foo = 'isTrue';
    } else {
        foo = 'isFalse';
    }
    
    is equivalent to
    var foo = ( condition ) ? 'isTrue' : 'isFalse';
    
What important questions did I not ask?
  • Similar shortcuts, called short-circuit evaluation, are also possible with the OR (||) and AND (&&) operators
    var x = a || b // evaluates to a if a is truthy, or b if a is falsey - ie IF (a) { x=a; } ELSE { x=b; }
    var y = a && b // evaluates to b if a is truthy, or b if a is falsey - ie IF (a) { y=b; } ELSE { y=a; }
    
  • jQuery isn't just for manipulating HTML (DOM) elements, there are some nifty utility functions – like $.each() and $.map(), which are similar to the native array methods, but work on objects as well.
That's probably just the tip of the iceberg, but its a bit hard answering such general questions. - Evad37 [talk] 09:52, 4 February 2018 (UTC)
On retrospect, the main thing I didn't think to ask is, "What are the goals of script writers?" I look around at the various scripts, and they all seem to pick away at the edges, but of what, I cannot tell.
I don't know if there is any one answer, but in a lot of cases, its ultimately laziness. Computers are completely deterministic machines, and every step they take in executing a script could be undertaken by a human – but might be time-consuming, boring, hard, or beyond an individual's capabilities. So we create scripts/programs to fully or partially automate tasks, allowing them to be completed in a fraction of the time/effort that would otherwise be required. Which probably makes us more efficient in the overall number of tasks we can complete, but in terms of each individual task, we get to be lazy. And then you can get philosophical about what even is programming (e.g. this video [1]). - Evad37 [talk] 01:58, 23 February 2018 (UTC)