Sometimes I wonder if I should only write a test when something unexpected happens (e.g. user has a bug report) instead of wasting time writing tests on the front end for core features and obvious edge cases.
I mostly work on scientific software, btw.
As this complex product evolved at rapid pace - one of the key differentiating factors of this product and others were time to market and product reliability - benefit reaped was many folds from test suite. Many LOB directors realised that efficiency of our platform had to do with test suites. If I've to run a successful company - I would heavily rely on such a test suite.
Having said that - its hard to write detailed TDD in early stage startups. I didn't write TDD at my last startup work but I had a swiss-army-script to test. In this case, reliability of software is on a developer who developed it. But once a component is proven and it goes as core software of your startup - it should be baked with test suite.
My program spawns and runs in the main thread. It calls the main function. If it want it to run forever, I'll stick a while(1) loop in that function.
Now I want to have a particular thing go off and do some work in parallel with that main loop, and when it's done, I want the next iteration of the main loop to pick up on that fact.
Not once have I encountered a sane API for that use-case as easily expressed as those sentences of prose above.
• Async/await in C# (I have a pretty good mental model and use it quite often but honestly have never truly understood how it compares to c/C++ threads)
• async concepts in Java Android. Runnable, future, asynctask, threads arrghhhh. My head hurts.
• multitable SQL joins (inner vs outer). Someone gave a pretty good explanation in the comments.
• why do I need to use nginx for my web server? And what is a reverse proxy anyways?
• how come I can use any smpt client or something like mailchimp or sendgrid to send an email and specify any email in the "from" field. Can't I pose as someone I'm not?
TLS is one aspect that comes to mind. A certificate and key is not enough. You must specify the correct parameters such as the cipher suites, DH parameters, HSTS, and more if you want a secure connection.
You mentioned a reverse proxy. This is the other aspect that comes to mind. Servers are bound to ports, like 80 and 443. How do you serve multiple applications on the same port on the same server? A proxy. More specifically a reverse proxy. It sits between the client and the services as a middleman to handle and direct requests. Multiple services can run on different ports but the reverse proxy allows for a single point of entry, such as HTTP requests on port 80. The proxy will inspect the request and based on certain values, say a hostname, it will be directed to the correct service. Otherwise you would have to tell your clients to specify the port the service is running on, ex: http://mydomain.com:8080
Functional programming in general clicks with me, however.
This is especially true if your functions if you have a bunch of functions that do this and they aren't really useful for anything else.
But what if I don't want to mutate the source data? I always wind up writing classes that are largely immutable, and it seems wrong from an OOP perspective. Is there a correct way to marry immutable data with OOP?
Values that are supposed to change at the same time (or care about each other, or would otherwise need to be in sync somehow) would normally have to be passed around together to maintain that property, but this can lead to errors because it's the sort of thing people forget. If you put them into a structure together then hide the ability to actually use them behind functions that maintain the property you want, you prevent that sort of error.
So you attach functions that operate on a data structure to the data structure solely for organizational purposes?
Seems almost identical to defining a record and module of functions that operate on said record. Except that in OO, by attaching the functions you create new copies of each function with a bound reference to the instance of data structure. Are there other advantages?
OO is mostly that plus the ability to forbid people from using the record without using the functions.
> by attaching the functions you create new copies of each function with a bound reference to the instance of data structure.
Yes, but the compiler won't actually copy the function, it'll implement it as something closer to the record plus modules approach (for example a record plus a pointer to the module). This might not be true if you're trying to use OO in a functional language.
One more question (restated from below):
Coming from FP where immutability is sacrosanct, I often wind up writing classes that are largely immutable, which doesn't seem like correct OOP. Is there a proper way to marry immutable data structures with OO?
It didn't click for me until the third tutorial, and there are lots of resources out there
Email is a real 'devil in the details' thing. Anyone can follow a web how-to (when they're not stale) and set up a basic server, but it's crazy complex to understand properly. It's also weirdly both old-as-rocks and at the same time constantly changing (eg: deliverability scores, major vendors changing how they accept things, etc). Aliasing and mail flow and MUAs vs MTAs and mailbox formats and multiple arcane config files and blacklisting and DKIM and MX records (and TXT records) and etc etc etc... and if you're really crazy, GPG-signing. I've always got enough to just scrape by, but never actually comfortably grokked it all at any point. So many disparate spinning plates...
From the basic options to set up a server, code deployment and maintenance using Github, nodejs and similar JS-everything, XML/JSON, how much of what should CSS take care of, DB access (and which one), structure of a modern webpage, CDNs, structure scaling, and requirements for browsers and platforms..
I used to use JS to change some text in html pages ftp'd to a server running a basic apache. Looking at it now is a big slap in the face. Nodeschool helps a bit, but it's all pretty blurred still. The more I dig, the deeper it gets without a sense of direction.
I have however embraced the magic of "no idea how things work under the hood" and now build things for our intranet in seaside.
I am however a bitter old fart that envy people that can throw beautiful web pages together in 25 minutes. Most of my work these days are management and scheme coding,so that is probably.the way it is going to stay.
(Variable assignment, as in foo = bar, always just assigns a reference, it doesn't mutate objects or copy values.)
I understand the concepts, and pointers make perfect sense to me when I'm programming in assembly, but whenever I look at them in C++ it's like & and * mean the opposite things when used in variable declarations from what they mean when used as an operator and yet another thing when used to declare arguments. But I've never seen anyone else acknowledge that they're weird so I feel like there's some sort of logical connection I'm missing.
For example, where in your hierarchy do you stick the AbstractSerializable class? If it's an interface like ISerializable you just implement it at whatever level you're at.
With multiple inheritance you don't need interfaces because you can just inherit from multiple base classes.
1. Interfaces can be used by any class no matter where they live in their class hierarchy. You can only extend a single (abstract) class in Java because the language designers saw the special rules and overrides other OOP languages like C++ used to avoid the 'diamond problem' and decided against it entirely. Note that in pre-Java 8 implementing multiple interfaces cannot lead to the diamond problem because if more than one interface exposes the same method signature then the compiler doesn't care because it doesnt have actual functionality that could be conflicting. So, because you are limited to only extending one superclass it is easier to bundle functionality in multiple smaller interfaces that can be implemented no matter where your implementing class lies in the class hierarchy.
2. Interfaces provide only a contract of functionality which in practice means they are easier to reason about and use. If you are implementing an interface you dont have to worry about calling a super constructor or any other garbage. Just implement the method signature. Of course you could ask "What if you only had abstract methods with no implementation in an abstract class", in which case I would refer you to point 1. A class that already has some existing superclass could not extend that abstract class.
I hope that clears some stuff up. Just in case you read that and thought the Java language designers were stupid for adding default methods in Java8 they had really good reasons to (mostly to support backwards compatibility with a large change called Lambdas). But having some functionality in interfaces could be argued for as well. In practice there are companion classes in the Java API that are just there to provide some base functionality that they could not do because of the previous limitations of interfaces. Also, the Java8 rules for fixing 'the diamond problem' with conflicting default methods in interfaces is pretty straightforward and rarely encountered.
Really the main reason it's "... in .NET" is because there are a few sections in the book that explain how to achieve DI in some common .NET frameworks, which you are free to ignore. The first half of the book is a fantastic explanation of both the problem that DI solves, and how DI solves it.
I felt like I didn't really understand OOP and the real point of object-oriented design patterns until I read it.
What makes some code better than other code? The understanding of this is probably a lifelong pursuit.
That is implemented using call/cc, and even though it is mostly a convenience function, it shows how call/cc can be used.
It should be noted though, that call/cc is extremely expensive and prone to memory leaks. If you are using racket , scheme48 or guile you should use their delimited continuations instead.
With things we do outside of an IDE.
Language specific functions and behaviour.
int a = 42; // puts the number 42 somewhere in memory
int* p = &a; // gives you the address where that 42 is stored
A function with a signature like
int f(int n);
takes an int as an argument. When you pass it the a above, it is copied in the stack before the function is called. If you change n inside the function, that only affects the value of n inside the function. But let's say you wanted to change what was passed in to it. In that case you would change f to
int f(int* p);
Now when you pass the a declared above (using &a) you actually have a pointer to a in f i.e. the address where a is stored. If you do
*p = 51;
inside f, you changed the value of a and that change is visible even after f returns.
Hope that helps.
Pointers start to make more sense when you take the comment above about pass by value vs. pass by reference into consideration.
There's a great gif about this where a cup is used as the argument to a fillCup() function.
https://blog.penjee.com/wp-content/uploads/2015/02/pass-by-r...
In pass by value, a second cup is created just for that function and then filled with liquid. The original cup is left untouched. With pass by reference, the original cup is being filled, not a duplicate of it. How does the function know to fill the original instead of creating a duplicate for its own scope? A pointer.
When calling a function with arguments a few things are happening behind the scenes. Memory allocation for these arguments is one of those things. This is where the stack and heap come into play. Memory allocated for the function call is considered the stack while memory for the entire program (think global variables) is the heap. Things get even more interesting when you look into stack frames and step through the execution of a program with a debugger like gdb or lldb. You'll start to understand how recursion works.
Pointers are also used in certain data structures like a linked list. They allow you to easily keep a chain of values that contain data and a pointer which points to the next data, otherwise known as a linked list, or binary tree, or many other names depending on the structure.
I'm replying on my phone so I apologize in advanced for the formatting. Hope this helps.